Search code examples
iosmacosmach-o

Technical differences between mach_override and fishhook?


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)?


Solution

  • 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).