Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/facebook/fishhook
A library that enables dynamically rebinding symbols in Mach-O binaries running on iOS.
https://github.com/facebook/fishhook
Last synced: about 1 month ago
JSON representation
A library that enables dynamically rebinding symbols in Mach-O binaries running on iOS.
- Host: GitHub
- URL: https://github.com/facebook/fishhook
- Owner: facebook
- License: bsd-3-clause
- Created: 2013-07-11T20:12:26.000Z (over 11 years ago)
- Default Branch: main
- Last Pushed: 2023-03-07T07:33:58.000Z (over 1 year ago)
- Last Synced: 2024-05-18T17:01:39.866Z (6 months ago)
- Language: C
- Homepage:
- Size: 39.1 KB
- Stars: 5,122
- Watchers: 230
- Forks: 958
- Open Issues: 37
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
- Awesome-iOS - fishhook - A library that enables dynamically rebinding symbols in Mach-O binaries running on iOS. (Foundation)
- awesome-ios-security - fishhook - A library that enables dynamically rebinding symbols in Mach-O binaries running on iOS. (Tools / Dynamic Analysis Tools)
- awesome-apple-security - fishhook - A library that enables dynamically rebinding symbols in Mach-O binaries running on iOS. (Tools / Dynamic Analysis Tools)
README
# fishhook
__fishhook__ is a very simple library that enables dynamically rebinding symbols in Mach-O binaries running on iOS in the simulator and on device. This provides functionality that is similar to using [`DYLD_INTERPOSE`][interpose] on OS X. At Facebook, we've found it useful as a way to hook calls in libSystem for debugging/tracing purposes (for example, auditing for double-close issues with file descriptors).
[interpose]: http://opensource.apple.com/source/dyld/dyld-210.2.3/include/mach-o/dyld-interposing.h ""
## Usage
Once you add `fishhook.h`/`fishhook.c` to your project, you can rebind symbols as follows:
```Objective-C
#import#import
#import "AppDelegate.h"
#import "fishhook.h"
static int (*orig_close)(int);
static int (*orig_open)(const char *, int, ...);
int my_close(int fd) {
printf("Calling real close(%d)\n", fd);
return orig_close(fd);
}
int my_open(const char *path, int oflag, ...) {
va_list ap = {0};
mode_t mode = 0;
if ((oflag & O_CREAT) != 0) {
// mode only applies to O_CREAT
va_start(ap, oflag);
mode = va_arg(ap, int);
va_end(ap);
printf("Calling real open('%s', %d, %d)\n", path, oflag, mode);
return orig_open(path, oflag, mode);
} else {
printf("Calling real open('%s', %d)\n", path, oflag);
return orig_open(path, oflag, mode);
}
}
int main(int argc, char * argv[])
{
@autoreleasepool {
rebind_symbols((struct rebinding[2]){{"close", my_close, (void *)&orig_close}, {"open", my_open, (void *)&orig_open}}, 2);
// Open our own binary and print out first 4 bytes (which is the same
// for all Mach-O binaries on a given architecture)
int fd = open(argv[0], O_RDONLY);
uint32_t magic_number = 0;
read(fd, &magic_number, 4);
printf("Mach-O Magic Number: %x \n", magic_number);
close(fd);
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
```
### Sample output
```
Calling real open('/var/mobile/Applications/161DA598-5B83-41F5-8A44-675491AF6A2C/Test.app/Test', 0)
Mach-O Magic Number: feedface
Calling real close(3)
...
```## How it works
`dyld` binds lazy and non-lazy symbols by updating pointers in particular sections of the `__DATA` segment of a Mach-O binary. __fishhook__ re-binds these symbols by determining the locations to update for each of the symbol names passed to `rebind_symbols` and then writing out the corresponding replacements.
For a given image, the `__DATA` segment may contain two sections that are relevant for dynamic symbol bindings: `__nl_symbol_ptr` and `__la_symbol_ptr`. `__nl_symbol_ptr` is an array of pointers to non-lazily bound data (these are bound at the time a library is loaded) and `__la_symbol_ptr` is an array of pointers to imported functions that is generally filled by a routine called `dyld_stub_binder` during the first call to that symbol (it's also possible to tell `dyld` to bind these at launch). In order to find the name of the symbol that corresponds to a particular location in one of these sections, we have to jump through several layers of indirection. For the two relevant sections, the section headers (`struct section`s from ``) provide an offset (in the `reserved1` field) into what is known as the indirect symbol table. The indirect symbol table, which is located in the `__LINKEDIT` segment of the binary, is just an array of indexes into the symbol table (also in `__LINKEDIT`) whose order is identical to that of the pointers in the non-lazy and lazy symbol sections. So, given `struct section nl_symbol_ptr`, the corresponding index in the symbol table of the first address in that section is `indirect_symbol_table[nl_symbol_ptr->reserved1]`. The symbol table itself is an array of `struct nlist`s (see ``), and each `nlist` contains an index into the string table in `__LINKEDIT` which where the actual symbol names are stored. So, for each pointer `__nl_symbol_ptr` and `__la_symbol_ptr`, we are able to find the corresponding symbol and then the corresponding string to compare against the requested symbol names, and if there is a match, we replace the pointer in the section with the replacement.
The process of looking up the name of a given entry in the lazy or non-lazy pointer tables looks like this:
![Visual explanation](http://i.imgur.com/HVXqHCz.png)