Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
darwin: Massage libunwind around Frida hooks (#515)
The problem this change intends to solve is that, currently, with code like this: NSURL * url = nil; @Try { [NSBundle bundleWithURL:url]; } @catch (id err) { NSLog (@"No worries mate!"); } If there's any Frida hook, either via Interceptor or via NativeCallback swizzling like ObjC.implement(), anywhere in the call stack between the raise and the catch of the exception, libunwind fails to find the exception handler. This leads to uncaught exceptions which wouldn't happen without instrumentation. When libunwind fails to unwind it usually means it can't resolve the unwind info, and it can happen for two different reasons: 1. libunwind asks dyld, via _dyld_find_unwind_sections(), but if frida-agent is injected then dyld doesn't know about it and libunwind gives up on the first instruction pointer to any of frida-agent's code on the stack (as normally happens for swizzling-like hooks). 2. In case of Interceptor, for function-aware hooks, the original return address on the stack is replaced with the one needed to implement onLeave() which belongs to a runtime-generated code thunk, therefore missing its mapping to unwind info. This solution addresses the two above problems directly, via the new UnwindSitter component: 1. By hooking _dyld_find_unwind_sections() to provide the right unwind info for the "invader". 2. By hooking UnwindCursor::setInfoBasedOnIPRegister() to call gum_invocation_stack_translate() on the return address to restore the original one on the stack at unwind-time. All of this can be disabled via the `unwind-sitter:off` frida-agent option.
- Loading branch information