Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Massage libunwind around Frida hooks #515

Merged
merged 14 commits into from
May 13, 2024
Merged

Massage libunwind around Frida hooks #515

merged 14 commits into from
May 13, 2024

Conversation

mrmacete
Copy link
Contributor

@mrmacete mrmacete commented Mar 29, 2024

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, leading 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 2 different reasons:

  1. libunwind asks dyld (via _dyld_find_unwind_sections()) but if the Frida agent is injected then dyld doesn't know about it and libunwind gives up on the first instruction pointer to any Frida agent's code in the stack (like normally happens for swizzling-like hooks)
  2. in case of Interceptor instead, 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

The solution proposed here 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 this can be disabled via the "unwind-sitter:off" frida-agent option.

@mrmacete mrmacete marked this pull request as draft March 29, 2024 08:53
@mrmacete mrmacete force-pushed the feature/unwind-sitter branch 2 times, most recently from ebce292 to ce38fd8 Compare April 8, 2024 13:45
@mrmacete mrmacete marked this pull request as ready for review April 8, 2024 15:10
@mrmacete mrmacete force-pushed the feature/unwind-sitter branch from 1d661a5 to dc7882e Compare April 11, 2024 11:56
@oleavr oleavr force-pushed the feature/unwind-sitter branch from dc7882e to 9faf9bd Compare May 13, 2024 13:20
@oleavr oleavr merged commit ab28e33 into main May 13, 2024
28 of 29 checks passed
@oleavr oleavr deleted the feature/unwind-sitter branch May 13, 2024 20:29
@oleavr
Copy link
Member

oleavr commented May 13, 2024

Thanks! 🙌 Amazing work!! 🔥

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants