# iOS RE Cheatsheet

> ARM64 · Swift · ObjC · Frida · IDA Pro · SSL Pinning · Jailbreak Detection · Static & Dynamic Analysis

***

## 1. Toolchain Setup

### Static Analysis

| Tool             | Description                                     |
| ---------------- | ----------------------------------------------- |
| `IDA Pro`        | Primary disassembler + decompiler (Hex-Rays)    |
| `Ghidra`         | Free alternative, good Swift support via plugin |
| `Hopper`         | Lightweight, fast ObjC analysis on macOS        |
| `class-dump`     | ObjC header reconstruction from binary          |
| `dsdump`         | Swift + ObjC metadata dump, more detailed       |
| `jtool2`         | Mach-O swiss-army knife, better than otool      |
| `nm` / `strings` | Symbol listing, string extraction               |

### Dynamic Analysis

| Tool          | Description                                |
| ------------- | ------------------------------------------ |
| `Frida`       | Runtime instrumentation, hook injection    |
| `Objection`   | Frida-based toolkit, SSL bypass, mem dump  |
| `lldb`        | On-device debugger via Xcode / debugserver |
| `frida-trace` | Auto-trace ObjC methods & C functions      |
| `r2frida`     | radare2 + Frida combined analysis          |
| `Burp Suite`  | HTTP/S proxy for traffic interception      |
| `mitmproxy`   | Lightweight proxy, scriptable              |

### Utility / Support

| Tool                   | Description                                  |
| ---------------------- | -------------------------------------------- |
| `ipsw`                 | Download & extract iOS firmware, DYLD cache  |
| `ldid`                 | Sign binaries for sideloading / testing      |
| `frida-ios-dump`       | Decrypt & dump App Store IPAs                |
| `bfdecrypt`            | Inline decryption via Cydia tweak            |
| `Filza / iFile`        | On-device filesystem browser                 |
| `otool`                | Object file displaying tool (built-in macOS) |
| `xcrun swift-demangle` | Demangle Swift mangled symbol names          |

***

## 2. First Recon — Before Opening IDA

### Shell Commands

```bash
# Check encryption
otool -l Binary | grep -A4 LC_ENCRYPT

# Linked frameworks
otool -L Binary
jtool2 -L Binary

# Architecture & flags
otool -hv Binary
file Binary

# Mach-O sections
otool -l Binary | grep -E "sectname|segname|size|offset"

# String extraction
strings -a Binary | grep -iE "http|api|key|token|secret|jwt"
strings -a Binary | grep -E "^[A-Za-z0-9+/]{20,}={0,2}$"  # base64 candidates

# Exported symbols
nm -U Binary | grep " T "    # defined text symbols
nm -u Binary                 # undefined (imports)

# Swift demangle
xcrun swift-demangle _'$s3App12NetworkClientC11fetchToken...'
nm Binary | xcrun swift-demangle
```

### class-dump / dsdump

```bash
# ObjC header dump
class-dump -H Binary -o ./headers/

# Swift metadata (more detailed)
dsdump --swift Binary
dsdump --swift --verbose Binary
dsdump --objc Binary

# Filter interesting classes
dsdump --swift Binary | grep -iE \
  "Manager|Service|Client|Handler|Auth|Token|Crypto|Pin|Network|Session"

# jtool2 ObjC metadata
jtool2 -d objc Binary
jtool2 --analyze Binary     # full analysis

# Priority targets to find:
# *Manager  *Service  *Client  *Handler  *Provider
# *Auth     *Token    *Session *Crypto   *Pin
# *Network  *Request  *Interceptor       *Certificate
```

### Decryption — App Store IPAs

```bash
# Method 1 — frida-ios-dump (USB device)
frida-ios-dump -u mobile -H 127.0.0.1:2222 com.target.app

# Method 2 — bfdecrypt (Cydia tweak, install on device)
# Tap app → decrypted IPA in /var/mobile/Documents/

# Method 3 — Bagbak
bagbak --host 127.0.0.1:2222 com.target.app

# Verify decryption worked
otool -l DecryptedBinary | grep -A4 cryptid
# cryptid 0 → decrypted ✓
# cryptid 1 → still encrypted ✗

# Extract from DYLD shared cache (iOS system frameworks)
ipsw dyld extract dyld_shared_cache UIKit
```

### DYLD Cache & Imports

```bash
# Key imports → what security features the app uses
otool -L Binary | grep -iE \
  "Security|CommonCrypto|LocalAuth|CFNetwork|sqlite"

# Security.framework  → Keychain, cert pinning, SecTrust
# CommonCrypto        → AES/SHA/HMAC/RSA (CC_SHA256 etc.)
# CFNetwork/NSURLSession → networking stack
# LocalAuthentication → Touch/Face ID
# libsqlite3          → local database (may store tokens)

# List all C imports
nm -u Binary | grep -E "^.*U _" | sed 's/.* _//' | sort

# Check for interesting C functions directly
nm -u Binary | grep -E \
  "CC_SHA|CCCrypt|SecItem|SecTrust|SSL_|fork|ptrace|sysctl"
```

***

## 3. ARM64 Quick Reference

### Calling Convention

| Register(s) | Role                                             |
| ----------- | ------------------------------------------------ |
| `x0–x7`     | Function arguments (in order) / return values    |
| `x0–x1`     | Return values (Swift String = x0 low + x1 flags) |
| `x8`        | **sret pointer** — indirect struct return buffer |
| `x9–x15`    | Scratch / caller-saved (can be clobbered)        |
| `x16–x17`   | Intra-procedure-call temporaries (IPC)           |
| `x18`       | Platform reserved (iOS: thread-local)            |
| `x19–x28`   | Callee-saved — preserved across calls            |
| `x29 (fp)`  | Frame pointer                                    |
| `x30 (lr)`  | Link register — return address                   |
| `sp`        | Stack pointer (16-byte aligned)                  |

### Key Instructions

```asm
; Calls
BL   label          ; call (Branch + Link)
BLR  X8             ; indirect call (vtable dispatch)
RET                 ; return (branch to x30)

; Conditional branches
B.EQ / B.NE         ; equal / not equal (zero flag)
B.LT / B.GT         ; less / greater than (signed)
B.LO / B.HI         ; lower / higher (unsigned)
CBZ  X0, label      ; branch if X0 == 0
CBNZ X0, label      ; branch if X0 != 0
TBZ  W0, #0, label  ; test bit 0, branch if zero  ← Bool check
TBNZ W0, #0, label  ; test bit 0, branch if non-zero

; Load / Store
LDR  X1, [X0, #16]  ; load 64-bit from X0+16
LDP  X1, X2, [X0]   ; load pair (efficient struct read)
STR  X1, [X0, #24]  ; store 64-bit to X0+24
STP  X1, X2, [SP,#-16]! ; push pair to stack

; Address loading (typical IDA pattern for strings/data)
ADRP X0, page           ; load page address (4KB aligned)
ADD  X0, X0, :lo12:sym  ; add page offset
LDR  X0, [X0, :lo12:ptr]; indirect (pointer to data)
```

### sret — Struct Return (Critical for Swift)

```asm
; When a function returns a struct > 16 bytes:
; → caller allocates buffer on stack
; → passes pointer in X8 BEFORE the call
; → callee writes result to *X8
; → x0 may be unrelated (or the sret ptr itself)

; IDA signature of sret function:
; __int64 __usercall func@<X0>(__int64 x8_0@<X8>, ...)
```

```javascript
// In Frida — WRONG (crashes):
Interceptor.attach(addr, {
  onEnter(args) { args[0] // ← this is sret pointer, NOT arg1! }
})

// In Frida — CORRECT:
Interceptor.attach(addr, {
  onEnter(args) {
    this.sret = this.context.x8  // ← capture sret ptr
    this.arg0 = args[0]           // ← first real argument
  },
  onLeave(retval) {
    const field = this.sret.add(0x10).readU8()
  }
})
```

### Common Patterns in IDA

```asm
; NULL check (Optional unwrap)
CBZ  X0, nil_path    ; → guard let / if let

; Bool return — only bit 0 matters
AND  W0, W0, #1      ; mask Bool
TBZ  W0, #0, false_path

; Swift enum discriminant
LDRB W1, [X0, #last_byte]  ; read tag byte
CMP  W1, #0                 ; 0 = first case
CMP  W1, #1                 ; 1 = second case

; vtable dispatch (Swift class method)
LDR  X8, [X0]         ; load vtable pointer from object
LDR  X9, [X8, #0x40]  ; load method from vtable+0x40
BLR  X9               ; call method

; Swift object layout
; [+0x00] isa / metadata pointer
; [+0x08] reference count
; [+0x10] first stored property
```

***

## 4. Swift Internals — IDA Patterns

### Swift String Encoding in Registers

| `x1` top bits  | Type                      | `x0` content                     |
| -------------- | ------------------------- | -------------------------------- |
| `0xE0…0xEF`    | Small inline string       | ASCII bytes packed in x0+x1      |
| `0x8000 0001…` | Large heap String         | Pointer to Swift \_StringStorage |
| `0xF000…`      | Foreign (NSString bridge) | Pointer to NSString object       |
| `x1>>62 == 2`  | Data heap large           | Pointer to `__DataStorage`       |
| `x1>>62 == 1`  | Data medium               | Encoded inline                   |
| `x1>>62 == 0`  | Data inline/small         | `BYTE6(x1)` = length             |

```javascript
// Decode small inline Swift String (Frida)
function swiftSmolStr(lo, hi) {
  let s = '';
  for (let i = 0; i < 8; i++) {
    const c = lo.shr(i*8).and(0xFF).toUInt32();
    if (c > 0x1F && c < 0x80) s += String.fromCharCode(c);
  }
  for (let i = 0; i < 6; i++) {
    const c = hi.shr(i*8).and(0xFF).toUInt32();
    if (c > 0x1F && c < 0xE0) s += String.fromCharCode(c);
  }
  return s;
}
```

### Skip-Pattern Recognition

These are always boilerplate — **skip immediately** without further analysis:

```c
// 1. Lazy type metadata accessor → Swift_lazyTypeMetadataAccessor → SKIP
result = *a1;
if (!result) {
  result = swift_getTypeByMangledNameInContext(...);
  *a1 = result;
}
return result;

// 2. Lazy witness table accessor → Swift_lazyWitnessTableAccessor → SKIP
result = qword_XXXX;
if (!qword_XXXX) {
  result = swift_getWitnessTable(...);
  atomic_store(result, &qword_XXXX);
}

// 3. swift_once initialiser → Swift_once_* → SKIP body
if (qword_XXXX != -1)
  swift_once(&qword_XXXX, sub_YYYY);
return &qword_ZZZZ;

// 4. CoW array reallocator → Swift_Array_*_reallocateBuffer → SKIP
if ((a3 & 1) != 0) { /* grow */ }
swift_allocObject(...)
memmove(...)

// 5. ARC dispatch → Swift_arcRetain/ReleaseTaggedOrHeap → SKIP
if (a2 >> 62 != 1) {
  if (a2 >> 62 != 2) return;
  swift_release(a2 & 0x3FFF...);
}
```

### Function Size Heuristic

| Size          | Likely type                                 | Action     |
| ------------- | ------------------------------------------- | ---------- |
| `< 0x20`      | ARC helper / metadata thunk / getter        | **Skip**   |
| `0x20–0x60`   | CoW helper / Data wrapper / witness init    | **Skip**   |
| `0x60–0x100`  | String/Data utility, possible crypto helper | Quick scan |
| `0x100–0x400` | Real logic — check functions, parsers       | Analyze    |
| `> 0x400`     | Core logic, orchestrators, complex checks   | Deep dive  |

**First call in function body:**

| First call                    | Action               |
| ----------------------------- | -------------------- |
| `swift_getTypeByMangledName…` | **Skip**             |
| `swift_getWitnessTable`       | **Skip**             |
| `swift_once`                  | **Skip body**        |
| `swift_allocObject`           | Note type, continue  |
| `CC_SHA256` / `CCCrypt`       | **Priority analyze** |
| `_dyld_*` / `sysctl`          | **Security check**   |
| `objc_msgSend`                | Read selector        |

### Swift Memory Layouts

```
// Protocol value on stack (existential container) — 40 bytes
[+0x00] value word 0    // inline if ≤ 3 words, else heap ptr
[+0x08] value word 1
[+0x10] value word 2
[+0x18] type metadata   // pointer to TypeMetadata
[+0x20] witness table   // pointer to protocol conformance

// Swift Optional<T> (pointer-sized T):
//   .none  → 0 (nil)
//   .some  → non-zero value
// Check: CBZ X0, nil_branch

// Swift Array buffer layout
[+0x00] isa / refcount
[+0x10] count (Int)
[+0x18] capacity×2 (encoded)
[+0x20] elements start here   // buf + 32

// Swift Dictionary bucket layout
// Bitmap at buf+64: 1 bit per bucket (occupied flag)
// Keys array at metadata[+48]: [String] pairs
// Values array at metadata[+56]: [Value] pairs
```

***

## 5. ObjC Runtime Patterns

### `objc_msgSend` Patterns

```c
// Register assignment:
// x0 = receiver (self or class)
// x1 = SEL (selector — IDA shows as string)
// x2, x3, ... = arguments

// [NSURLSession sharedSession]
cls     = objc_opt_self(&OBJC_CLASS___NSURLSession);
session = objc_msgSend(cls, "sharedSession");

// [[MyClass alloc] initWithString:]
obj    = objc_allocWithZone(&OBJC_CLASS___MyClass);
result = objc_msgSend(obj, "initWithString:", str);

// Retain/release — skip these in analysis
objc_retain(x)
objc_release(x)
objc_retainAutoreleasedReturnValue(x)   // always after msgSend

// Static / class method
cls    = objc_opt_self(&OBJC_CLASS___NSBundle);
bundle = objc_msgSend(cls, "mainBundle");   // +mainBundle

// When IDA doesn't show the selector:
// Look at x1 register → reference to __TEXT.__objc_methnames
// Or: Search → Immediate value → address of selector
```

### Key ObjC Classes & Selectors

| Class / Selector                      | Security Relevance                             |
| ------------------------------------- | ---------------------------------------------- |
| `NSURLSession -dataTaskWithRequest:`  | HTTP requests — hook for traffic interception  |
| `NSURLSession -didReceiveChallenge:…` | SSL auth challenge — pinning bypass target     |
| `SecItemCopyMatching`                 | Keychain read — dump credentials               |
| `SecItemAdd`                          | Keychain write — trace stored secrets          |
| `SecTrustEvaluate / …WithError:`      | Certificate validation — pinning               |
| `NSBundle -pathForResource:ofType:`   | Reads embedded resources (plist, cert, config) |
| `NSFileManager -fileExistsAtPath:`    | Jailbreak filesystem checks                    |
| `UIDevice -systemVersion`             | OS version checks                              |
| `NSUserDefaults -objectForKey:`       | Persistent config / flags storage              |
| `FIRCrashlytics -recordError:`        | Security event telemetry reporting             |

***

## 6. Frida — Essential Scripts

### CLI — Device Setup

```bash
# List running processes
frida-ps -Uia           # USB, installed apps
frida-ps -H 127.0.0.1   # SSH tunnel

# Attach REPL
frida -U com.target.app
frida -U -f com.target.app --no-pause   # spawn + attach

# Auto-trace ObjC methods
frida-trace -U -f com.target.app \
  -m "*[NSURLSession *]" \
  -m "*[*Auth* *]" \
  -m "-[*ViewController *]"

# Trace by RVA (Swift functions)
frida-trace -U com.target.app \
  -a "FrameworkName!0x1234"

# Objection quick actions
objection -g com.target.app explore
  ios sslpinning disable
  ios keychain dump
  ios jailbreak simulate
  memory list modules
  ios hooking list classes
  ios hooking watch class NSURLSession
```

### Hook Template — Universal

```javascript
const base  = Module.getBaseAddress('TargetFramework');
const slide = base.sub(ptr('0x100000000'));

function hook(rva, name, enter, leave) {
  Interceptor.attach(ptr(rva).add(slide), {
    onEnter(args) {
      this.name = name;
      if (enter) enter.call(this, args);
    },
    onLeave(retval) {
      if (leave) leave.call(this, retval);
    }
  });
}

// Hook ObjC method
const cls = ObjC.classes.NSURLRequest;
Interceptor.attach(cls['- URL'].implementation, {
  onEnter(args) {
    console.log('[HTTP]', ObjC.Object(args[0]).URL().absoluteString());
  }
});

// Replace ObjC method return value
const orig = ObjC.classes.MyClass['- isJailbroken'].implementation;
Interceptor.replace(orig, new NativeCallback(function(self, sel) {
  return 0;  // force false
}, 'bool', ['pointer', 'pointer']));
```

### Runtime Introspection

```javascript
// Find all instances of a class at runtime
ObjC.choose(ObjC.classes.MyClass, {
  onMatch(obj) { console.log('found:', obj); },
  onComplete()  { console.log('done'); }
});

// Hook all methods of a class
const cls = ObjC.classes.NSURLSession;
for (const m of cls.$ownMethods) {
  Interceptor.attach(cls[m].implementation, {
    onEnter() { console.log(`[NSURLSession] ${m}`); }
  });
}

// Memory dump at address
console.log(hexdump(ptr('0x...'), {
  length: 64, header: true, ansi: true
}));

// List loaded modules + base addresses
Process.enumerateModules()
  .filter(m => m.name.includes('target'))
  .forEach(m => console.log(m.name, m.base, m.size));

// Read Swift String from memory (large heap)
function readSwiftString(ptr) {
  const len = ptr.add(0x10).readU64();
  return ptr.add(0x20).readUtf8String(Number(len));
}
```

### Keychain & CommonCrypto Hooks

```javascript
// Keychain read intercept
const SecItemCopyMatching = Module.findExportByName(
  'Security', 'SecItemCopyMatching');
Interceptor.attach(SecItemCopyMatching, {
  onEnter(args) { this.result = args[1]; },
  onLeave(retval) {
    if (retval.toInt32() === 0) {
      const item = this.result.readPointer();
      console.log('[Keychain]', ObjC.Object(item).toString());
    }
  }
});

// CC_SHA256 — log every hash input/output
const CC_SHA256 = Module.findExportByName(null, 'CC_SHA256');
Interceptor.attach(CC_SHA256, {
  onEnter(args) {
    const data = args[0];
    const len  = args[1].toUInt32();
    console.log('[SHA256 input]', hexdump(data, { length: len }));
  },
  onLeave(retval) {
    console.log('[SHA256 digest]', retval.readByteArray(32));
  }
});
```

***

## 7. SSL Pinning Bypass

### Bypass Levels — Try in Order

| Level | Method                                                    | Notes                                                    |
| ----- | --------------------------------------------------------- | -------------------------------------------------------- |
| **1** | `objection: ios sslpinning disable`                       | Patches common patterns automatically. Try first.        |
| **2** | SSL Kill Switch 2 (Cydia tweak)                           | System-wide hook on `SecTrustEvaluate`.                  |
| **3** | Hook `-URLSession:didReceiveChallenge:completionHandler:` | Force `NSURLSessionAuthChallengeUseCredential` with nil. |
| **4** | Hook `TSKSPKIHashCache` (TrustKit)                        | Return hash matching your proxy cert's SPKI.             |
| **5** | Hook `SecTrustEvaluateWithError` → force `true`           | Works for custom SecTrust implementations.               |
| **6** | Find embedded client cert via `SecPKCS12Import`           | Mutual TLS — cert embedded in `__DATA` or bundle.        |

### Bypass Code

```javascript
// SecTrustEvaluateWithError bypass
const SecTrust = Module.findExportByName(
  'Security', 'SecTrustEvaluateWithError');
Interceptor.replace(SecTrust, new NativeCallback(
  (trust, error) => { return 1; },  // always trusted
  'bool', ['pointer', 'pointer']
));

// NSURLSession delegate hook
const cls = ObjC.classes.YourAppDelegate;
const sel = 'URLSession:didReceiveChallenge:completionHandler:';
Interceptor.replace(cls['- '+sel].implementation,
  new NativeCallback(function(self, _sel, session, challenge, handler) {
    const disposition = 1; // NSURLSessionAuthChallengeUseCredential
    ObjC.Object(handler).call([disposition, NULL]);
  }, 'void', ['pointer','pointer','pointer','pointer','pointer'])
);
```

```bash
# Find embedded cert/key in binary
otool -l Binary | grep -A5 __DATA
# Look for suspiciously-sized sections in __DATA_CONST
# PKCS#12 header: 0x3082 (DER SEQUENCE)
# PEM: look for "CERTIFICATE" string
strings Binary | grep -E "BEGIN CERT|BEGIN RSA|BEGIN PRIV"
```

***

## 8. Jailbreak Detection — Bypass

### Detection Vectors

| Method                             | What to Spoof                                                         |
| ---------------------------------- | --------------------------------------------------------------------- |
| `stat` / `lstat` / `access`        | Return `ENOENT` for JB paths (`/bin/bash`, `/Applications/Cydia.app`) |
| `fopen` / `open`                   | Return `NULL`/`−1` for JB files                                       |
| `fork()`                           | Sandboxed apps can't fork → return `−1`                               |
| `ptrace(PT_DENY_ATTACH)`           | Hook ptrace → return `0` (allow debugger)                             |
| `sysctl(P_TRACED)`                 | Debugger presence → clear flag in returned struct                     |
| `dlopen(MobileSubstrate)`          | Return `NULL` for substrate/tweak libraries                           |
| `canOpenURL("cydia://")`           | Force return `NO`                                                     |
| `NSFileManager -fileExistsAtPath:` | Return `NO` for JB paths                                              |
| `vm_region_64`                     | Check `__DATA_CONST` writability → mask `VM_PROT_WRITE`               |
| `_dyld_image_count` / name         | Filter out Substrate/tweak dylibs from list                           |

### Universal Filesystem Bypass (Frida)

```javascript
const JB_PATHS = [
  '/Applications/Cydia.app', '/bin/bash',
  '/usr/sbin/sshd', '/etc/apt',
  '/private/var/lib/apt', '/var/lib/cydia',
  '/Library/MobileSubstrate', '/var/checkra1n',
  '/var/jb', '/bootstrap'
];

['stat', 'lstat', 'fopen', 'access', 'open'].forEach(sym => {
  const fn = Module.findExportByName(null, sym);
  if (!fn) return;
  Interceptor.attach(fn, {
    onEnter(args) {
      try { this.path = args[0].readUtf8String(); } catch(e) {}
    },
    onLeave(retval) {
      if (JB_PATHS.some(p => this.path?.includes(p)))
        retval.replace(ptr(-1));
    }
  });
});

// ptrace bypass
const ptrace = Module.findExportByName(null, 'ptrace');
Interceptor.replace(ptrace, new NativeCallback(
  () => 0, 'int', ['int','int','int','int']));

// sysctl debugger check bypass
// Clear P_TRACED flag (offset 32 in kinfo_proc, bit 0x800)
const sysctl = Module.findExportByName(null, 'sysctl');
Interceptor.attach(sysctl, {
  onLeave() {
    // Read & clear P_TRACED flag from returned kinfo_proc
  }
});
```

***

## 9. IDA Pro — Systematic Workflow

{% stepper %}
{% step %}

### Phase 1 — Orientation (30 min)

1. **Functions window** → sort by size DESC → largest = real logic, skip < 0x20 bytes
2. **Imports window** → identify security libraries: `Security.framework`, `CommonCrypto`, `CFNetwork`, `LocalAuthentication`, `sqlite3`
3. **Strings window** → filter: `https://`, `/api/`, `/v1/`, error messages, base64 patterns
4. **Search** → class names from `dsdump` output → jump directly to known interesting classes
5. **Segments** → check `__DATA.__const` and `__TEXT.__cstring` → embedded certs, keys, endpoints
   {% endstep %}

{% step %}

### Phase 2 — Function Analysis Flow

1. Check size → apply heuristic (`< 0x20` skip, `> 0x100` full analysis)
2. Check first call → `swift_getTypeByMangledName` → skip immediately
3. `xrefs_to` → caller context often explains purpose completely
4. `callgraph(depth=2)` → find `CC_SHA256`, `CCCrypt`, `_dyld_*`, `sysctl` in subtree
5. Rename locals immediately as you understand them (`v1→ptr_data`, `v2→len`)
6. `set_comments` at key addresses — document polarity, bypass points, data layout
   {% endstep %}
   {% endstepper %}

### IDA Shortcuts (macOS)

| Shortcut        | Action                                |
| --------------- | ------------------------------------- |
| `F5`            | Decompile current function (Hex-Rays) |
| `N`             | Rename symbol / variable              |
| `;`             | Add comment at cursor                 |
| `X`             | Cross-references TO current address   |
| `Ctrl+X`        | xrefs FROM current address            |
| `G`             | Go to address                         |
| `Alt+↑ / Alt+↓` | Navigate xref history                 |
| `Space`         | Toggle graph / linear view            |
| `Ctrl+F`        | Search text in current function       |
| `Alt+T`         | Search all text / strings             |
| `Ctrl+Alt+F`    | Search function names                 |
| `Tab`           | Switch between asm and pseudocode     |
| `Y`             | Change type of variable/function      |
| `H`             | Toggle hex display                    |

### Naming Conventions

| Prefix                    | Usage                                              |
| ------------------------- | -------------------------------------------------- |
| `ISS_Integrity_`          | Integrity check functions (SHA256, manifest)       |
| `ISS_Pipeline_`           | Security check orchestrators / dispatchers         |
| `ISS_Util_`               | Utility / support functions (base64, string parse) |
| `ISS_Crypto_`             | Cryptographic operations (AES, HMAC)               |
| `ISS_Thunk_`              | Thunks / stubs to real implementations             |
| `Swift_Array_`            | Generic array buffer helpers **(skip)**            |
| `Swift_Data_`             | Foundation Data helpers **(skip)**                 |
| `Swift_String_`           | String manipulation helpers **(skip)**             |
| `Swift_once_`             | Lazy initializers **(skip)**                       |
| `Swift_lazyType`          | Type metadata accessors **(skip)**                 |
| `Swift_arcRetain/Release` | ARC helpers **(skip)**                             |

***

## 10. Analysis Decision Tree

### Full Target — Where to Start

```
Got the binary
       │
       ├─ Encrypted? ──YES──▶ frida-ios-dump / bagbak ──▶ continue
       │
       ├─ strings ──▶ URLs/keys visible?
       │           ├── YES ──▶ static analysis first (IDA)
       │           └── NO  ──▶ dynamic analysis first (Frida trace)
       │
       ├─ class-dump / dsdump ──▶ meaningful class names?
       │           ├── YES ──▶ map to IDA, analyze those classes
       │           └── NO  ──▶ Frida trace → log all methods → map back to IDA
       │
       ├─ SSL pinning?
       │           └──▶ objection sslpinning disable
       │               ▶ Burp/mitmproxy ──▶ understand API ──▶ then map in IDA
       │
       └─ Security checks?
                   └──▶ Identify with Frida (log all returns)
                       ▶ IDA: analyze only flagged functions
                       ▶ Surgical bypass (not global hook)


For each suspicious function:

  size < 0x20?    ──YES──▶  SKIP
       │
       │ NO
       ▼
  first call = swift_getTypeByMangledName?  ──YES──▶  SKIP
       │
       │ NO
       ▼
  xrefs_to  ──▶  caller name tells you the purpose?  ──YES──▶  name it, done
       │
       │ NO
       ▼
  callgraph  ──▶  find CC_SHA256 / CCCrypt / _dyld_ / sysctl?
       ├── CC_SHA256  ──▶  integrity check
       ├── CCCrypt    ──▶  crypto/decryption
       ├── _dyld_*    ──▶  jailbreak / integrity
       ├── sysctl     ──▶  debugger detection
       ├── fork       ──▶  sandbox check
       └── none       ──▶  decompile and read carefully
```

### Priority Import Functions

| Function                    | Security Relevance           |
| --------------------------- | ---------------------------- |
| `CC_SHA256`                 | Integrity / certificate hash |
| `CCCrypt`                   | AES encrypt/decrypt          |
| `CCHmac`                    | HMAC signing                 |
| `SecItemCopyMatching`       | Keychain read                |
| `SecTrustEvaluateWithError` | Cert validation              |
| `ptrace`                    | Anti-debug                   |
| `sysctl`                    | Process flags / debugger     |
| `_dyld_get_image_name`      | Loaded dylib enumeration     |
| `vm_region_64`              | Memory protection check      |
| `fork` / `vfork`            | Sandbox detection            |

### Bypass Hook Priority

| Priority | Target                                           | Notes                                        |
| -------- | ------------------------------------------------ | -------------------------------------------- |
| **1**    | Result comparator (string equality)              | One hook kills all checks. Most surgical.    |
| **2**    | Orchestrator / scheduler function                | Return early before any check runs.          |
| **3**    | Individual check entry points                    | Per-check bypass. Handle polarity carefully. |
| **4**    | Low-level C functions (`stat`, `sysctl`, `fork`) | Coarse but reliable. Risk of side effects.   |

### Common Pitfalls

| Pitfall                                     | Explanation                                                                 |
| ------------------------------------------- | --------------------------------------------------------------------------- |
| **Inverting sret / first arg**              | `x8` = sret ptr. `args[0]` is NOT always the first argument in Swift.       |
| **Wrong polarity on check return**          | Some checks: `1=detected`, others: `1=clean`. Always verify before hooking. |
| **In-memory hash (not disk)**               | Patching binary on disk won't change the in-memory `__text` hash.           |
| **Result struct written before comparison** | Hook the struct init (sret), not just the final comparator.                 |
| **Unmapped checks causing crash**           | Full bypass mode needs ALL checks mapped first.                             |

***

*ARM64 · Swift · ObjC · Frida · IDA Pro*


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://notes.dado1513.dev/mobile-pentesting/ios-re-cheatsheet.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
