Companion to Terra Incognita — Apple Silicon Forensics · v1.0 · Konrad (@unrooted) Klawikowski · 02/06/2026
The wall is also a witness. The same lockdown that denies you the old acquisition options — Target Disk Mode, block-level imaging, chip-off, memory dumps, SEP introspection — is the architecture that signs, caches, logs, and SIP-protects more persistent evidence than Intel ever did.
Three buckets — keep them straight:
- Logical collection of the trail → solved. Glob the files today, with tools that exist. This is the easy half.
- Deep acquisition (memory, SEP internals, physical) → still the frontier. Largely unsolved; that's the research list.
- Interpretation of the AS-native artifacts → the real terra incognita. Parsers exist (you can read the bytes), but the forensic meaning — cross-version behaviour, normal-vs-anomalous baselines, how artifacts corroborate each other — is still being charted. A parser is a camera, not a map.
Collection is commodity. Understanding what you collected is the open problem.
| Bucket | Artifacts | Why |
|---|---|---|
| Genuinely AS-native | Rosetta AOT cache (/var/db/oah) · aot_shared_cache · PAC crash artifacts (ARMv8.3) · LocalPolicy as a user-configurable on-disk policy object + its 4CCs · the NVRAM 1TR-gated boot-security model · the iSCPreboot/Preboot two-volume layout |
New because the chip + boot architecture are new |
| Format older than AS / shared with iOS or T2 | IMG4 (Image4 since ~iOS 7 / 2013; on Intel via the T2 chip, 2017+, for secure boot) — only the LocalPolicy usage is AS-era · SEP (T2 Intel Macs had one too) | The container/coprocessor predates Apple Silicon; the application is what changed |
| macOS-wide — not AS at all (the anti-list) | Unified Logs / tracev3 (macOS Sierra 10.12, 2016) · Biome (Ventura 13) · KnowledgeC · TCC · Quarantine DB · APFS snapshots · FSEvents · ExecPolicy / KextPolicy (notarisation era) | Shipped across the macOS line, Intel included |
Rule of thumb: tracev3 and Biome are modern macOS; IMG4/SEP are Apple, pre-AS; AOT, PAC, and LocalPolicy-on-disk are the genuinely new terrain.
Each stage cryptographically verifies the next (the chain of trust); each leaves a different artifact.
| Stage | Drops |
|---|---|
| Boot ROM (immutable, on-die) | nothing on disk — root of trust |
| LLB → iBoot (reads LocalPolicy, checks nonce) | LocalPolicy IMG4 (iSCPreboot) · NVRAM boot-args/boot-nonces (1TR-gated) |
| Kernel + AuxKC (SEP co-signs) | single kernelcache (root:wheel) in Preboot · AuxKC = approved third-party kexts, hash tied to LocalPolicy |
| macOS userspace (Cryptex · Rosetta · execution) | Preboot restore/update history + CryptexRegistry · Rosetta AOT first-execution timestamps |
| Runtime (PAC enforced) | EXC_BAD_ACCESS w/ high-bit address on auth failure → exploitation-attempt signal |
iSCPreboot = the policy (LocalPolicy img4). Preboot = the history (BORD logs, RestoreLog, CryptexRegistry, kernelcache, firmware). Same volume-group UUID — collect both.
| Observation | Interpretation |
|---|---|
| LocalPolicy at Permissive Security on a non-dev machine | Physical access + admin credentials, via 1TR. Timestamped. |
Anomalous boot-args in NVRAM |
Deliberate weakening — userspace can't write these; required 1TR. |
coih set in LocalPolicy |
Non-Apple kernel hash installed via kmutil configure-boot. Asahi, dev, or attacker. |
| Cluster of PAC failure crashes against one process | Exploitation attempt — attacker iterating. |
RestoreLog.plist shows rollback to older macOS |
Possible reach for a vulnerable kernel or to defeat newer EDR. |
AOT files for ping, chmod, sudo, id, cat clustered in a tight window |
x86_64 process invoked native tools — POOLRAT-style tradecraft. Clustering/timing is the tell — individual AOTs may predate the intrusion. |
/var/db/oah empty when x86_64 binaries were present |
Either no Rosetta execution or SIP was disabled (itself a 1TR event). |
| Cryptex/RSR versions mismatched against claimed macOS build | "macOS 14.x.y" isn't precise enough — actual patch level differs. |
| Touch ID enrolled count drops between snapshots | User or actor tidied biometric state. Note: no userspace timestamps. |
_oahd no longer owns an .aot, or AOT mtime > binary's last run |
Possible AOT tampering (see tradecraft). SIP-off is the precondition. |
| Path / Command | What it tells you | AS-only? | Parse with |
|---|---|---|---|
/var/db/oah/<UUID>/<binary>.aot |
First-execution evidence for x86_64 binaries (birth-time); _oahd-owned |
✓ | stat -f %SB; binary tools |
aot_shared_cache (with dyld_shared_cache) |
Pre-translated system frameworks; tampering surface | ✓ | Project Champollion |
/System/Volumes/iSCPreboot/<UUID>/LocalPolicy/*.img4 |
Security mode, SIP bits, AuxKC, MDM, custom kernel | ✓ (usage) | bputil -e · img4lib · pyimg4 |
…/Preboot/<UUID>/var/log/BORD/ |
Boot progress logs | ✓ | log |
…/Preboot/<UUID>/RestoreLog.plist |
OS reinstall/restore history with timestamps | ✓ | plutil |
…/Preboot/<UUID>/var/db/CryptexRegistry/ |
RSR + cryptex versions, install times | ✓ | plutil |
…/Preboot/<UUID>/boot/<hash>/…/com.apple.kernelcaches/kernelcache |
Single Boot Kernel Collection (root:wheel, ~30 MB); chip ID not in filename; AuxKC separate | ✓ | binary tools (Mach-O) |
~/Library/Logs/DiagnosticReports/ |
PAC failure crashes (exploit attempts) | ✓ | grep |
/var/db/spindump/ · ASL DB |
Backup locations for PAC crashes | ✓ | log |
/var/db/lockdown/ |
DFU / Configurator pairing records | partial | binary |
/var/MobileAsset/AssetsV2/ |
Downloaded-but-unapplied updates / RSRs | partial | filesystem |
NVRAM boot-args, boot-nonces |
Boot security state — userspace can't modify | ✓ | nvram -p |
bioutil -r -s / -c -s |
Touch ID config + enrolled count (current state only) | ✓ | direct output |
/var/db/SystemPolicyConfiguration/ExecPolicy |
Execution provenance, signing identity | ✗ Intel too | sqlite3 |
/var/db/SystemPolicyConfiguration/KextPolicy |
Approved third-party kext history | ✗ Intel too | sqlite3 |
Notes: /var/db/oah and /var/db/lockdown are SIP-protected — even sudo find returns Operation not permitted on a live box, so read them from the image or with your acquisition tool's privileges. The kernelcache <hash> dir and exact MobileAsset layout vary by build — verify paths on your own machine before quoting them in reports.
| 4CC | Meaning |
|---|---|
smb0, smb1 |
Security downgrade bits: Reduced (smb0) / Permissive (smb1) |
sip0 |
SIP policy bits (moved off NVRAM) |
sip3 |
Disables iBoot's boot-args allow-list enforcement |
auxp, auxr |
AuxKC policy hash + receipt (third-party kexts) |
coih |
Custom kernel hash — kmutil configure-boot from 1TR |
smb4 |
MDM enrolment via ABM/ASM |
| SoC ID | Chip |
|---|---|
t8103 |
M1 |
t8112 |
M2 |
t8122 |
M3 |
t8132 |
M4 |
Read these from ioreg, panic logs, system_profiler SPHardwareDataType, or IPSW/restore filenames — not from the on-disk Preboot kernelcache (that file is just kernelcache, root:wheel; no chip ID in the name).
Apple Silicon-exclusive (ARMv8.3 hardware; Intel literally cannot generate these).
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x<high-bit-set value>
High bits set because the chip stripped the auth code and found a mismatch. One = curiosity. Cluster against same process = strong exploit-attempt evidence.
- x86_64 / Rosetta loophole — ARM64 requires strict code signing + notarisation; x86_64 under Rosetta has relaxed requirements. State-sponsored actors ship x86_64 builds by choice (not for lack of an ARM64 toolchain). POOLRAT is the named example.
- Forced Rosetta — any x86-only tool drags the chain into the relaxed environment. Classic illustration: Python 2 (no ARM64-native macOS build), but it's just one instance — pick any x86-only binary and you've downgraded signing for free and generated AOT cache.
- Universal binaries default to the x86_64 slice under Rosetta — any universal or x86 tool invoked by an x86_64 process is translated and leaves an AOT entry, even on an M-series Mac.
- AOT poisoning — theoretical, not yet in the wild. SIP off → rewrite a
.aotso the clean, correctly-signed source binary silently executes injected ARM64. Detect: regenerate a known-good AOT from the original binary (pinned OS + Rosetta) and hash-diff vs the on-disk entry; at scale, glob theoahtree and re-translate offline, alerting where the source hash is unchanged but the AOT differs. Cheap signals first: broken_oahdownership · AOT mtime newer than the binary's last legit run · SIP-off precondition (no SIP-off, no poisoning). Caveat: re-translation isn't bit-deterministic across versions — pin OS + Rosetta, or diff behaviourally. - AuxKC abuse — only possible with SIP disabled, which itself is a noisy 1TR event.
- EDR / Endpoint Security visibility — ES sees the x86
execevent, but the_oahdAOT write is post-hoc — the cache is evidence after the fact, not a real-time alert. - Prevention (blue team) — MDM-enforce Full Security so a LocalPolicy downgrade is impossible-or-visible; alert on LocalPolicy downgrades and
_oahdanomalies. Turns these artifacts into tripwires, not just post-hoc evidence. - Catalog of macOS LOTL binaries: LOOBins — by Brendan Chamberlain (@infosecB). Each entry has MITRE ATT&CK mappings, example malicious uses, and detection signatures. Cited by CISA and Australia's ASD as the canonical macOS LOTL reference. PyLOOBins SDK + JSON API for programmatic consumption.
Modern-macOS artifacts that get mistaken for AS-specific. Collect them, but don't claim them as Apple Silicon evidence (see the native-vs-inherited table above for why):
Biome · Unified Logs (tracev3) · KnowledgeC · TCC · Quarantine DB · APFS snapshots · FSEvents · ExecPolicy / KextPolicy
What the two big collection frameworks grab out of the box, and — critically — what they don't (the AS-specific artifacts you still collect by hand).
Velociraptor — built-in macOS artifacts (MacOS.* / Generic.*):
| Artifact | Covers |
|---|---|
MacOS.System.TCC |
TCC.db — privacy/permission grants |
MacOS.System.QuarantineEvents |
LSQuarantine — download provenance |
MacOS.System.Plist |
arbitrary plist parsing |
MacOS.System.Users / .Dock / .Wifi / .TimeMachine |
accounts, dock, Wi-Fi, TM config |
MacOS.Applications.KnowledgeC |
KnowledgeC.db — app usage/activity |
MacOS.Applications.Chrome.History / .MRU |
browser + recent items |
MacOS.Detection.Autoruns / .InstallHistory |
persistence + install history |
MacOS.UnifiedLogHunter |
live log predicate hunting |
Exchange.MacOS.UnifiedLogParser |
offline tracev3 (wraps Mandiant lib) |
Exchange.MacOS.Collection.Aftermath |
runs Aftermath, ships result to server |
Generic.Forensic.SQLiteHunter |
see below |
SQLiteHunter (Generic.Forensic.SQLiteHunter, bundled since Velociraptor 0.7.0) — auto-discovers and parses any known SQLite DB on the host: browser history/cookies/downloads (Chrome, Firefox, Edge, Safari, Opera), TCC, KnowledgeC, Quarantine, plus many app DBs. One artifact, identify-then-parse, self-contained. The right tool when you don't know in advance which DBs are present.
What neither parses natively today — hand-collection list (the AS-specific gap):
/var/db/oah (Rosetta AOT) · LocalPolicy img4 (bputil -e / iSCPreboot) · NVRAM boot-args/boot-nonces · Preboot BORD logs · RestoreLog.plist · CryptexRegistry · PAC crash reports · /var/db/lockdown pairing · SEP/firmware version · bioutil Touch ID state
This is the seam the talk is about: the general macOS frameworks have mature coverage of the charted (modern-macOS) artifacts and no native parser for the AS-specific ones — you bolt on the standalone tools below by hand. Getting the bytes is solved; turning them into meaning is the frontier.
Acquisition (Apple Silicon-capable): Fuji · LLIMAGER · RECON ITR · Cellebrite Digital Collector
Collection frameworks: Velociraptor (MacOS.* artifacts + offline collector) · SQLiteHunter (Generic.Forensic.SQLiteHunter)
Live IR / MDM-driven: Aftermath (Jamf Threat Labs) — Swift, deploys via MDM, --analyze mode produces chronological storyline
Image artifact parser: mac_apt (Yogesh Khatri) — Python, cross-platform, 30+ plugins, works on E01/VMDK/AFF4/DD/DMG/Velociraptor/UAC collections
Unified Logs parser (offline): mandiant/macos-UnifiedLogs — Rust, parses .logarchive / tracev3 to CSV or JSON, cross-platform binaries
AOT shared cache RE: Project Champollion (FFRI) — format research; no turnkey forensic parser yet
Native / raw parsing: bputil -e (LocalPolicy) · img4lib / pyimg4 (raw IMG4) · sqlite3 (ExecPolicy/KextPolicy) · plutil (plists, RestoreLog) · nvram -p · log (live unified logs)
Order matches priority. All commands need an unlocked, logged-in session and sudo.
# 1. Logical image — pick one
# Fuji · LLIMAGER · RECON ITR · Cellebrite Digital Collector
# 2. Unified logs
sudo log collect --last 30d
# 3. LocalPolicy
sudo bputil -e
# + raw img4 files from:
# /System/Volumes/iSCPreboot/<UUID>/LocalPolicy/
# 4. SIP-protected dirs — even root gets "Operation not permitted" live;
# read them from the IMAGE, or with your acquisition tool's privileges
# /var/db/oah # Rosetta AOT cache
# /var/db/lockdown # DFU/Configurator pairing
# /var/db/SystemPolicyConfiguration # ExecPolicy, KextPolicy (Intel too)
# /System/Volumes/Preboot/<UUID>/ # BORD logs, RestoreLog, CryptexRegistry
# 4b. AOT first-execution timeline (run on the IMAGE — live find is denied)
# sudo find /var/db/oah -name '*.aot' \
# -exec stat -f '%SB %Su %N' -t '%Y-%m-%d %H:%M:%S' {} \; | sort
# 4c. Verify the real kernelcache path on THIS build (the <hash> dir varies)
# sudo find /System/Volumes/Preboot -type d -name com.apple.kernelcaches
# # -> contains ONE file named `kernelcache` (root:wheel, ~30 MB)
# 5. Single-shot commands
sudo nvram -p
system_profiler SPHardwareDataType
sudo bioutil -c -s
sudo sysdiagnoseDrive removal = ciphertext, always. On a live machine, FileVault decides: on → password-gated; off → the Secure Enclave releases the volume key at boot (data accessible without the password). Check FileVault state first.
- Goddard, J. — Not Lost in Translation, Mandiant / Google Cloud, 2025
- Apple — Apple Platform Security guide
- Howard Oakley — The Eclectic Light Company (LocalPolicy, boot internals)
- Aftermath — Jamf Threat Labs · github.com/jamf/aftermath
- mac_apt — Y. Khatri (@SwiftForensics) · github.com/ydkhatri/mac_apt
- macos-UnifiedLogs — Mandiant · github.com/mandiant/macos-UnifiedLogs
- Velociraptor (Rapid7 / Velocidex) · SQLiteHunter — github.com/Velocidex/SQLiteHunter
- FFRI — Project Champollion (AOT shared cache reverse-engineering)
- LOOBins — B. Chamberlain (@infosecB) · loobins.io
- Fuji (A. Lazzarotto) · RECON ITR (SUMURI) · LLIMAGER (e-Forensics) · Digital Collector (Cellebrite)
- Prior work: Sarah Edwards (mac4n6) · Csaba Fitzl · Patrick Wardle / Objective-See · the Mandiant FLARE team