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

Process Hollowing实现触发访问违例错误c0000005求助

Process Hollowing(RunPE)实现后触发访问违例的调试思路请求

我参考教程结合自身知识,用C语言实现Process Hollowing(RunPE)技术:创建挂起状态的calc.exe进程,找到其PEB及镜像基址并解除内存映射,读取notepad.exe的PE头、节区等内容写入目标进程内存,通过重定位表修补字节,修改线程上下文将EAX设为新进程入口点后恢复主线程。经WinDbg调试确认内存写入正常,但恢复线程后触发如下访问违例错误:

(216c.3d84): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=02fc1860 ebx=030a4000 ecx=00000000 edx=00000000 esi=00000000 edi=00000000
eip=76f35080 esp=02f6fe58 ebp=00000000 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
ntdll!RtlUserThreadStart:
76f35080 833ddc69fe7600  cmp     dword ptr [ntdll!LdrDelegatedRtlUserThreadStart (76fe69dc)],0 ds:002b:76fe69dc=00000000

我是逆向新手,请求提供进一步调试的思路。以下是我的main.c代码:

#include <Windows.h>
#include <stdio.h>
#include <winternl.h>


typedef NTSTATUS(NTAPI* NtUnmapViewOfSection)(
    HANDLE ProcessHandle,
    PVOID  BaseAddress
    );


int main(int argc, char* argv[])
{

    printf("Creating process\r\n");

    LPSTARTUPINFOA si = (LPSTARTUPINFOA)calloc(1, sizeof(STARTUPINFOA));
    LPPROCESS_INFORMATION pi = (LPPROCESS_INFORMATION)calloc(1, sizeof(PROCESS_INFORMATION));

    // Start process in suspended state
    if (!CreateProcessA
    (
        "C:\\Windows\\sysWOW64\\calc.exe",
        NULL,
        NULL,
        NULL,
        NULL,
        CREATE_SUSPENDED,
        NULL,
        NULL,
        si,
        pi
    ))
    {
        printf("Error with CreateProcessA - %d", GetLastError());
        return 1;
    }

    if (!pi->hProcess)
    {
        printf("Error creating process - %d", GetLastError());
        return 1;
    }

    HANDLE hDestProcess = pi->hProcess;

    PROCESS_BASIC_INFORMATION* pbi = (PROCESS_BASIC_INFORMATION*)calloc(1, sizeof(PROCESS_BASIC_INFORMATION));
    DWORD retLen = 0;

    // Find PEB
    if (NtQueryInformationProcess(hDestProcess, ProcessBasicInformation, pbi, sizeof(PROCESS_BASIC_INFORMATION), &retLen))
    {
        printf("Error finding peb - %d", GetLastError());
        return 1;
    }

    printf("PEB address: %p\n", pbi->PebBaseAddress);

    DWORD pebImageBaseOffset = (DWORD)pbi->PebBaseAddress + 0x8;

    LPVOID destImageBase = 0;
    SIZE_T bytesRead;

    // Find image base by PEB's offset 0x8
    if (!ReadProcessMemory(hDestProcess, (LPCVOID)pebImageBaseOffset, &destImageBase, 0x4, &bytesRead))
    {
        printf("Error getting process's image base - %d", GetLastError());
        return 1;
    }

    printf("Process image base: %p\n", destImageBase);

    // Read other exe file
    HANDLE sourceFile =
        CreateFileA("C:\\Windows\\sysWOW64\\notepad.exe", GENERIC_READ, NULL, NULL, OPEN_EXISTING, NULL, NULL);
    DWORD sourceFileSize = GetFileSize(sourceFile, NULL);
    DWORD fileBytesRead = 0;
    LPVOID sourceFileStart = (LPVOID)malloc(sourceFileSize);
    ReadFile(sourceFile, sourceFileStart, sourceFileSize, &fileBytesRead, NULL);

    PIMAGE_DOS_HEADER sourceDosHeader = (PIMAGE_DOS_HEADER)sourceFileStart;
    PIMAGE_NT_HEADERS sourceNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)sourceFileStart + sourceDosHeader->e_lfanew);
    SIZE_T sourceSize = sourceNtHeaders->OptionalHeader.SizeOfImage;

    // Get the NtUnmapViewOfSection function and unmap the memory
    NtUnmapViewOfSection NtUnmapViewOfSectionFunc =
        (NtUnmapViewOfSection)GetProcAddress(GetModuleHandleA("ntdll"), "NtUnmapViewOfSection");

    if (NtUnmapViewOfSectionFunc == NULL)
    {
        printf("Problem finding NtUnmapViewOfSection - %d", GetLastError());
        return 1;
    }

    if (NtUnmapViewOfSectionFunc(hDestProcess, destImageBase))
    {
        printf("Problem unmapping process virtual memory");
        return 1;
    }

    printf("Memory unammped\n");

    PVOID newDestImageBase =
        VirtualAllocEx(hDestProcess, NULL, sourceSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

    printf("New allocated image base: %p\n", newDestImageBase);

    sourceNtHeaders->OptionalHeader.ImageBase = (DWORD)destImageBase;

    // Write headers
    if (!WriteProcessMemory(hDestProcess, newDestImageBase, sourceFileStart, sourceNtHeaders->OptionalHeader.SizeOfHeaders, NULL))
    {
        printf("Problem writing headers - %d", GetLastError());
        return 1;
    }
    
    PIMAGE_SECTION_HEADER sourceSection = IMAGE_FIRST_SECTION(sourceNtHeaders);
    PIMAGE_SECTION_HEADER sourceSectionOld = sourceSection;

    // Save the reloc table pointer for later
    DWORD sourceRelocTableRaw;

    // Write sections
    for (int i = 0; i < sourceNtHeaders->FileHeader.NumberOfSections; i++)
    {
        if (!sourceSection->PointerToRawData)
            continue;

        PVOID destSectionAddr = (PVOID)((DWORD)newDestImageBase + sourceSection->VirtualAddress);
        PVOID sourceSectionAddr = (PVOID)((DWORD)sourceFileStart + sourceSection->PointerToRawData);

        printf("Writing %s section to %p\r\n", sourceSection->Name, destSectionAddr);

        if (!WriteProcessMemory(hDestProcess, destSectionAddr, sourceSectionAddr, sourceSection->SizeOfRawData, NULL))
        {
            printf("Problem writing sections - %d", GetLastError());
            return 1;
        }

        if (memcmp(sourceSection->Name, ".reloc", 6) == 0)
        {
            sourceRelocTableRaw = sourceSection->PointerToRawData;
        }

        sourceSection++;
    }

    // Getting the difference between the real based address and the preferred base address, for relocations
    DWORD deltaImageBase = (DWORD)newDestImageBase - sourceNtHeaders->OptionalHeader.ImageBase;

    IMAGE_DATA_DIRECTORY relocTable = sourceNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
    DWORD relocOffset = 0;

    while (relocOffset < relocTable.Size)
    {
        PIMAGE_BASE_RELOCATION relocBlock = (PIMAGE_BASE_RELOCATION)((DWORD)sourceFileStart + sourceRelocTableRaw + relocOffset);
        relocOffset += sizeof(IMAGE_BASE_RELOCATION);
        DWORD relocEntryCount = (relocBlock->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
        PWORD relocEntries = (PWORD)((DWORD)sourceFileStart + sourceRelocTableRaw + relocOffset);

        for (DWORD i = 0; i < relocEntryCount; i++)
        {
            relocOffset += sizeof(WORD);

            if (relocEntries[i] & 0xF000 == IMAGE_REL_BASED_ABSOLUTE)
            {
                // Skip this entry, since it represents an absolute address
                continue;
            }

            DWORD patchAddrRVA = relocBlock->VirtualAddress + (relocEntries[i] & 0x0FFF);
            DWORD patchedBuff = 0;
            
            if (!ReadProcessMemory(hDestProcess, (DWORD)newDestImageBase + patchAddrRVA, &patchedBuff, sizeof(DWORD), &bytesRead))
            {
                printf("Problem reading bytes to patch - %d", GetLastError());
                return 1;
            }

            // Add the difference between the actual image base and the preferred image base
            patchedBuff += deltaImageBase;

            if (!WriteProcessMemory(hDestProcess, (DWORD)newDestImageBase + patchAddrRVA, &patchedBuff, sizeof(DWORD), NULL))
            {
                printf("Problem writing patched bytes - %d", GetLastError());
                return 1;
            }
        }
    }

    printf("Relocation bytes patched\n");

    // Get context of the main thread
    LPCONTEXT context = (LPCONTEXT)malloc(sizeof(CONTEXT));;
    context->ContextFlags = CONTEXT_INTEGER;
    GetThreadContext(pi->hThread, context);

    // Change entry point
    DWORD newEntryPoint = (DWORD)newDestImageBase + sourceNtHeaders->OptionalHeader.AddressOfEntryPoint;
    context->Eax = newEntryPoint;
    
    printf("New entry point addr: %p\n", newEntryPoint);

    // Set the main thread context with eax containing the new entry point
    SetThreadContext(pi->hThread, context);

    // Finally, resume the main thread
    ResumeThread(pi->hThread);
    printf("Process main thread resumed");

    // Close handles
    CloseHandle(pi->hProcess);
    CloseHandle(pi->hThread);

    return 0;
}

恳请各位提供调试建议,非常感谢!


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 09:22:08