Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,79 @@ if (ObjC.available) {
}
```

## LLDB-Assisted Frida Detection Bypass & Swift Hooking

### Remote debugging pipeline

Penetration tests against production-like builds often require keeping jailbreak protections enabled while still attaching Frida. A reliable workflow is to pair Apple’s `debugserver` with LLDB over USB multiplexing:

1. Forward SSH so the jailbroken phone is reachable even without Wi-Fi: `iproxy 2222 22 &` followed by `ssh root@localhost -p 2222`.
2. On the device, spawn the debugger stub and make it wait for the target process: `debugserver *:5678 --waitfor <BundleName>` and then launch the app from the SpringBoard.
3. Forward the debugging port and attach LLDB from macOS:

```bash
iproxy 1234 5678 &
lldb
(lldb) process connect connect://localhost:1234
```

4. Use `finish` a few times so constructors return and LLDB can resolve every Swift/ObjC image before you start patching symbols.

Keeping `frida-server` running in parallel now becomes viable even if the app performs anti-instrumentation checks during startup.

### Patching Swift jailbreak / Frida checks

Swift apps frequently centralize jailbreak detection into a boolean helper such as `systemSanityCheck() -> Bool`. With LLDB already attached you can resolve the function name and force it to return `false` without touching the binary:

```bash
(lldb) image lookup -rn 'frida'
(lldb) image lookup -rn 'Check' FridaInTheMiddle.debug.dylib
(lldb) breakpoint set --name 'FridaInTheMiddle.systemSanityCheck'
(lldb) c
(lldb) finish
(lldb) register write x0 0
(lldb) c
```

On arm64 the Swift return value lives in `x0`, so zeroing that register after `finish` makes every caller believe the environment is clean, which keeps the UI alive while `frida-server` remains listening.

### Discovering Swift targets for Frida

Once the detection code is neutralized you can dynamically discover the mangled name of the function that handles sensitive data (e.g. the action behind a “Get Flag” button) instead of guessing:

```bash
frida-trace -U <BundleName> -i "*dummy*"
```

Trigger the UI action and `frida-trace` will log the exact symbol such as `$s16FridaInTheMiddle11ContentViewV13dummyFunction4flagySS_tF`. That string can be fed into `Module.load(<app>.debug.dylib).findExportByName()` inside a Frida script for precise hooking.

### Hooking Swift `String` arguments

Understanding the Swift ABI is essential to rebuild high-level arguments from registers when you intercept pure Swift functions:

- **Small strings (≤15 bytes)** are stored inline and the low byte of `x0` carries the length. The characters themselves are packed in the remainder of `x0`/`x1`.
- **Large strings (>15 bytes)** are heap-backed objects. `x1` holds the pointer to the object header and the UTF‑8 buffer starts at `x1 + 32`.

A single hook can extract both cases without reverse engineering the app’s source:

```javascript
const mod = Module.load('FridaInTheMiddle.debug.dylib')
const fn = mod.findExportByName('$s16FridaInTheMiddle11ContentViewV13dummyFunction4flagySS_tF')
Interceptor.attach(fn, {
onEnter() {
const inlineLen = this.context.x0.and(0xff)
if (inlineLen.toInt32() > 0 && inlineLen.toInt32() <= 15) {
console.log('flag:', this.context.x0.readUtf8String(inlineLen.toInt32()))
return
}
const heapPtr = ptr(this.context.x1).add(32)
console.log('flag:', heapPtr.readUtf8String())
}
})
```

Instrumenting the function at this level means any secret `String` arguments—flags, session tokens, or dynamically generated credentials—can be dumped even when the UI never displays them. Combine this hook with the LLDB patch above to keep the app running under observation despite jailbreak or Frida detections.

## Frida Fuzzing

### Frida Stalker
Expand Down Expand Up @@ -1576,7 +1649,8 @@ console.log(" - changeProtection(address, size, 'rwx')")
## References

- [Great Reversing Training](https://reversing.training/ )
- [https://www.briskinfosec.com/blogs/blogsdetail/Getting-Started-with-Frida](https://www.briskinfosec.com/blogs/blogsdetail/Getting-Started-with-Frida)
- [Getting Started with Frida](https://www.briskinfosec.com/blogs/blogsdetail/Getting-Started-with-Frida)
- [Bypassing iOS Frida detection with LLDB and Frida](https://tonygo.tech/blog/2025/8ksec-ios-ctf-writeup)


{{#include ../../banners/hacktricks-training.md}}
Expand Down