-
-
Couldn't load subscription status.
- Fork 678
Description
My use case looks something like the following:
| `executable.c` | `patch.c` |
|---|---|
#include <stdio.h>
#include <stdlib.h>
int target(char* x) {
return atoi(x) + 10;
}
int main(int argc, char** argv) {
if (argc) {
int result = target(argv[0]);
printf("%d\n", result);
return 0;
}
return 1;
} |
#include <stdlib.h>
#include <string.h>
int target_a(char* ) {
return atoi(x) + 15;
}
int target_b(char* ) {
return strlen(x) + 15;
} |
Given a Mach-O executable compiled from the former file, and an object file compiled from the latter, it's currently possible to use LIEF to inject the patch code into new segments and sections (it's finicky, but possible), and replace the behavior of target with the behavior of target_a (by updating the symbol table, and/or by inserting a jump from &target to &target_a).
target_b is trickier, though. While atoi, strlen, and printf all come from the same shared library on macOS (/usr/lib/libSystem.B.dylib), strlen is completely unknown to the original binary, and the dynamic linker has no instructions for dealing with it.
Implementing a dynamic binding like this requires (if I understand correctly, which is far from guaranteed), adding an additional instruction to __TEXT,__stubs, adding an additional pointer to __DATA,__nl_symbol_ptr or __DATA,__la_symbol_ptr (pointed at 0x0 or __TEXT,__stub_helper, respectively), and a new symbol table entry that points to the __TEXT,__stubs instruction. Unfortunately, I have not found the appropriate public APIs to extend or update existing sections safely, nor to resolve section or segment overlaps.
In my ideal world, it would be straightforward to add new dynamic bindings with a simple convenience method (e.g. binary->add_dynamic_binding(symbol, library)); practically speaking, there's probably more general value in providing better tools for manipulation of all the various elements of the problem.