You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/mobile-pentesting/ios-pentesting/frida-configuration-in-ios.md
+75-1Lines changed: 75 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -358,6 +358,79 @@ if (ObjC.available) {
358
358
}
359
359
```
360
360
361
+
## LLDB-Assisted Frida Detection Bypass & Swift Hooking
362
+
363
+
### Remote debugging pipeline
364
+
365
+
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:
366
+
367
+
1. Forward SSH so the jailbroken phone is reachable even without Wi-Fi: `iproxy 2222 22 &` followed by `ssh root@localhost -p 2222`.
368
+
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.
369
+
3. Forward the debugging port and attach LLDB from macOS:
370
+
371
+
```bash
372
+
iproxy 1234 5678 &
373
+
lldb
374
+
(lldb) process connect connect://localhost:1234
375
+
```
376
+
377
+
4. Use `finish` a few times so constructors return and LLDB can resolve every Swift/ObjC image before you start patching symbols.
378
+
379
+
Keeping `frida-server` running in parallel now becomes viable even if the app performs anti-instrumentation checks during startup.
380
+
381
+
### Patching Swift jailbreak / Frida checks
382
+
383
+
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:
(lldb) breakpoint set --name 'FridaInTheMiddle.systemSanityCheck'
389
+
(lldb) c
390
+
(lldb) finish
391
+
(lldb) register write x0 0
392
+
(lldb) c
393
+
```
394
+
395
+
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.
396
+
397
+
### Discovering Swift targets for Frida
398
+
399
+
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:
400
+
401
+
```bash
402
+
frida-trace -U <BundleName> -i "*dummy*"
403
+
```
404
+
405
+
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.
406
+
407
+
### Hooking Swift `String` arguments
408
+
409
+
Understanding the Swift ABI is essential to rebuild high-level arguments from registers when you intercept pure Swift functions:
410
+
411
+
-**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`.
412
+
-**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`.
413
+
414
+
A single hook can extract both cases without reverse engineering the app’s source:
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.
0 commit comments