【问题标题】:Getting Base Address not working获取基地址不起作用
【发布时间】:2013-11-23 21:47:15
【问题描述】:

我需要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 ;

【问题讨论】:

  • lpszModuleName 最后缺少 '\0'
  • @halex 谢谢,现在去检查一下
  • @halex 还是 0 !
  • 进入调试器,找出失败的原因。
  • 对于那些不赞成投票的人,请告诉我为什么,以便我可以改进这个问题......

标签: c++ winapi base-address


【解决方案1】:

也许这只是因为我在 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,如果您没有为足够的模块留出空间,“需要”参数将设置为它包含的模块数量所需的空间。但是有一个竞争条件:在返回的时间和您再次调用 EnumProcessModules 的时间之间,该进程可能已经加载了更多的 DLL,因此第二次调用可能会以同样的方式失败。

目前,我只是假设没有进程会使用超过 2048 个模块。要真正正确,您应该有一个从零空间开始的 while 循环(或者可能是一个 do/while 循环),调用EnumProcessModules 以找出需要多少空间,分配它(可能需要额外的一点,以防万一加载更多的 DLL)并重复直到成功。

【讨论】:

  • 字符串比较有点脆弱。它匹配任何包含.exe 的模块名称,例如myapp.exe.resources.dll。 UNICODE 支持也不会受到影响。
  • @IInspectable:是的——其余的几乎都是为了演示如何使用这些功能。
  • 还有一件事,可能更重要的是要提到:字符串比较区分大小写,即它不会匹配MYAPP.EXE。我想这就是 OP 遇到的困难。
猜你喜欢
  • 2015-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多