2009-08-03 81 views
0

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

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

例如:

.text:402BE620 

哪些地址是在运行时?我如何将该数字转换为指针?

一些背景:我必须修复生命周期结束DLL中的错误,并且我们无法访问源代码。为此我想挂钩一个特定的函数并在运行时覆盖它。

(它包含WaitForSingleObject调用其中MsgWaitForMultipleObjects必须使用,因为它不能被固定用十六进制编辑器中的附加参数)

编辑:谢谢你的建议,但我加那些关于钩子的东西只是为了给你一些背景。 我不需要钩子框架!。我有一个很好的钩子框架,可以完成所有繁重的工作 - 至少现在 - 我不需要任何关于钩子本身的更多信息。

我只需提供函数的地址来挂钩我的钩子框架,并且我必须知道如何计算它,我不知道如何确定它。

编辑2:我已经使用了两个不同的反汇编程序,都显示上述地址。有点奇怪:如果我使用他们的“goto”功能,两者都拒绝“402BE620”作为偏移量。我必须输入偏移量作为“2BE620”以使其工作...

回答

0

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

只是一个想法....

+2

没有,这将工作。更改可执行页面将触发写入时复制,因此运行过程将永久使用修补后的代码。 – 2009-08-06 02:19:57

0

为了做这样的事,你通常会使用detours
它允许你创建一个正在运行的进程和钩线程在它/替换任何功能。
通常它通过查找符号来工作,但不应该有一个原因,它不会使用偏移量。

要专门回答你的问题,在dll文件中你通常会找到相对地址。相对于文件的开始。当一个PE(dll,exe)被加载到内存中时,所有的相对地址都被使用加载PE的基地址的绝对地址替换。您可以使用GetModuleHandle()
402BE620来查看特定DLL的基地址。根本看起来不像是相对地址。它确实看起来像一个绝对的地址,所以你最好确定反汇编器显示你的东西。相对地址不能大于它们所在的DLL文件的大小。
您可能会发现有用的另一个提示 - 将调试器附加到进程时,通常会列出所有的DLL及其基址。

0

这对API Interception via DLL Redirection(PDF)milw0rm纸
讨论了几种方式,应该给你一个想法,你的冒险。

虽然有几种方法可以用来实现我们的目标,但本教程将仅讨论DLL35重定向的 。选择这种方法有以下几个原因:

  1. 它的实现相对简单。
  2. 它允许我们查看和修改传递给API函数的参数,更改该函数的返回值以及运行我们期望的任何其他代码。
  3. 尽管大多数其他方法需要将代码注入到目标进程或从外部应用程序运行,但DLL重定向只需要对目标应用程序的 工作目录执行写入访问。
  4. 我们可以在不修改目标(在磁盘或内存中)或任何系统文件的情况下拦截任何API调用。

一旦我们将程序重定向到加载我们的DLL,我们需要具有它所需要的所有功能 正在寻找。假设我们要拦截Internet Explorer对 MessageBox进行的每个呼叫。 MessageBox位于user32.dll中,因此我们需要创建一个名为user32.dll的DLL,其中包含一个名为MessageBox的可导出函数,创建iexplore.exe.manifest文件,并将 放置到我们新创建的user32.dll和iexplore中。在C:\ Program Files \ Internet Explorer目录中的exe.manifest文件。现在,当IE导入其API函数时,它将从我们的 user32.dll文件加载MessageBox;那么,无论何时IE调用MessageBox函数,我们放置在我们的MessageBox函数上的代码都会被执行。

问题在于MessageBox不是从user32.dll导入的唯一函数。 可能有数百个IE会在user32.dll中查找的函数,如果其中任何一个是 丢失,那么IE将无法加载。因为我们不想重新编写所有的USER32 DLL函数,我们 将简单的功能,其余转发给其原始User32.dll文件

0

我不知道从偏移.text段,但在调试器中查看您想要的地址并从中减去模块加载偏移量。即使基地址是明确设置的,它也可能每次都在不同的地址加载。

替代运行时修补可能只是简单地修补dll本身。 OllyDbg是一款优秀的免费汇编级调试器和代码分析工具,可让您轻松修补二进制文件。

编辑:

只是为了好玩这是我用来使用扩展二进制补丁了一些功能我没有在一个应用程序像一些示例代码 - 在运行时。我做了一些简化,没有重新编译和测试,但你应该明白。

(我有二进制被周期性地更新的复杂化,因此,附加的工作模式匹配的小范围从已知偏移之内。)

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); 
       } 
      } 
     } 
    } 
} 
相关问题