LoadPE 代码实现部分(ASM汇编版本)>>04
目录
整体调用逻辑
源码实现部分
整体调用逻辑
start (程序入口) ↓ INVOKE LoadPE ↓ 1. 获取自身 ImageBase ↓ 2. 打开 PlantsVsZombies.exe → CreateFile → CreateFileMapping → MapViewOfFile ↓ 3. 解析 PE 结构 ├── DOS Header ├── NT Header(获取区段数量、入口点、SizeOfHeaders 等) └── Section Table 位置 ↓ 4. VirtualProtect(把自己内存改成可写可执行) ↓ 5. 拷贝 PE Headers 到自身内存 ↓ 6. 循环拷贝所有 Section(.text、.data、.rsrc 等) ↓ 7. 手动修复 Import Table(IAT) ├── 遍历每个 DLL ├── LoadLibrary 加载 DLL └── GetProcAddress + 填充 IAT ↓ 8. 清理文件映射和句柄 ↓ 9. JMP @dwEP ← 跳转到 PlantsVsZombies.exe 的原始入口点源码实现部分
.386 .model flat, c option casemap:none include windows.inc include msvcrt.inc include kernel32.inc include user32.inc includelib msvcrt.lib includelib kernel32.lib includelib user32.lib .const IMAGE_SIZE EQU 394000H ; 自身预留内存大小(可后续优化为动态) .data g_szFile db "PlantsVsZombies.exe", 0 ; 要加载的目标程序 .code db 90h ; NOP 占位 ORG IMAGE_SIZE ; 代码放在高地址,避免覆盖自身 ;============================================================ ; 主加载函数 ;============================================================ LoadPE PROC ;===================== 局部变量 ===================== LOCAL @hFILE:HANDLE LOCAL @hFileMap:HANDLE LOCAL @szPeBuffer:LPVOID ; 文件映射指针 LOCAL @pDosHeader:PTR IMAGE_DOS_HEADER LOCAL @pNtHeader:PTR IMAGE_NT_HEADERS LOCAL @pSectionHeader:PTR IMAGE_SECTION_HEADER LOCAL @dwNumberSec:DWORD LOCAL @dwSizeOfHeader:DWORD LOCAL @dwEP:DWORD ; 目标 OEP (Original Entry Point) LOCAL @pImageImpHeader:PTR IMAGE_IMPORT_DESCRIPTOR LOCAL @ZeroHeadImp: IMAGE_IMPORT_DESCRIPTOR LOCAL @dwImageBase:DWORD ; 自身 ImageBase LOCAL @dwMod:HANDLE ; DLL 句柄 LOCAL @dwOld:DWORD ; 旧内存保护属性 ; 1. 获取自身模块基址 INVOKE GetModuleHandle, NULL MOV @dwImageBase, EAX ; 2. 打开并映射目标 PE 文件到内存 INVOKE CreateFile, offset g_szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL MOV @hFILE, EAX INVOKE CreateFileMapping, @hFILE, NULL, PAGE_READONLY, 0, 0, NULL MOV @hFileMap, EAX INVOKE MapViewOfFile, @hFileMap, FILE_MAP_READ, 0, 0, 0 MOV @szPeBuffer, EAX ; 内存中的 PE 文件镜像 ; 3. 解析 PE Header MOV @pDosHeader, EAX ASSUME ESI :PTR IMAGE_DOS_HEADER MOV ESI, EAX ADD EAX, [ESI].e_lfanew ; 定位 NT Header MOV @pNtHeader, EAX ASSUME ESI :PTR IMAGE_NT_HEADERS MOV ESI, @pNtHeader MOV EAX, [ESI].OptionalHeader.SizeOfHeaders MOV @dwSizeOfHeader, EAX MOVZX EAX, [ESI].FileHeader.NumberOfSections MOV @dwNumberSec, EAX ; 计算目标入口点 OEP MOV EAX, [ESI].OptionalHeader.AddressOfEntryPoint ADD EAX, @dwImageBase MOV @dwEP, EAX ; 定位 Section Table MOVZX EAX, [ESI].FileHeader.SizeOfOptionalHeader LEA EBX, [ESI].OptionalHeader ADD EAX, EBX MOV @pSectionHeader, EAX ; 4. 修改自身内存保护权限(关键步骤) INVOKE VirtualProtect, @dwImageBase, IMAGE_SIZE, PAGE_EXECUTE_READWRITE, ADDR @dwOld ; 5. 拷贝 PE Headers INVOKE crt_memcpy, @dwImageBase, @szPeBuffer, @dwSizeOfHeader ; 6. 拷贝所有 Sections MOV ESI, @pSectionHeader ASSUME ESI :PTR IMAGE_SECTION_HEADER XOR ECX, ECX .WHILE ECX < @dwNumberSec MOV EDI, @dwImageBase ADD EDI, [ESI].VirtualAddress ; 目标地址 MOV EDX, @szPeBuffer ADD EDX, [ESI].PointerToRawData ; 源地址 PUSH ECX PUSH EDX INVOKE crt_memcpy, EDI, EDX, [ESI].SizeOfRawData POP EDX POP ECX INC ECX ADD ESI, SIZEOF IMAGE_SECTION_HEADER .ENDW ; 7. 修复 Import Table(IAT) MOV ESI, @pNtHeader MOV EAX, [ESI].OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT * 8].VirtualAddress ADD EAX, @dwImageBase MOV @pImageImpHeader, EAX MOV ESI, @pImageImpHeader ASSUME ESI:PTR IMAGE_IMPORT_DESCRIPTOR .WHILE TRUE INVOKE crt_memcmp, ESI, ADDR @ZeroHeadImp, SIZEOF IMAGE_IMPORT_DESCRIPTOR .IF EAX == 0 .BREAK .ENDIF .IF [ESI].Name1 == NULL || [ESI].FirstThunk == NULL || [ESI].OriginalFirstThunk == NULL .BREAK .ENDIF ; LoadLibrary 加载 DLL MOV EAX, [ESI].Name1 ADD EAX, @dwImageBase PUSH ECX PUSH EDX INVOKE LoadLibrary, EAX POP EDX POP ECX MOV @dwMod, EAX ; 修复该 DLL 的 IAT MOV EBX, [ESI].FirstThunk ADD EBX, @dwImageBase MOV EDI, [ESI].OriginalFirstThunk ADD EDI, @dwImageBase .while DWORD PTR[EDI] != 0 .IF dword PTR[EDI] & 80000000h MOV EDX, DWORD PTR[EDI] AND EDX, 0FFFFH .ELSE MOV EDX, DWORD PTR[EDI] ADD EDX, @dwImageBase ADD EDX, 2 .endif PUSH ECX PUSH EDX INVOKE GetProcAddress, @dwMod, EDX POP EDX POP ECX MOV DWORD PTR[EBX], EAX ADD EBX, 4 ADD EDI, 4 .endw ADD ESI, SIZEOF IMAGE_IMPORT_DESCRIPTOR .ENDW ; 8. 清理资源 INVOKE UnmapViewOfFile, @szPeBuffer INVOKE CloseHandle, @hFileMap INVOKE CloseHandle, @hFILE ; 9. 跳转执行目标程序 JMP @dwEP ret LoadPE ENDP ;============================================================ start: INVOKE LoadPE invoke ExitProcess, 0 ret end start