今天我第一次遇到了鱼钩库https://github.com/facebook/fishhook,它可以用来动态重新绑定Mach-O二进制文件中的符号(他们说对于iOS,但我想这些代码也适用于OS X)。
到目前为止,我只知道并使用了mach_override https://github.com/rentzsch/mach_override,它的目标是类似的目标(即用另一个函数替换一个函数的一个实现),但是重写函数开头的汇编语句以跳转到不同的位置。
鱼钩方法看起来更简单,但由于它“仅”重写了符号表,我觉得它不像mach_override方法那样通用。
当一个项目优先于另一个项目时(即一种方法不起作用,但另一种方法不起作用的情况),有人可以提供一些关于情况的技术性事实吗?
答案 0 :(得分:10)
这两种方法使用不同的方法:
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 apis取消保护页面(仅当设备被越狱时)。
答案 1 :(得分:4)
创建Fishhook的目的是将作为入口点的函数挂钩到iOS上的系统调用,以便追踪很少发生的错误。在iOS上,可执行页面是只读的,因此在跳转中进行补丁是不可行的,但用于定位动态链接函数的表不是只读的,所以我们改为修补它们。
这种方法由于显而易见的原因不适用于不通过动态链接存根的函数,而对于mach_override,只要您可以找到函数并写入包含代码的内存页面,它就会起作用。 / p>
请注意,我没有亲自使用过mach_override,所以我不确定它的实际效果如何。