Today I first encountered the fishhook library https://github.com/facebook/fishhook which can be used to dynamically rebind symbols in Mach-O binaries (they say for iOS, but I guess the code will also work on OS X).
So far I only knew and used mach_override https://github.com/rentzsch/mach_override which aims at a similar goal (i.e. replacing one implementation of a function with another one), but rewrites the assembler statements of the beginning of the function to jump to a different location.
The fishhook approach looks much simpler, but since it "only" rewrites the symbol table, I have the gut feeling that it is less generic than the mach_override approach.
Can someone give some hard technical facts on situations when one project should be preferred over the other (i.e. situations where one approach won't work, but the other will)?
The two approaches use different methods:
A) fishhook works, as you have stated, on symbols in the symbol table. This means that, if a symbol is exported by a dylib or framework, and you can patch the import table, you can redirect it to your implementation.
B) mach_override uses the Mach VM APIs of OS X (and iOS) to patch the functions when they are already loaded - i.e. already in memory. It does so by binary patching the beginning of the function implementation to jump to another address (your implementation) then jump back.
Fishhook is more stable, in the sense that it is (i) an easier operation to implement and (ii) seamless once the process is loaded by dyld and the symbols are linked. However, it will not work on symbols which are not directly loaded by the executable. In other words, if you want to patch printf(3), for example, it will only work on calls to printf from your executable, and not on calls made from libSystem, or other libraries. Mach_override, however, is not all that stable, however, since it relies on certain function prologs which can be overridden - some 90% of the time, but not 100%.
While yiding is correct about iOS pages being read only, in some cases it may be possible to work around that (if you patch the executable you can also patch the LC_SEGMENT and section commands), and you can use the mach VM apis to unprotect pages (only if the device is jailbroken).
Fishhook was created for the purpose of hooking the functions which served as entry points into system calls on iOS in order to track down a rarely occurring bug. On iOS, executable pages are read only, so it's infeasible to patch in jumps, but the tables used to locate dynamically linked functions are not read only, so we patch those instead.
This approach would for obvious reasons not work for functions which are not going through an dynamic-link stub, whereas for mach_override, it would work as long as you can locate the function and write to the memory page containing the code.
Note that I have not personally used mach_override, so I'm not sure how well it actually works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With