【问题标题】:Converting "application's" memory address转换“应用程序的”内存地址
【发布时间】:2015-01-03 03:10:43
【问题描述】:

因此,我正在为 Microsoft 的 Spider Solitaire 编写我的第一个培训师。首先,我需要对所有内存地址进行反向工程,直到找到一个静态地址。我使用了偏移量,因此我可以轻松地将它们还原。

我发现了这个:

1000157F78  <-- starting value(never changes)
+ E8        <-- offsets to pointers
+ 14
002DC3D4    <-- final adress(changes every time)

这是我的训练师获取他最终记忆地址的方式:

DWORD FindFinalAddr(HANDLE hProc, BYTE offsets[], DWORD baseAddress, unsigned char pointerLevel)
{
    DWORD pointer = baseAddress;
    DWORD pTemp = 0;
    DWORD pointerAddr = 0;

    // set base address
    ReadProcessMemory(hProc, (LPCVOID)pointer, &pTemp, (DWORD)sizeof(pTemp), NULL);

    for (int c = 0; c < pointerLevel; c++)
    {
        pointerAddr = pTemp + (DWORD)offsets[c];
        ReadProcessMemory(hProc, (LPCVOID)pointerAddr, &pTemp, (DWORD)sizeof(pTemp), NULL);
    }

    return pointerAddr;
}

在这种情况下,我(大致)这样做:FindFinalAddr(hProc, {0xE8, 0x14}, 0x1000157F78, 2);

当蜘蛛纸牌打开并且我刚刚找到静态值时,这可以正常工作。 但是当我关闭它并重新打开它时它不再有效。

我发现1000157F78实际上是SpiderSolitaire.exe+B5F78,就像一个偏移量。如果我在作弊引擎中输入它,我会得到正确的内存地址,但我不能简单地在我的代码中输入它。

现在我的问题是:如何将SpiderSolitaire.exe+B5F78 转换为正确的内存地址?

注意:SpiderSolitaire.exe 是 64 位的。

编辑: 我尝试了以下方法:

void * entryPoint = (void*) hProc;

DWORD base_addr = ((DWORD)(entryPoint) + 0xB5F78);

但这不起作用,因为入口点是5C。它应该给出的地址(在这个会话中)是FF7A5F78,但真正发生的是5C + B5F78 = B5F4D

【问题讨论】:

  • 地址空间随机化:en.wikipedia.org/wiki/…
  • 这是系统特定的。您没有说明系统(某些 M$ 系统除外)。版本? 64位? 32 位?
  • 好点,@user3344003。我在 Windows 7 64 位上。
  • @user:这不是系统特定的。确定模块基地址所需的 API 调用适用于所有受支持的 Windows 版本,并且它们的使用方式相同。

标签: c++ winapi pointers memory reverse-engineering


【解决方案1】:

我认为您可以使用GetModuleInformation 查询加载地址,将NULL 传递给模块句柄参数。如果这不起作用,您可以通过EnumProcessModulesGetModuleBaseName 采取更长的路线。

【讨论】:

  • 是的,这就是我过去做过类似事情的方式。或者,您可以注入代码,然后加载您设计的 DLL,该 DLL 将加载到进程地址空间本身,这使得使用 GetProcAddress 更容易。
  • 我研究了它,但我并没有真正理解它。不过我试过了。它没有用,至少对于 GetModuleInformation 来说是这样。能给我举个例子吗?或者我需要对 ModuleInformation 做什么?
  • 模块信息包含应该添加相对偏移量的模块的基地址。
  • @Jester 我试过了,我得到了不同的入口点(这很好),但它不起作用。
  • 基地址可能不是完全相同的参考点,但它应该只是一个可以轻松计算的恒定偏移量。
【解决方案2】:

经过长时间的研究,我找到了自己的答案! 这段代码获取模块基地址(AKA入口点)(需要包含TlHelp32.h和tchar.h):

DWORD getModuleBaseAddr(DWORD procId, TCHAR * lpszModuleName)
{
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, procId);
    DWORD moduleBaseAddr = 0;

    if (hSnapshot != INVALID_HANDLE_VALUE)
    {
        MODULEENTRY32 mentry32 = { 0 };
        mentry32.dwSize = sizeof(MODULEENTRY32);

        if (Module32First(hSnapshot, &mentry32))
        {
            do
            {
                if (_tcscmp(mentry32.szModule, lpszModuleName) == 0)
                {
                    moduleBaseAddr = (DWORD)mentry32.modBaseAddr;
                    break;
                }
            } while (Module32Next(hSnapshot, &mentry32));
        }
    }
    else
    {
        std::cout << "Error on finding module base address: " << GetLastError() << "\n";
    }

    return moduleBaseAddr;
}

你给它 pid 和模块的名称(如 game.exe),然后它浏览模块并检查它们是否相同,然后返回基地址。

现在,我用蜘蛛纸牌对此进行了测试。它给了我一个错误。 那是因为我编译的代码是32位的,SpiderSolitaire.exe是64位的,这是因为我的Windows 7是64位的。

因此,请确保您的代码与您的目标代码具有相同的平台目标!

【讨论】:

    猜你喜欢
    • 2012-03-21
    • 2016-10-12
    • 1970-01-01
    • 1970-01-01
    • 2020-12-08
    • 2019-07-03
    • 2013-04-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多