┌─────────────────────────────────┬───────────┬─────────────┬─────────────────┬─────┬───────────┬────────────────────────────────────────┐ │ VA range │ PA │ size │ AP │ dom │ writable? │ what it is │ ├─────────────────────────────────┼───────────┼─────────────┼─────────────────┼─────┼───────────┼────────────────────────────────────────┤ │ 0x400000–0x407000 │ 0x423d000 │ 28 K │ R-X │ 6 │ ✗ │ GCP code (+ RO literal pools) │ │ 0x407000–0x417000 │ 0x4244000 │ 64 K │ RW- │ 6 │ ✓ │ .data + .bss │ │ 0x417000–0x418000 │ — │ 4 K │ — │ — │ ✗ │ guard (fault → wedges ring) │ │ 0x418000–0x41c000 │ 0x4254000 │ 16 K │ RW- │ 6 │ ✓ │ stack, SP0 = 0x41c000 │ │ 0x41c000–0x41d000 │ — │ 4 K │ — │ — │ ✗ │ guard │ │ 0x41d000–0x421000 │ 0x4258000 │ 16 K │ RW- │ 6 │ ✓ │ heap │ │ 0x421000–0x422000 │ — │ 4 K │ — │ — │ ✗ │ guard │ │ 0x422000–0x423000 │ 0x4260000 │ 4 K │ RW- │ 6 │ ✓ │ process page — contents never examined │ │ 0xf00000–0xf01000 │ 0x41c1000 │ 4 K │ R-X │ 7 │ ✗ │ tlApi library (the heap allocator) │ │ 0x04024000 +len │ host VRAM │ cmd_buf_len │ RW- │ 5 │ ✓ │ host-shared cmd buffer (ta_params) │ │ 0x200000–0x20f000 │ 0x12000 │ — │ R-X/RW-/**RWX** │ 1 │ ✗ DACR │ sysdrv — mapped but domain-blocked │ │ 0xe00000–0xeb7000 │ 0x4106000 │ — │ R-X/RW- │ 2 │ ✗ DACR │ ASD — mapped but domain-blocked │ │ 0x0–0x10000, 0x50000–0x88000, … │ — │ — │ --- (user) │ 0 │ ✗ │ sOS kernel (priv-only) │ └─────────────────────────────────┴───────────┴─────────────┴─────────────────┴─────┴───────────┴────────────────────────────────────────┘ 5 writable regions total: .data/.bss, stack, heap, process page, shared cmd buffer. 2. .data — [0x407000, 0x415a26), initialized ┌───────────────────┬───────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ VA range │ size │ contents │ ├───────────────────┼───────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ 0x407000–0x408926 │ 6.3 K │ PlayReady CertificateCollection XML — device cert chain (the 6 keys cmd02 returns) │ │ 0x408926–0x415a26 │ 53 K │ 44 ENC key blobs, 0x4C0 each — by wrapping-key-id: 0x67ff5db3×32, 0x5439fea3×9, 0xfb6a4205×3. Ciphertext only │ │ 0x415a26–0x416000 │ — │ file tail, zeros │ └───────────────────┴───────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ 3. .bss globals — GCP's entire mutable global set is 9 cells ┌──────────┬────────────────────┬─────────────────────────────────────────────────────────────────────┐ │ VA │ referenced from │ what it is │ ├──────────┼────────────────────┼─────────────────────────────────────────────────────────────────────┤ │ 0x416000 │ 0x40011c, 0x4022cc │ runtime-globals base (gcp_runtime_globals) │ │ 0x416014 │ 0x405748 │ tlApiMalloc heap BASE cache — measured = 0x0041d000 │ │ 0x416018 │ (same pair [1]) │ heap SIZE cache │ │ 0x41601c │ 0x4042b0 │ unidentified │ │ 0x4164dc │ 0x4042ac │ FE08 __h4 scratch/guard │ │ 0x41699c │ 0x404264 │ FE08 __h3/__h4 scratch/guard │ │ 0x416e5c │ 0x40293c │ resolved tlApi library entry (→ 0xf00100); the only cell holding it │ │ 0x416e60 │ 0x404054 │ shared handle/state (cmdFE02, rpc_103B) │ │ 0x416e64 │ 0x40010c │ .bss top marker │ └──────────┴────────────────────┴─────────────────────────────────────────────────────────────────────┘ Everything else in those ~6 K is unused zeroed space — nothing reads it. ⚠️ 0x416014 was previously mislabelled "session-context pointer" (Add.80 correction). There is no ctx pointer in .bss — sOS holds it and passes it as a1 per invoke. 4. Heap — [0x41d000, 0x421000) ``` 0x41d000 ┬ IN-BAND allocator header (0x30 B) ← writable, == (ctx - 0x30) │ +0x00/+0x04/+0x18 = 0x0041ee40 next-free / chunk end │ +0x08 = 0x21a0 ? +0x20 = 0x5600 ? (UNEXPLAINED: 0x5600 > the 0x4000 heap) │ +0x0c = 0x41d010 +0x10 = 0x41d000 link-ish │ +0x1c = 0x00001e10 this chunk's size ✓ 0x41d030 ┴ ctx payload (0x1e10) ─────────────────────────────────────────── ``` ┌────────────┬───────────────────┬────────┬─────────────────────────────────────────────────────────────────────────────────────────────┐ │ struct │ base │ stride │ fields (slot i) │ ├────────────┼───────────────────┼────────┼─────────────────────────────────────────────────────────────────────────────────────────────┤ │ drm[32] │ 0x41d030 │ 0x18 │ handle@+0, state@+4, body[16]@+8 │ │ auth[16] │ 0x41d330 │ 0x50 │ handle@+0, state@+4, body[72]@+8 │ │ crypto[64] │ 0x41d830 │ 0x58 │ handle@+0, unk04@+4, key(u64)@+8, field10@+0x10, decode_handle@+0x18, state@+0x20, rest[52] │ │ tail │ 0x41ee30 │ — │ asd_refcount, unk1E04@+4, handle_counter@+8 │ │ free heap │ 0x41ee40–0x421000 │ — │ ~8.9 K, never allocated │ └────────────┴───────────────────┴────────┴─────────────────────────────────────────────────────────────────────────────────────────────┘ TA heap metadata layout (heap [0x41d000, 0x421000); allocator = user-mode library 0xF00000) ``` 0x41d000 ┌──────────────────────────────┐ │ ARENA DESCRIPTOR (0x10 B) │ 0x41d010 ├──────────────────────────────┤ ◄── H (chunk header = ptr − 0x20) │ CHUNK HEADER (0x20 B) │ 0x41d030 ├──────────────────────────────┤ ◄── ctx (the pointer tlApiMalloc returned) │ │ │ PAYLOAD: gcp_ctx (0x1e10) │ │ drm[32] auth[16] crypto[64]│ │ │ 0x41ee40 ├──────────────────────────────┤ ◄── next chunk (the free remainder) │ CHUNK HEADER (0x20 B) │ flag=1 (free), size 0x21a0 0x41ee60 ├──────────────────────────────┤ │ free space (0x21a0) │ 0x421000 └──────────────────────────────┘ ``` Arena descriptor — 0x41d000, 0x10 bytes ┌───────┬──────────┬────────────┬──────────────────────────────────────┐ │ off │ abs │ measured │ role (from free()/malloc disasm) │ ├───────┼──────────┼────────────┼──────────────────────────────────────┤ │ +0x00 │ 0x41d000 │ 0x0041ee40 │ list head; written str r2,[r1] when │ │ │ │ │ a coalesce empties the chain │ ├───────┼──────────┼────────────┼──────────────────────────────────────┤ │ +0x04 │ 0x41d004 │ 0x0041ee40 │ free-list head; read ldr r2,[r1,#4], │ │ │ │ │ compared against H, rewritten │ │ │ │ │ [r1,#4]=r2 │ ├───────┼──────────┼────────────┼──────────────────────────────────────┤ │ +0x08 │ 0x41d008 │ 0x000021a0 │ total free bytes — target of │ │ │ │ │ *(arena+8) += size+0x20 │ ├───────┼──────────┼────────────┼──────────────────────────────────────┤ │ +0x0c │ 0x41d00c │ 0x0041d010 │ fallback/first-chunk pointer (read │ │ │ │ │ when the +0x04 chain hits 0) — │ │ │ │ │ points at H │ └───────┴──────────┴────────────┴──────────────────────────────────────┘ ✔ Cross-check: 0x421000 − 0x41ee40 − 0x20 = 0x21a0 — exactly the +0x08 value. Confirms it's the free-byte accounting. Chunk header — H = ptr − 0x20, 0x20 bytes ┌───────────┬───────────┬────────────┬──────────────────────┬──────────┐ │ off │ abs (ctx │ measured │ role │ evidence │ │ │ chunk) │ │ │ │ ├───────────┼───────────┼────────────┼──────────────────────┼──────────┤ │ +0x00 │ 0x41d010 │ 0x0041d000 │ arena back-pointer. │ free │ │ │ │ │ r1 = [ptr−0x20], │ 0xf004dc │ │ │ │ │ then *(r1+8) += │ │ │ │ │ │ size+0x20 — │ │ │ │ │ │ dereferenced │ │ │ │ │ │ unconditionally, │ │ │ │ │ │ first │ │ ├───────────┼───────────┼────────────┼──────────────────────┼──────────┤ │ +0x04 │ 0x41d014 │ 0x00000000 │ prev chunk. If ≠0 │ free │ │ │ │ │ and │ 0xf00502 │ │ │ │ │ byte[prev+0x10]≠0 → │ │ │ │ │ │ backward coalesce: │ │ │ │ │ │ *(prev+0xc) += …, │ │ │ │ │ │ *(prev+8) = next │ │ ├───────────┼───────────┼────────────┼──────────────────────┼──────────┤ │ +0x08 │ 0x41d018 │ 0x0041ee40 │ next chunk. │ free │ │ │ │ │ *(next+4) = prev ← │ 0xf00514 │ │ │ │ │ the unlink write; │ │ │ │ │ │ forward coalesce │ │ │ │ │ │ reads │ │ │ │ │ │ byte[next+0x10] │ │ ├───────────┼───────────┼────────────┼──────────────────────┼──────────┤ │ +0x0c │ 0x41d01c │ 0x00001e10 │ size (= the 0x1E10 │ free │ │ │ │ │ requested). Addend │ 0xf004e0 │ │ │ │ │ in both += writes │ │ ├───────────┼───────────┼────────────┼──────────────────────┼──────────┤ │ +0x10 │ 0x41d020 │ 0x00 │ flag: 0 = allocated, │ free │ │ │ │ │ 1 = free. Validated │ 0xf005de │ │ │ │ │ (must be 0), set to │ / │ │ │ │ │ 1 by free │ 0xf004ee │ ├───────────┼───────────┼────────────┼──────────────────────┼──────────┤ │ +0x11 │ 0x41d021 │ 0x56 │ MAGIC 'V'. Validated │ free │ │ │ │ │ by free and realloc; │ 0xf005da │ │ │ │ │ zeroed on coalesce │ │ ├───────────┼───────────┼────────────┼──────────────────────┼──────────┤ │ +0x12..13 │ 0x41d022 │ 0x0000 │ unknown / padding │ — │ ├───────────┼───────────┼────────────┼──────────────────────┼──────────┤ │ +0x14 │ 0x41d024 │ unread │ flags, replayed into │ realloc │ │ │ │ │ malloc by realloc │ 0xf00652 │ ├───────────┼───────────┼────────────┼──────────────────────┼──────────┤ │ +0x18 │ 0x41d028 │ unread │ size used as memcpy │ realloc │ │ │ │ │ length by realloc │ 0xf0064a │ │ │ │ │ (min(old,new)) │ │ ├───────────┼───────────┼────────────┼──────────────────────┼──────────┤ │ +0x1c │ 0x41d02c │ unread │ unknown │ — │ └───────────┴───────────┴────────────┴──────────────────────┴──────────┘