我需要exe“tibia.exe”的基地址。这是我到目前为止所得到的,但它不起作用。它总是返回0
。
怎么了?
DWORD MainWindow::getBaseAddress(DWORD dwProcessIdentifier)
{
TCHAR lpszModuleName[] = {'t','i','b','i','a','.','e','x','e','\0'}; //tibia.exe
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,
dwProcessIdentifier);
DWORD dwModuleBaseAddress = 0;
if(hSnapshot != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 ModuleEntry32;
ModuleEntry32.dwSize = sizeof(MODULEENTRY32);
if(Module32First(hSnapshot, &ModuleEntry32))
{
do
{
if( wcscmp(ModuleEntry32.szModule, lpszModuleName) == 0)
{
dwModuleBaseAddress = (DWORD)ModuleEntry32.modBaseAddr;
break;
}
}
while(Module32Next(hSnapshot, &ModuleEntry32));
}
CloseHandle(hSnapshot);
}
return dwModuleBaseAddress;
}
//Call it here
tibiaWindow = FindWindow( L"TibiaClient", NULL);
DWORD PID;
GetWindowThreadProcessId( tibiaWindow, &PID );
DWORD baseAddress = getBaseAddress( PID );
if( baseAddress == 0 )
return false ;
答案 0 :(得分:2)
也许只是因为我在ToolHelp32可用之前使用它们(至少在基于NT的操作系统上),但我倾向于使用PSAPI函数来完成这类任务。使用它们,代码看起来像这样:
#include <windows.h>
#include <string>
#include <psapi.h>
#include <iostream>
int main(int argc, char **argv) {
HANDLE process = GetCurrentProcess();
if (argc != 1)
process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, atoi(argv[1]));
HMODULE handles[2048];
DWORD needed;
EnumProcessModules(process, handles, sizeof(handles), &needed);
for (int i = 0; i < needed / sizeof(handles[0]); i++) {
MODULEINFO info;
char name[1024];
GetModuleBaseName(process, handles[i], name, sizeof(name));
if (std::string(name).find(".exe") != std::string::npos) {
GetModuleInformation(process, handles[i], &info, sizeof(info));
std::cout << name << ": " << info.lpBaseOfDll << "\n";
break;
}
}
}
现在,这将允许您在命令行中输入进程ID,并显示在该进程中找到的第一个模块的加载地址,其名称包含“.exe”。如果你没有指定进程ID,它将搜索自己的进程(演示函数如何工作,但在其他方面几乎没用)。
使用ToolHelp32或PSAPI,您最终会遇到类似的限制:您需要将其编译为64位可执行文件,以便能够“看到”其他64位进程(即编译为32-时)位代码,他们只看到其他32位进程。)
还有一些进程(例如CSRSS.exe)无法成功打开/枚举。据我所知,使用PSAPI与ToolHelp32相同的过程将成功/失败。
与ToolHelp32相比,PSAPI确实有一点笨拙:处理(好)具有大量模块的进程是笨拙的(充其量)。您调用EnumProcessModules
,如果您没有为足够的模块腾出空间,则“Needed”参数将设置为其包含的模块数所需的空间。但是有一种竞争条件:在返回的时间和再次调用EnumProcessModules
的时间之间,进程可能加载了更多的DLL,因此第二次调用可能会以相同的方式失败。
目前,我只是假设没有任何进程会使用超过2048个模块。要真正正确,你应该有一个以零空间开头的while循环(或者可能是一个do / while循环),调用EnumProcessModules
以找出需要多少空间,分配它(可能还有一些额外的空间)如果它加载更多的DLL)并重复,直到它成功。