外挂和木马常用技术:傀儡进程代码注入-软件安全逆向社区论坛-技术社区-学技术网

外挂和木马常用技术:傀儡进程代码注入

介绍

傀儡进程,原名Process Hollowing(进程替换),有的也叫RunPE技术。指的是:将目标进程的映射文件替换为指定的映射文件,替换后的进程称之为傀儡进程。在早期的木马程序中使用较广,现在很多外挂程序仍然使用此技术实现隐藏自身。实现傀儡进程必须要选择合适的时机,要在目标进程刚加载进内存后还未开始运行之前替换。

显著特点外挂运行后,发现是执行在某些系统程序进程中的,比如notepad.exe

图片[1]-外挂和木马常用技术:傀儡进程代码注入-软件安全逆向社区论坛-技术社区-学技术网

技术实现:

  • 样本创建一个合法进程(如 Notepad.exe)处于挂起状态;

  • 解除该进程的原始内存代码段;

  • 将自身(A.exe)或者某其他(B.exe)代码写入 Notepad 的内存中;

  • 恢复执行 Notepad,此时实际运行的是 A.exe 的逻辑。

代码实现

代码解析

这段代码的核心原理是 “进程替换”(Process Hollowing),也叫 “RunPE技术”,用于将一个合法的进程(比如 Notepad.exe)作为壳进程挂起启动,然后用你自己的程序(A.exe)替换其内存中的内容,再恢复运行,实现注入和伪装执行。


代码执行流程讲解

1. 创建挂起的合法进程(notepad.exe)

CreateProcessA("C:\\Windows\\SysWOW64\\notepad.exe", ..., CREATE_SUSPENDED, ...)
  • 启动目标(壳)进程,但 不立即运行,而是挂起线程。

  • 这样可以安全地修改其内存内容。

2. 读取你要注入的程序(A.exe)到内存

HANDLE hFile = CreateFileA(realExePath, ...);
ReadFile(hFile, buffer, fileSize, &bytesRead, NULL);
  • 读取整个 A.exe 的二进制内容到内存。

  • 为后面写入目标进程做准备。

3. 解析 A.exe 的 PE 结构

PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)buffer;
PIMAGE_NT_HEADERS32 nt = (PIMAGE_NT_HEADERS32)(buffer + dos->e_lfanew);
  • 定位 NT 头(即 IMAGE_NT_HEADERS32)以获取 ImageBaseSizeOfImage、节信息等。

4. 获取目标进程的 PEB 中 ImageBase

GetThreadContext(pi.hThread, &ctx);  // 获取线程上下文
DWORD pebAddress = ctx.Ebx;          // EBX 指向 PEB 地址(32位进程中)
ReadProcessMemory(pi.hProcess, (LPCVOID)(pebAddress + 8), &imageBase, sizeof(DWORD), NULL);
  • 找到 Notepad.exe 当前加载的 ImageBase 地址。

5. 解除原来 Notepad.exe 映像在目标进程中的映射

ZwUnmapViewOfSection(pi.hProcess, (PVOID)imageBase);
  • 使用 ZwUnmapViewOfSection 清除原始映像,释放其地址空间,避免冲突。

6. 在原 ImageBase 地址分配新的空间

VirtualAllocEx(pi.hProcess, (LPVOID)nt->OptionalHeader.ImageBase, ...)
  • 尝试在相同地址为 A.exe 分配足够大的空间。

7. 写入 A.exe 的 PE Header 和每一个节(Section)

WriteProcessMemory(pi.hProcess, remoteImage, buffer, nt->OptionalHeader.SizeOfHeaders, NULL);
  • 写入 PE 头信息。

  • 然后循环写入每个节区内容。

8. 修复 PEB 中的 ImageBase 地址

WriteProcessMemory(pi.hProcess, (LPVOID)(pebAddress + 8), &nt->OptionalHeader.ImageBase, ...);
  • 修改目标进程的 PEB,使其以为自己是 A.exe。

9. 设置线程入口地址为 A.exe 的 EntryPoint

ctx.Eax = (DWORD)remoteImage + nt->OptionalHeader.AddressOfEntryPoint;
SetThreadContext(pi.hThread, &ctx);
  • 修改线程的 EAX,使其跳转到新映像的入口。

10. 恢复线程运行,执行 A.exe

ResumeThread(pi.hThread);
  • 启动线程,运行 A.exe。

实验样本下载

请登录后发表评论