我最近开始了一个新项目,我的目标是将字节码注入(inject)另一个进程,然后启动一个远程线程执行我的字节码,但是我遇到了一个非常奇怪的问题。
它的作用是分配并写入任意进程的内存,它为远程进程写入一个包含指向 user32.dll 和 kernel32.dll 中函数的指针的结构体,它还为函数指针写入一个调用操作然后,它从该结构中创建一个带有“调用操作”的 lpStartAddress 的远程线程
您可以在这里找到源代码: http://pastie.org/9298306
在第 55 行调用 GetPrivileges(第 185 行的方法),它返回 true,这意味着 OpenProcessToken、LookupPrivilegeValue 和 AdjustTokenPrivileges 返回 true。
不久之后将调用以下内容:
param->pMessageBox = (DWORD)GetProcAddress(user32, "MessageBoxA");
param->pSleep = (DWORD)GetProcAddress(kernel32, "Sleep");
user32 和 kernel32 都是有效句柄,但 param->pMessageBox 将被设置为 NULL,而 param->pSleep 将获取 Sleep 的实际指针。
奇怪的是,当我用我在线复制的代码片段替换 GetPrivileges 时,它工作正常,并且 param->pMessageBox 将设置为正确的指针地址。
BOOL GetPrivileges()
{
HANDLE tokenHandle;
TOKEN_PRIVILEGES tokenPriv;
if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &tokenHandle) != 0)
{
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tokenPriv.Privileges[0].Luid);
tokenPriv.PrivilegeCount = 1;
tokenPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(tokenHandle, 0, &tokenPriv, sizeof(tokenPriv), NULL, NULL);
}
else
{
TCHAR buffer[256];
wsprintf(buffer, TEXT("0x%x"), GetLastError());
MessageBox(NULL, buffer, TEXT("OpenProcessTokenError"), MB_ICONERROR);
return FALSE;
}
return true;
}
继续进行调试,请注意,由于 OpenProcessToken 按预期返回 true,因此不会调用复制的 GetPrivileges 中的 else 语句,并删除:
TCHAR buffer[256];
wsprintf(buffer, TEXT("0x%x"), GetLastError());
param->pMessageBox 将设置为 NULL,怎么可能?
向沮丧的 ogelami 致敬。
最佳答案
模块句柄实际上无效。它们是远程进程的模块句柄。模块句柄实际上是作为基地址实现的,因此仅对执行进程的虚拟地址空间有意义。
碰巧,注入(inject)进程的kernel32模块的基地址与远程进程的kernel32模块的基地址相同。
实际上,如果您在注入(inject)过程中放入如此多的代码,您的目标将很难实现。如果将 DLL 注入(inject)到其他进程中,情况会更好。创建一个远程线程,其第一步是加载此 DLL。然后,您将在另一个进程的地址空间内运行代码,因此能够直接调用 GetModuleHandle
、GetProcAddress
等函数。
关于c++ - 当 hModule 和 lpProcName 有效时 GetProcAddress 返回 NULL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24259796/