6

今天我第一次遇到了鱼钩库https://github.com/facebook/fishhook,它可以用来动态地重新绑定 Mach-O 二进制文件中的符号(他们说适用于 iOS,但我猜该代码也适用于 OS X)。

到目前为止,我只知道并使用了 mach_override https://github.com/rentzsch/mach_override,它旨在实现类似的目标(即将一个函数的一个实现替换为另一个),但将函数开头的汇编语句重写为跳转到不同的位置。

鱼钩方法看起来要简单得多,但由于它“只”重写了符号表,我有直觉认为它不如 mach_override 方法通用。

有人可以就一个项目应该优先于另一个项目的情况(即一种方法行不通,但另一种方法行得通的情况)给出一些硬性技术事实吗?

4

2 回答 2

12

这两种方法使用不同的方法:

A)如您所述,鱼钩适用于符号表中的符号。这意味着,如果符号由 dylib 或框架导出,并且您可以修补导入表,则可以将其重定向到您的实现。

B) mach_override 使用 OS X(和 iOS)的 Mach VM API 来修补已经加载的函数 - 即已经在内存中。它通过二进制修补函数实现的开头来跳转到另一个地址(您的实现)然后跳转回来。

Fishhook 更稳定,因为它 (i) 操作更容易实现,并且 (ii) 一旦进程由 dyld 加载并链接符号,它就可以无缝运行。但是,它不适用于不是由可执行文件直接加载的符号。换句话说,如果你想修补 printf(3),例如,它只适用于从你的可执行文件调用 printf,而不适用于来自 libSystem 或其他库的调用。然而,Mach_override 并不是那么稳定,因为它依赖于某些可以被覆盖的函数序言——大约 90% 的时间,但不是 100%。

虽然 yiding 关于 iOS 页面只读是正确的,但在某些情况下可能会解决这个问题(如果您修补可执行文件,您也可以修补 LC_SEGMENT 和 section 命令),并且您可以使用 mach VM api 取消保护页面(仅当设备越狱时)。

于 2013-08-01T21:10:50.267 回答
4

Fishhook 的创建目的是为了将作为入口点的函数挂钩到 iOS 上的系统调用中,以追踪一个很少发生的错误。在 iOS 上,可执行页面是只读的,因此在跳转中修补是不可行的,但是用于定位动态链接函数的表不是只读的,所以我们改为修补它们。

由于显而易见的原因,这种方法不适用于不通过动态链接存根的函数,而对于 mach_override,只要您可以找到函数并写入包含代码的内存页面,它就可以工作。

请注意,我没有亲自使用过 mach_override,所以我不确定它的实际效果如何。

于 2013-08-01T06:31:44.210 回答