在PE文件中跳转存根

最近我反汇编了一个DLL(用c / c ++编写),注意到代码段中有很多“跳转桩”。 这些存根(stub)什么也不做,只是跳到DLL里面的函数。

例如:

jmp foo() jmp foo2() ... 

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

谢谢!

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

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

有关更多背景信息, 请参阅MSDN 。

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

 void (*fptr)() = foo; 

如果foo只是对DLL中某个地方的引用,这个地址如何解析将取决于加载器。 解决这个问题要比解决“这是一个foo()入口点,让你走向真正的富”这个问题复杂得多。

DLL是可重定位的,这意味着它们可能在内存中的任何地方结束。 这意味着所有的电话都必须重写。 通过将所有这样的调用保持在一个小的跳跃范围内,在重定位的情况下只需要重写一个页面。 这很重要,因为可以跨进程共享未改变的代码页面,但每个进程都有自己的修改页面副本。