CreateToolhelp32Snapshot:INVALID_HANDLE_VALUE(ERROR_PARTIAL_COPY)

问题描述 投票:1回答:2

此代码在64位应用程序中运行。目标应用程序是32位。

每次运行此代码时,CreateToolhelp32Snapshot()返回INVALID_HANDLE_VALUE然后GetLastError()返回ERROR_PARTIAL_COPY。所以它跳过循环并返回false。

BOOL HookInjector::InjectIntoProcess(DWORD pID)
{
    //Get Handle to Remote Process
    HANDLE Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
    ....
    //Check to see if 64-bit or 32-bit application
    IsWow64Process(Proc, &isWow64);
    size_t szCurProc = sizeof(void*); //returns 8
    if (isWow64)
    {
        __debugbreak();
        //Get list of all Modules associated with the Process
        HANDLE hProc32Module;
        do {
            hProc32Module = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE32, pID);
        }
        while ((hProc32Module == INVALID_HANDLE_VALUE) && (GetLastError() == ERROR_BAD_LENGTH));

    if (hProc32Module == INVALID_HANDLE_VALUE) {
        __debugbreak();
        DWORD err = GetLastError(); //just to see the error code which is 0x12b
        return false;
    }

        //Find the module for Kernel.dll and get the base address of it
        MODULEENTRY32 entryModule;
        entryModule.dwSize = sizeof(MODULEENTRY32);
        BOOL isGetModuleSuccess = Module32First(hProc32Module, &entryModule);
        DWORD errEndofList = GetLastError();
        BOOL isSuccessful = false;
        while (errEndofList != ERROR_NO_MORE_FILES && isGetModuleSuccess)
        {
            if (_tcscmp(entryModule.szModule, KERNEL32_DLL)){
                isSuccessful = true;
                break;
            }
            isGetModuleSuccess = Module32Next(hProc32Module, &entryModule);
            errEndofList = GetLastError();
        }

        if (!isSuccessful)
        {
            __debugbreak();
            CloseHandle(hProc32Module);
            return false;
        }

        //Get handle for Kernel.dll module
        hKernel32 = entryModule.hModule;
        CloseHandle(hProc32Module);
    }
    else
    {
        ....
c++ windows snapshot
2个回答
1
投票

根据documentation,当CreateToolhelp32Snapshot()被试图访问64位进程的32位进程调用时,ERROR_PARTIAL_COPY只与CreateToolhelp32Snapshot()失败:

如果指定的进程是64位进程且调用程序是32位进程,则此函数将失败,最后一个错误代码为ERROR_PARTIAL_COPY(299)。

确保您的应用程序真正编译为64位开始。 TH32CS_SNAPMODULE32只有在64位进程中调用CreateToolhelp32Snapshot()时才有意义:

TH32CS_SNAPMODULE32 0x00000010 包括从64位进程调用时快照中th32ProcessID中指定的进程的所有32位模块。

您也没有考虑到GetLastError()仅在API函数失败时更新,除非另有说明。你的循环假设每次API调用后都会更新GetLastError(),这根本不是真的。

尝试更像这样的东西:

BOOL HookInjector::InjectIntoProcess(DWORD pID)
{
    //Get Handle to Remote Process
    HANDLE Proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID);
    ....

    DWORD dwFlag;
    #ifdef _WIN64
    //Check if Remote Process is a 32-bit application
    BOOL isWow64 = FALSE;
    IsWow64Process(Proc, &isWow64);
    if (!isWow64) return false;
    // TH32CS_SNAPMODULE32 includes 32bit modules when used by a 64bit process...
    dwFlag = TH32CS_SNAPMODULE32;
    #else
    // TH32CS_SNAPMODULE includes 32bit modules when used by a 32bit process...
    dwFlag = TH32CS_SNAPMODULE;
    #endif

    __debugbreak();

    //Get list of all Modules associated with the Process

    HANDLE hProc32Module;
    do {
        hProc32Module = CreateToolhelp32Snapshot(dwFlag, pID);
    }
    while ((hProc32Module == INVALID_HANDLE_VALUE) && (GetLastError() == ERROR_BAD_LENGTH));

    if (hProc32Module == INVALID_HANDLE_VALUE) {
        __debugbreak();
        return false;
    }

    //Find the module for Kernel.dll and get the base address of it

    hKernel32 = NULL;

    MODULEENTRY32 entryModule = {0};
    entryModule.dwSize = sizeof(MODULEENTRY32);

    BOOL isGetModuleSuccess = Module32First(hProc32Module, &entryModule);
    while (isGetModuleSuccess) {
        if (_tcscmp(entryModule.szModule, KERNEL32_DLL)) {
            hKernel32 = entryModule.hModule;
            break;
        }
        isGetModuleSuccess = Module32Next(hProc32Module, &entryModule);
    }

    if (!hKernel32) {
        __debugbreak();
        CloseHandle(hProc32Module);
        return false;
    }

    CloseHandle(hProc32Module);

    ....
}

0
投票

根据文档,当尝试访问64位进程的32位进程调用CreateToolhelp32Snapshot()时,CreateToolhelp32Snapshot()仅使用ERROR_PARTIAL_COPY失败:

如果指定的进程是64位进程且调用程序是32位进程,则此函数将失败,最后一个错误代码为ERROR_PARTIAL_COPY(299)。

这是完全错误的,因为你可以从你发布的摘录中推断出来。当调用者试图访问64位的32位时,它在哪里说它只能与ERROR_PARTIAL_COPY (299)失败?它没有。

如果文档是完整的,而不是文档,那么您可以正确地假设所述行为是生成ERROR_PARTIAL_COPY错误代码的唯一方法。遗憾的是,文档并不完整。

例如,如果使用CREATE_SUSPENDED标志启动进程,则CreateToolhelp32Snapshot API会在查询模块时将错误代码设置为ERROR_PARTIAL_COPY,而不管主机或目标应用程序的位数如何。我怀疑这是因为PebLdr中的PEB指针是NULL

基本上任何阻止读取进程内存(在PEB中丢失地址,未映射的段等)的内容都可能导致ERROR_PARTIAL_COPY的描述如下:

ERROR_PARTIAL_COPY 299 (0x12B)
Only part of a ReadProcessMemory or WriteProcessMemory request was completed.
© www.soinside.com 2019 - 2024. All rights reserved.