Code Signing & Entitlements
Code signing là cơ chế đảm bảo chỉ code được Apple (hoặc developer được Apple cấp certificate) tin tưởng mới được phép chạy trên iOS. Entitlements là hệ thống capability-based security gắn liền với code signature.
Tại Sao Quan Trọng
- Jailbreak phải bypass code signing để chạy unsigned code
- Entitlements quyết định quyền hạn — nhiều exploit chains cần entitlement manipulation
- Trust Cache injection là bước thiết yếu trong modern jailbreaks
- TrollStore hoạt động nhờ CoreTrust bypass — hiểu cơ chế = hiểu bug
Kiến Trúc Code Signing Trên iOS
Tầng 1: AMFI (AppleMobileFileIntegrity)
AMFI là kernel extension (kext) kiểm tra code signature trước khi cho phép:
- Mỗi page của code khi được load vào memory đều được verify hash
- Process
amfid(userspace daemon) hỗ trợ AMFI cho các checks phức tạp - AMFI quyết định: binary này có được phép chạy không, với entitlements nào
Flow kiểm tra:
exec() system call
└─→ XNU kernel calls AMFI
├─→ Check Trust Cache (kernel-loaded list of trusted cd_hashes)
│ └─→ Found? → ALLOW (no further checks needed)
│
├─→ Send to amfid (userspace) for full validation
│ ├─→ Verify certificate chain (up to Apple Root CA)
│ ├─→ Verify CMS signature
│ ├─→ Verify Code Directory hashes
│ └─→ Return result to kernel
│
└─→ Decision: allow/deny execution + which entitlements to grant
Tầng 2: CoreTrust (iOS 12+)
CoreTrust là kernel extension thực hiện certificate validation trong kernel, thay vì phụ thuộc amfid:
- Chạy trong KTRR-protected memory → khó patch hơn
- Validate certificate chain cho App Store apps
- Nếu CoreTrust approve → binary chạy với entitlements không bị filter
Tại sao Apple thêm CoreTrust:
- Trước iOS 12: amfid chạy ở userspace → jailbreaks hook amfid để bypass code signing
- CoreTrust đưa validation vào kernel → không thể hook từ userspace
Tầng 3: TXM (iOS 17+, A15+)
Trusted Execution Monitor thay thế cả AMFI và CoreTrust:
- Chạy tại EL2 (hypervisor level) — cao hơn kernel
- Kernel exploit alone không đủ để bypass TXM
Code Directory & cd_hash
Code Directory
struct CodeDirectory {
uint32_t magic; // CSMAGIC_CODEDIRECTORY (0xFADE0C02)
uint32_t length;
uint32_t version;
uint32_t flags;
uint32_t hashOffset; // Offset to hash array
uint32_t identOffset; // Offset to identifier string
uint32_t nSpecialSlots; // Number of special slots (before hash array)
uint32_t nCodeSlots; // Number of code page hashes
uint64_t codeLimit; // Limit of code pages
uint8_t hashSize; // Hash output size (20 for SHA-1, 32 for SHA-256)
uint8_t hashType; // Hash algorithm
uint8_t platform; // Platform identifier
uint8_t pageSize; // log2(page size in bytes), usually 12 (4KB) or 14 (16KB)
// ... followed by hash slots
};
cd_hash = hash của Code Directory itself. Đây là unique identifier cho mỗi signed binary.
Special Slots:
| Slot | Nội dung |
|---|---|
| -1 | Info.plist hash |
| -2 | Requirements hash |
| -3 | Resource Directory hash |
| -4 | Application Specific (unused) |
| -5 | Entitlements hash |
| -6 | DER Entitlements hash |
| -7 | Launch Constraints hash |
Code Slots: Hash của mỗi page (thường 16KB trên iOS) của binary code. Khi page được loaded vào memory, AMFI verify hash này.
Entitlements
Entitlements là XML/DER plist embedded trong code signature, quy định capabilities:
Entitlements Quan Trọng
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN">
<plist version="1.0">
<dict>
<!-- Cho phép debug (get-task-allow → tfp) -->
<key>get-task-allow</key>
<true/>
<!-- Chạy không bị sandbox -->
<key>com.apple.private.security.no-sandbox</key>
<true/>
<!-- Platform binary status (Apple binaries) -->
<key>platform-application</key>
<true/>
<!-- Task-for-pid — đọc/ghi memory process khác -->
<key>task_for_pid-allow</key>
<true/>
<!-- Root access -->
<key>com.apple.private.persona-mgmt</key>
<true/>
<!-- Keychain access groups -->
<key>keychain-access-groups</key>
<array>
<string>com.apple.token</string>
</array>
<!-- Sandbox container -->
<key>com.apple.security.app-sandbox</key>
<true/>
<!-- Mach port lookup permissions -->
<key>com.apple.security.exception.mach-lookup.global-name</key>
<array>
<string>com.apple.backboardd</string>
</array>
</dict>
</plist>
Phân Loại Entitlements
| Loại | Ví dụ | Ai được phép |
|---|---|---|
| Public | com.apple.security.app-sandbox |
Mọi developer |
| Private | com.apple.private.security.* |
Chỉ Apple binaries |
| Restricted | task_for_pid-allow |
Chỉ platform binaries có đúng profile |
| Managed | com.apple.developer.kernel.* |
Cần Apple approval |
Platform binaries = binaries signed bởi Apple với Apple-internal certificate. Chúng có thể dùng private entitlements mà third-party apps không thể.
Trust Cache
Trust Cache là danh sách cd_hashes được tín nhiệm tự động bởi AMFI, không cần full certificate validation.
Các Loại Trust Cache
- Static Trust Cache: Embedded trong firmware, chứa hashes của tất cả system binaries
- Loadable Trust Cache: Có thể load thêm tại runtime (cần entitlement đặc biệt)
- Engineering Trust Cache: Cho development/debug builds
Trust Cache Structure
struct trust_cache_entry_v2 {
uint8_t cd_hash[20]; // SHA-1 cd_hash
uint8_t hash_type; // 1 = SHA-1, 2 = SHA-256
uint8_t flags;
uint16_t constraint_category;
};
struct trust_cache_v2 {
uint32_t version; // 2
uuid_t uuid;
uint32_t entry_count;
struct trust_cache_entry_v2 entries[]; // sorted for binary search
};
Trust Cache Injection (Jailbreak technique)
Modern jailbreaks inject trust cache entries để AMFI trust unsigned binaries:
- Gain kernel read/write
- Tìm
loadedTrustCacheslinked list trong kernel - Allocate kernel memory cho new trust cache
- Thêm cd_hashes của jailbreak binaries
- Link vào
loadedTrustCaches
Bypass Techniques Đã Biết
1. amfid Hook (Pre-iOS 12)
- Jailbreak inject code vào amfid process
- Hook hàm validation → luôn return “valid”
- CoreTrust khắc phục bằng cách đưa validation vào kernel
2. TOCTOU Attack
- Thay đổi cd_hash khi AMFI đang evaluate nhưng chưa xong
- Race condition giữa “check hash” và “use hash”
3. CoreTrust Multiple Signer Bug (TrollStore)
- Binary có nhiều signers
- CoreTrust evaluate signer cuối nhưng apply policy từ signer đầu
- Cho phép self-signed binary có App Store policy flags
- Đây là cơ sở cho TrollStore — permanently install bất kỳ IPA nào
4. CoreTrust Root Certificate Bug
- Craft certificate chain trick CoreTrust chấp nhận custom root CA
- Cho phép sign binary với bất kỳ entitlements nào
5. Trust Cache Injection (Runtime)
- Sau khi có kernel r/w, inject entries vào loaded trust caches
- Binary với matching cd_hash sẽ bypass mọi signature checks
Thực Hành
# Extract entitlements từ system binary
codesign -d --entitlements :- /usr/libexec/mobileassetd
# Xem code signature details
codesign -dvvv /usr/bin/ls
# Trên jailbroken device, dump trust cache
# (cần kernel r/w tool)
# Dùng jtool2
jtool2 --ent /path/to/binary
jtool2 --sig /path/to/binary
Tài Nguyên
- Apple — Security of Runtime Process
- Dynastic Research — CoreTrust Overview
- Dynastic Research — Bypassing Codesigning
- Alfie CG — Getting Untethered Code Execution
- TrollStore — How it works
- Apple
<Security/SecCode.h>and<security/codesign.h>headers