第一遍学习这个注入方法时候,只知道NtCreateThreadEx是未公开的nt函数,当时要定义一个函数指针出来,好像在看雪上找到的这个函数的声明,,太久远了,记不清了。
在Windows2000的源码和Reactos中都无法找到NtCreateThreadEx的函数声明和实现,所以试了下用IDA看看ntdll的导出表,哇,好开心找到了,但是,,好像什么都没有,只有一个系统调用号,没有任何参数的信息。
我最后在https://securityxploded.com/ntcreatethreadex.php找到了有关这个函数的声明,它是未文档化的。。难顶
废话不多说,对于注入来说,NtCreateThreadEx也是经常用的一种方法,只是这个函数没有被微软文档化,这点比较d疼。接下来说说实现思路,基本和CreateRemoteThread差不多:
- 从控制台得到想要实施注入的目标进程名字
- 得到当前进程所在的目录,并保存
- 得到当前进程的位数
- 根据进程名字得到当前进程的Id
- 根据进程Id得到当前进程的完整路径
- 通过进程完整路径对PE文件解析得到目标进程位数
- 目标与当前进程的位数进行匹配,决定加载哪一个dll
- 根据当前进程目录,得到dll完整路径
- 通过GetModuleHandle得ntdll和kernel32模块得句柄
- 通过GetProcAddress分别从ntdll和kernel32中得到NtCreateThreadEx和LoadLibraryA
- 通过目标进程Id,打开目标进程,获得进程句柄
- 在目标进程中申请内存
- 在申请好的内存中写入Dll完整路径
- 利用NtCreateThreadEx启动远程线程执行加载Dll,完成注入
以下是代码框架:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | //.h #pragma once #include<Windows.h> #include<iostream> #include<tchar.h> using namespace std; //https://securityxploded.com/ntcreatethreadex.php //Here is the prototype of NtCreateThreadEx function [undocumented] typedef NTSTATUS(WINAPI* LPFN_NTCREATETHREADEX)( OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN LPVOID ObjectAttributes, IN HANDLE ProcessHandle, IN LPTHREAD_START_ROUTINE ThreadProcedure, IN LPVOID ParameterData, IN BOOL CreateSuspended, IN SIZE_T StackZeroBits, IN SIZE_T SizeOfStackCommit, IN SIZE_T SizeOfStackReserve, OUT LPVOID BytesBuffer); typedef HMODULE(WINAPI * LPFN_LOADLIBRARYW)(LPCWSTR lpLibFileName); typedef HMODULE(WINAPI * LPFN_LOADLIBRARYA)(LPCSTR lpLibFileName); //.cpp #include"NtCreateThreadEx.h" #include"Helper.h" #ifdef UNICODE LPFN_LOADLIBRARYW __LoadLibrary = NULL; #else LPFN_LOADLIBRARYA __LoadLibrary = NULL; #endif LPFN_NTCREATETHREADEX __NtCreateThreadEx = NULL; int _tmain(int argc, TCHAR* argv[], TCHAR *envp[]) { //控制台识别中文 setlocale(LC_ALL, "Chinese-simplified"); TCHAR ProcessImageName[MAX_PATH] = { 0 };//保存进程名字 TCHAR CurrentFullPath[MAX_PATH] = { 0 }; //当前进程的完整路径 TCHAR TargetProcessFullPath[MAX_PATH] = { 0 };//目标进程的完整路径 ULONG_PTR TargetProcessPathLength = MAX_PATH; ULONG ProcessId = 0;//目标进程Id HANDLE ProcessHandle = INVALID_HANDLE_VALUE;//进程句柄 LPVOID VirtualAddress = NULL; SIZE_T ReturnLength = 0; BOOL IsOk = FALSE; //注入的启动程序和目标程序的位数 BOOL SourceIsWow64 = FALSE; BOOL TargetIsWow64 = FALSE; _tprintf(_T("输入一个进程ImageName\r\n")); TCHAR RcceiveChar = _gettchar();//接受字符串 int i = 0;//用来偏移ProcessName字符数组 while (RcceiveChar != '\n') { ProcessImageName[i++] = RcceiveChar; RcceiveChar = _gettchar(); } //ProcessImageName = 0x00000056f16ff2b0 "Taskmgr.exe" GetCurrentDirectory(MAX_PATH, CurrentFullPath);//保存当前进程的完整路径 IsWow64Process(GetCurrentProcess(), &SourceIsWow64);//得到当前进程位数 ProcessId = KtGetProcessIdentify(ProcessImageName);//通过进程名得到进程Id if (ProcessId == 0) { return 0; } IsOk = KtGetProcessFullPath(TargetProcessFullPath, &TargetProcessPathLength, ProcessId, FALSE); if (IsOk == FALSE) { return 0; } //判断目标进程位数 KtIsWow64Process(TargetProcessFullPath, &TargetIsWow64); if (SourceIsWow64 == TRUE && TargetIsWow64 == TRUE) { _tcscat_s(CurrentFullPath, _T("\\Dll.dll")); } else if (SourceIsWow64 == FALSE && TargetIsWow64 == FALSE) { _tcscat_s(CurrentFullPath, _T("\\Dll.dll")); } //CurrentFullPath = 0x00000056f16ff3e0 "Z:\\Ring3层代码\\[2]Ring3注入\\NtCreateThreadEx\\NtCreateThreadEx\\Dll.dll" HMODULE NtdllModuleBase = NULL; HMODULE Kernel32ModuleBase = NULL; NtdllModuleBase = GetModuleHandle(_T("NTDLL.DLL")); Kernel32ModuleBase = GetModuleHandle(_T("KERNEL32.DLL")); if (NtdllModuleBase == NULL || Kernel32ModuleBase == NULL) { KtCloseHandle(ProcessHandle); return 0; } //当前exe模块中没有该函数导入 __NtCreateThreadEx = (LPFN_NTCREATETHREADEX)GetProcAddress(NtdllModuleBase, "NtCreateThreadEx"); //__NtCreateThreadEx = ntdll.dll!0x00007ffb6580c0e0 (加载符号以获取其他信息) if (__NtCreateThreadEx == NULL) { KtCloseHandle(ProcessHandle); return 0; } #ifdef UNICODE __LoadLibrary = (LPFN_LOADLIBRARYW)GetProcAddress(Kernel32ModuleBase, "LoadLibraryW"); #else __LoadLibrary = (LPFN_LOADLIBRARYA)GetProcAddress(Kernel32ModuleBase, "LoadLibraryA"); #endif //__LoadLibrary = kernel32.dll!0x00007ffb63c7e710 (加载符号以获取其他信息) if (__LoadLibrary == NULL) { KtCloseHandle(ProcessHandle); return 0; } ProcessHandle = KtOpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId); ULONG BufferLength = 0; //在目标进程空间中申请内存 BufferLength = (_tcslen(CurrentFullPath) + 1) * sizeof(TCHAR); //目标进程空间中申请内存 VirtualAddress = VirtualAllocEx(ProcessHandle, NULL, BufferLength, MEM_COMMIT, PAGE_READWRITE); //VirtualAddress = 0x0000021819010000 if (VirtualAddress == NULL) { KtCloseHandle(ProcessHandle); return 0; } //目标进程空间中写入数据 if (KtProcessMemoryWriteSafe(ProcessHandle, VirtualAddress, CurrentFullPath, BufferLength, &ReturnLength) == FALSE) { KtCloseHandle(ProcessHandle); return 0; } //再目标进程中启动一个线程 HANDLE ThreadHandle = INVALID_HANDLE_VALUE; IsOk = __NtCreateThreadEx(&ThreadHandle, THREAD_ALL_ACCESS, NULL, ProcessHandle, (LPTHREAD_START_ROUTINE)__LoadLibrary, VirtualAddress, FALSE, NULL, NULL, NULL, NULL); if (IsOk < 0) { VirtualFreeEx(ProcessHandle, VirtualAddress, BufferLength, MEM_RELEASE); KtCloseHandle(ProcessHandle); return 0; } else { WaitForSingleObject(ThreadHandle, INFINITE); VirtualFreeEx(ProcessHandle, VirtualAddress, BufferLength, MEM_RELEASE); KtCloseHandle(ProcessHandle); } return 0; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | //.dllmain // dllmain.cpp : 定义 DLL 应用程序的入口点。 #include "stdafx.h" #include <tchar.h> BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { MessageBox(NULL, _T("NtCreateThreadEx"), _T("NtCreateThreadEx"), NULL); } case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } |
Win7(32)注入Explorer和Win10注入Taskmgr.exe(64)两个都测试通过,32和64都没问题
今日份头秃:为什么我的Win7(32)调用系统函数IsWow64Process返回的当前程序位数是64位???我醉了。。。。
今日份古诗分享:
“蓬头稚子学垂纶,侧坐莓苔草映身。”
这小孩真挺可爱的,蓬头稚子,哈哈哈哈。。