CreateToolhelp32Snapshot:INVALID_HANDLE_VALUE(ERROR_PARTIAL_COPY)

时间:2014-10-20 20:28:33

标签: c++ windows snapshot

此代码在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
    {
        ....

2 个答案:

答案 0 :(得分:1)

根据documentation,当{32}进程尝试访问64位进程调用CreateToolhelp32Snapshot()时,ERROR_PARTIAL_COPY仅在CreateToolhelp32Snapshot()时失败:

  

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

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

  

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

除非另有说明,否则您也没有考虑{API}仅在API函数失败时更新GetLastError()。你的循环假设每次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);

    ....
}

答案 1 :(得分:0)

  

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

     
    

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

  

这是很明显的错误,因为您可以从发布的摘录中推论得出。它在哪里说只有32位呼叫者尝试访问64位时,它仅以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.