Winapi 如何在运行时将Win32可执行文件的文本段中的偏移量转换为指针?

Winapi 如何在运行时将Win32可执行文件的文本段中的偏移量转换为指针?,winapi,pointers,executable,Winapi,Pointers,Executable,如何在运行时将Win32可执行文件文本段中的偏移量转换为指针? 当使用反汇编程序时,我可以看到相对地址。但如何在运行时将它们转换为绝对地址 例如: .text:402BE620 在运行时它是哪个地址?如何将该数字转换为指针 一些背景:我必须修复一个使用寿命结束的DLL中的错误,我们无法访问源代码。为此,我想钩住一个特定的函数,并在运行时重写它 (它包含对WaitForSingleObject的调用,其中必须使用MsgWaitForMultipleObjects,并且由于附加参数,无法使用十六进

如何在运行时将Win32可执行文件文本段中的偏移量转换为指针?

当使用反汇编程序时,我可以看到相对地址。但如何在运行时将它们转换为绝对地址

例如:

.text:402BE620
在运行时它是哪个地址?如何将该数字转换为指针

一些背景:我必须修复一个使用寿命结束的DLL中的错误,我们无法访问源代码。为此,我想钩住一个特定的函数,并在运行时重写它

(它包含对
WaitForSingleObject
的调用,其中必须使用
MsgWaitForMultipleObjects
,并且由于附加参数,无法使用十六进制编辑器修复)

编辑:谢谢你的建议,但我添加了关于钩住的内容只是为了给你一些背景知识我不需要挂钩框架。我有一个很好的挂钩框架,它可以完成所有的重物提升,至少现在,我不需要关于挂钩本身的更多信息

我只需要提供函数的地址来钩住我的钩住框架,为此我必须知道如何计算它,而我不知道如何确定它


编辑2:我使用了两个不同的反汇编程序,都显示了如上所述的地址。有点奇怪:如果我使用他们的“goto”功能,他们都会拒绝将“402BE620”作为偏移量。我必须以“2BE620”的形式输入偏移量才能使其生效…

我不知道您具体问题的答案,但即使我知道,我认为您的计划也行不通。我认为您计划通过调用(或跳转)到您自己的代码来动态地修补函数调用?但是,如果包含修补程序的页面被操作系统丢弃,然后在稍后某个时间重新加载(从DLL磁盘映像)会发生什么情况?您将如何检测并重新修补它


只是一个想法……

要做这样的事情,您通常会使用
它允许您在正在运行的进程中创建线程,并钩住/替换其中的任何函数。
通常它是通过查找符号来工作的,但不应该有任何理由不使用偏移量

为了明确回答您的问题,通常在dll文件中可以找到相对地址。相对于文件的开头。当PE(dll,exe)加载到内存中时,所有相对地址都将使用加载PE的基址替换为绝对地址。您可以使用
402BE620
看起来根本不像相对地址。它看起来真的像一个绝对地址,所以你最好确定反汇编程序向你显示了什么。相对地址不能大于它们所在的DLL文件的大小。

您可能会发现另一个有用的提示—当您将调试器附加到进程时,它通常会列出所有DLL及其基本地址。

这篇milw0rm论文(PDF) 讨论了一些方法,可以让你知道你在哪里冒险

虽然有几种方法可以用来实现我们的目标,但本教程将 只检查DLL重定向。选择这种方法有几个原因:

  • 它的实现相对简单
  • 它允许我们查看和修改传递给API函数的参数,更改该函数的返回值,并运行所需的任何其他代码
  • 而大多数其他方法需要将代码注入目标进程或从 外部应用程序,DLL重定向只需要对目标应用程序的 工作目录
  • 我们可以拦截任何API调用,而无需修改目标(在磁盘或内存中)或任何 系统文件
  • 一旦我们将程序重定向到加载DLL,我们就需要拥有它所包含的所有函数 他正在寻找。假设我们想要截获Internet Explorer对 MessageBox。MessageBox位于user32.dll中,因此我们需要创建一个名为user32.dll的dll 包含名为MessageBox的可导出函数,创建iexplore.exe.manifest文件,然后 将新创建的user32.dll和iexplore.exe.manifest文件放在C:\Program files\Internet中 资源管理器目录。现在当IE导入它的API函数时,它将从我们的 user32.dll文件;然后,每当IE调用MessageBox函数时,我们在 MessageBox函数将被执行

    问题是MessageBox不是将从user32.dll导入的唯一函数。 IE可能会在user32.dll中寻找数百个函数,如果其中任何一个是 丢失则IE将无法加载。因为我们不想重写所有的user32dll函数,所以我们 只需将其余函数转发到原始user32.dll文件


    具体来说,我不知道.text段的偏移量,但在调试器中查看所需的地址并从中减去模块加载偏移量。即使显式设置了基址,它也可能每次在不同的地址加载

    运行时修补的替代方法可能是简单地修补dll本身。是一个伟大的免费汇编级调试器和代码分析工具,可以让您轻松地修补二进制文件

    编辑:

    为了好玩,这里有一些示例代码,我在运行时使用扩展来修补我不喜欢的应用程序中的一些功能。我做了一些简化,没有重新编译和测试,但你应该明白了

    (我的问题是二进制文件会定期更新,因此需要在已知偏移量的小范围内进行额外的模式匹配。)

    void MyCrazyPatch()
    {
    静态布尔修补=错误;
    如果(!已修补)
    {
    
    void MyCrazyPatch()
    {
        static bool patched = false;
    
        if (!patched)
        {
            patched = true;
    
            DWORD dwPatchOffsetStart = 0x5310;
            DWORD dwPatchLength = 22;
    
            BYTE rgPatchMatch[] = { 0xab, 0x07, 0x37, 0x56, 0x50, 0xe8, 0x92, 0xfb, 0xff, 0xff, 0x83, 
                                    0xf8, 0x01, 0x89, 0xb5, 0xfc, 0x0f, 0x85, 0xb2, 0xaa, 0x00, 0x00, 0x8b };
    
            HMODULE hmod = GetModuleHandle(L"mybinary.dll");
            if (hmod != NULL
            {
                MODULEINFO modInfo;
                if (GetModuleInformation(GetCurrentProcess(),
                                         hmod,
                                         &modInfo,
                                         sizeof(modInfo)))
                {
                    DWORD dwIncrement = 0;
                    dwPatchOffsetStart += (DWORD)modInfo.lpBaseOfDll;
    
                    while (dwIncrement < 0x200 &&
                           memcmp((void*)(dwPatchOffsetStart + dwIncrement),
                                  rgPatchMatch,
                                  sizeof(rgPatchMatch)) != 0)
                    {
                        dwIncrement++;
                    }
    
                    // Sanity check then add nop's to stomp out the offending code.
                    if (dwIncrement < 0x200 &&
                        memcmp((void*)(dwPatchOffsetStart + dwIncrement),
                               rgPatchMatch,
                               sizeof(rgPatchMatch)) == 0)
                    {
                        DWORD dwOldProtect = 0;
    
                        VirtualProtect((void*)(dwPatchOffsetStart + dwIncrement),
                                       dwPatchLength,
                                       PAGE_EXECUTE_READWRITE,
                                       &dwOldProtect);
                        memset((void*)(dwPatchOffsetStart + dwIncrement), 0x90, dwPatchLength);
    
                        VirtualProtect((void*)(dwPatchOffsetStart + dwIncrement),
                                       dwPatchLength,
                                       dwOldProtect,
                                       NULL);
                    }
                }
            }
        }
    }