此代码在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
{
....
根据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);
....
}
根据文档,当尝试访问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.