【问题标题】:jump stubs in PE filesPE文件中的跳转存根
【发布时间】:2013-06-02 05:00:54
【问题描述】:

最近我反汇编了一个 DLL(用 c/c++ 编写),发现代码段中有很多“跳转存根”。这些存根除了跳转到 DLL 中的函数之外什么都不做。

例如:

jmp foo() 
jmp foo2()
...

为什么编译器 (Visual Studio 2012) 在二进制文件中包含这些函数存根?

谢谢!

【问题讨论】:

    标签: c++ windows reverse-engineering portable-executable


    【解决方案1】:

    在所有存根之后是否有一大堆 0xCC 字节?如果是这样,您正在查看已在启用增量链接的情况下编译的代码(调试版本的默认设置)。

    编译增量链接时,编译器会为每个函数创建一个存根,并确保所有调用都通过存根进行。如果需要用更新的代码替换函数,可以在末尾添加新代码,只需修补跳转 thunk - 所有现有调用都将重定向到新代码。额外的 CC 保留给更多存根,以防添加新功能。

    更多背景信息,see MSDN

    【讨论】:

    • 是的,在这些 thunk 之后有一堆 0xcc 字节。而且这些 thunk 只出现在发布版本中。
    【解决方案2】:

    这就是链接器和 DLL 的符号“混合在一起”的方式。它保证在符号表中使用正确的偏移量,可以由加载 DLL 的加载器解析(并因此更新 DLL 中函数的地址),并且编译后的代码仍然可以处理例如函数指针:

    void (*fptr)() = foo;
    

    如果foo 只是对 DLL 中某个位置的引用,那么如何解析此地址将取决于加载程序。解决这个问题要比解决“这里有一个 foo() 入口点,让你找到真正的 foo”的问题要复杂得多。

    【讨论】:

    • DLL = 共享库。是的,我们说的是foomydll.dll 的一部分,而不是myprog.exe
    【解决方案3】:

    DLL 是可重定位的,这意味着它们可能最终位于内存中的任何位置。这意味着对它们的所有调用都必须重写。通过将所有这些调用放在一个小的跳转表中,在重定位的情况下只需要重写一页。这很重要,因为可以跨进程共享未更改的代码页面,但每个进程都有自己的修改页面副本。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-19
      • 1970-01-01
      • 2015-08-15
      • 2021-10-29
      相关资源
      最近更新 更多