When to use / when not to use
- Use: macOS native/closed-source applications (.app/.dylib/.framework), targets with signing notarization and sandboxing, Keychain/Secure Enclave hardware key scenarios
- Use: authorization/distribution state determination—who the signer, notarization, hardened runtime, and Team ID are (distribution surface/trust surface analysis)
- Use: trust chain issues—Dylib Hijacking, injection surface, TCC dependencies (which privacy capabilities are requested/used)
- Do not use: iOS applications (switch to [[re-ios]]); pure Mach-O format parsing (switch to [[re-format-macho]])
- Do not use: Linux/Windows targets (go to [[re-gdb]] / [[re-x64dbg]] respectively)
- Do not use: when you only want to capture network traffic/file behavior (when there is no macOS-specific surface, go through the [[re-behavior]] / [[re-netcap]] generic path)
- Note: TCC and Keychain data fall within the scope of system privacy; analyze read-only and do not export contents (red line)
Tool preparation
codesign / spctl / otool / lipo (signing and Mach-O tools, built into macOS)
- macOS: built into the system (Xcode command line tools
xcode-select --install) - Linux: can statically analyze Mach-O (
llvm-otool,brew install llvmor the distribution's llvm package), signature parsing is limited - Verify:
codesign --version、macOS:otool --version;Linux:llvm-otool --version
plutil / xattr (Info.plist and quarantine inspection, built into macOS)
- Verify:
plutil -help、xattr -h - Purpose: Info.plist key parsing (
plutil -p);com.apple.quarantineextended attributes determine whether Gatekeeper blocks
Hopper / IDA / Ghidra (decompilation base)
- For installation and verification see [[re-ida]] / [[re-ghidra]]
lldb (dynamic debugging)
- For installation and verification see [[re-lldb]]; handle PT_DENY_ATTACH before attach (step 6)
Operation steps
Execute in order, archive each step's artifacts (path + sha256, see [[re-triage]]). Record signing/entitlements information according to the [[re-analyze/analysis-contract]] contract.
-
Bundle structure and signature inspection:
file Sample.app/Contents/MacOS/Sample codesign -dv Sample.app 2>&1 | head # 签名者/Team ID(要求需 `-d -r-` 查看) spctl -a -vv Sample.app 2>&1 # 公证状态(Gatekeeper) defaults read Sample.app/Contents/Info.plist # Info.plist 关键键- Focus on: signer (Apple developer/distribution certificate), Team ID, CDHash, Hardened Runtime (runtime flag), Info.plist's CFBundleIdentifier/version/minimum system version
- Architecture confirmation:
fileoutput/x86_64 and arm64 universal binary (lipo -archs)—determines decompilation and dynamic environment (arm64e on Apple Silicon has PAC differences, see [[gotchas]]) - Notarization-derived check:
spctl -apassing does not guarantee a local staple—xcrun stapler validate Sample.appcheck whether the ticket accompanies the bundle - Quarantine attribute inspection:
xattr -l Sample.applook atcom.apple.quarantine(quarantine flag + timestamp + responsible app;does not contain the source URL—source information is in Spotlight attributes, usemdls -name kMDItemWhereFroms Sample.appto check)
-
entitlements and sandbox:
codesign -d --entitlements :- Sample.app 2>&1 | head -30- Key key groups:
com.apple.security.app-sandbox(sandbox master switch),network.client/server(network),files.user-selected.*(user-selected files),device.camera/microphone(device),application-groups(group sharing),cs.allow-dyld-environment-variables/cs.disable-library-validation(injection surface),get-task-allow(debug entitlement, should not be present in release builds) - The sandbox profile determines the capability boundary—when analyzing authorization logic and attack surface, look at the entitlements list first, then cross-validate with dynamic behavior
- Anomalous signals: release build carrying
get-task-allow(should only be used for development debugging) or privilege-escalation combinations (e.g., no UI but enablingdevice.camera)—record as suspicious items into the conclusion
- Key key groups:
-
TCC permission database:
# 用户级 TCC 库(授权记录) ls ~/Library/Application\ Support/com.apple.TCC/ # 系统级 TCC 库 ls /Library/Application\ Support/com.apple.TCC/- Pre-check: TCC.db itself is protected by TCC—reading it without Full Disk Access will fail with a permission error, so confirm authorization before reading
- TCC.db (SQLite) records each App's authorization for privacy resources; analyze the target's dependency on TCC (what permissions were requested, when they were requested, failure paths)
- Note: TCC data is system privacy data; read-only analysis only, do not export contents (red line)
-
Keychain and Secure Enclave:
- Keychain item types (generic password/internet password/key) and access conditions—
kSecAttrAccessibleisaccessibility(what state the device must be in for it to be readable: unlocked/after first unlock/this device only),not ACL; access control iskSecAttrAccessControl/SecAccessControl(biometric/passcode gate); macOS traditional ACL additionally hasSecAccess/kSecAttrAccess(see [[gotchas]]) - Secure Enclave keys: generated on-device using
SecKeyCreateRandomKey(with attributekSecAttrTokenID: kSecAttrTokenIDSecureEnclave)—SecKeyCreateWithDatais import/restore from external key data; the SE private key never leaves the chip and cannot be imported, so do not treat it as an SE generation API; the private keyis non-extractable(equivalent to Android Keystore hardware backing, see [[re-android-native]] Keystore audit) - Analysis: which keychain items the target reads (SecItemCopyMatching call sites), whether keys are Secure Enclave bound (non-extractable → record purpose and access conditions rather than looking for bytes)
- Keychain item types (generic password/internet password/key) and access conditions—
-
dyld load chain:
otool -L Sample.app/Contents/MacOS/Sample | head # LC_LOAD_DYLIB 依赖 otool -l Sample.app/Contents/MacOS/Sample | grep -A4 LC_RPATH- Dependency list and RPATH → Dylib Hijacking surface (writable directory + missing dependency combination)
- Injection surface: DYLD_INSERT_LIBRARIES is restricted by hardened runtime—entitlements without
cs.allow-dyld-environment-variablesit does not take effect; under system integrity protection, injection into system paths is ineffective - Injection verification: environment variable + trial run in sandbox
DYLD_INSERT_LIBRARIES=/path/to/hook.dylib ./Sample; if ineffective, return to the static path ([[re-ghidra]]), do not force injection
-
Anti-debugging and protection:
- Debugger detection:
PT_DENY_ATTACH(ptrace request returns deny on attach)—first statically locate the ptrace call site ([[re-ghidra]] / [[re-ida]]), patch or bypass before attaching - Signature verification:
SecStaticCodeCheckValidity/SecRequirementCheckcall sites—typical points that trigger verification failure when signature is changed or injection occurs; locate them point by point (pitfall 1) - Countermeasure surface record: code signature verification, debugger detection, anti-injection (DYLD_INSERT_LIBRARIES check)—the respective call sites and trigger conditions for each of the three categories
- Debugger detection:
-
Evidence verification (wrap-up): originals of signer/Team ID/entitlements, TCC dependency points, keychain item purposes, dyld dependency list—file them per [[re-analyze/analysis-contract]]; compare dynamic conclusions against static lists (capability boundary is based on dynamic behavior, see [[decision-tree]])
Cross-domain combination
- [[re-format-macho]]: Mach-O format foundation (LC_* parsing)
- [[re-ios]]: iOS-side complement (jailbreak ecosystem and entitlements differences)
- [[re-lldb]]: dynamic debugging
- [[re-frida]]: dynamic instrumentation (macOS desktop support)
- [[re-sandbox]] / [[re-analyze/platform-tips]]: dynamic execution isolation (signature/behavior observation performed within the sandbox)
- [[re-analyze/analysis-contract]]: signature/entitlements information passed according to the data contract
- [[re-patching]]: persistent handling of PT_DENY_ATTACH and signature verification points
- Swift layer analysis (mangling/witness table) → [[re-swift]]
Common pitfalls and traps
- Signature verification triggered at multiple points: Symptom—exits immediately when run after patching; Cause—multiple verification points at load/run/update; Countermeasure—locate point by point (step 6), handle verification points first, then proceed to logic
- Secure Enclave keys are not extractable: Symptom—private key cannot be found in memory; Cause—hardware-backed; Countermeasure—record purpose and access conditions, do not search for bytes (see step 4)
- TCC permissions cause missing functionality: Symptom—target functionality grayed out; Cause—TCC not authorized; Countermeasure—analyze its request logic rather than bypassing system permissions (red line)
- Notarization checks cannot be reproduced offline: Symptom—abnormal spctl results in an offline environment; Cause—notarization requires a network query (including revocation status); Countermeasure—use codesign local signature information instead, and annotate "notarization status unverified"
- hardened runtime restricts injection: Symptom—DYLD_INSERT_LIBRARIES has no effect; Cause—the runtime flags do not include the allow-dyld environment variable; Countermeasure—static analysis path ([[re-ghidra]]), do not hard-inject
- quarantine interferes with execution: Symptom—crash/popup when the target is downloaded from a source; Cause—
com.apple.quarantinetriggers Gatekeeper checks; Countermeasure—xattr -dr com.apple.quarantineremove and retest (test environment only) - Nested signatures missed in handling: Symptom—runtime verification fails after patching; Cause—framework/helper/extensions each have independent signatures; re-signing only the main program is insufficient; Countermeasure—
codesign --deepor re-sign layer by layer, and verify the CDHash of each layer - For decision branches (dynamic feasibility determination/data target grading), see [[decision-tree]]; for signature/injection/TCC boundaries and counterexamples, see [[gotchas]]; all executed within the sandbox (the highest principle of [[re-analyze/platform-tips]])