# Branch-target hunting material (GCP 22.0.0.77 + tlApi library) Produced for the control-flow work in FINDING-GCP-FE09-...md Add.89-94. ## Binaries (offset == VA - base, so you can disassemble at the right address) | file | base VA | notes | |---|---|---| | `tlapi_lib_0xf00000.bin` | `0xf00000` | the 4 KB tlApi library page, **live dump from the emulator** (mapped R-X, dom 7). Code occupies `0xf00101-0xf00790`; `"$PS1"` magic + len `0x590` at `+0x10`. ARM veneer at `0xf00100`, Thumb body from `0xf00114`. | | `gcp_22.0.0.77_code_0x400000.bin` | `0x400000` | GCP code region `0x400000-0x407000` (R-X). **`0x400000-0x400100` is SYNTHETIC ZERO PADDING** — the real content is unknown (Add.92 observed an ARM store executing at `0x400044`, so it is NOT all zero). Body proper starts at `0x400100`. | | `gcp_22.0.0.77_image_0x400000.bin` | `0x400000` | same but the whole image (code+.data+.bss span, to `0x416100`). | ## Disassembly (linear sweep, resynced every instruction so literal pools don't desync) `tlapi_lib.thumb.txt`, `tlapi_lib.arm.txt`, `gcp_code.thumb.txt`, `gcp_code.arm.txt` ## Gadget catalogues `GADGETS.txt` - control-transfer / sp-write / svc sites, per region per mode `GADGET-CLASSES.txt` - grouped: PC-from-r4, PC-from-mem, SP-from-reg, add-sp+pop-pc, bx/blx r4|r0 ## Entry state when our planted branch is taken `UNLOAD_TA -> TA_CloseSessionEntryPoint -> gcp_tlApiFree -> gcp_call_once_init -> bx ip` r0 = sp = &requestBlock (tlApiFree frame) r1 = r2 = r3 = 0 r4 = ctx pointer (0x41d030) r5 = sp lr = 0x405617 (into tlApiFree) Z=1, V=0 (from `movs r3,#0`) requestBlock: [sp]=0x22 [sp+4]=2 [sp+8..0x28)=0 [sp+0x38]=ctx ; rest = stale stack NOTE: branching INTO an IT block clears ITSTATE, so e.g. `moveq sp,r4` at 0x40371c executes unconditionally as `mov sp,r4` (encoding 0xa546 is a plain MOV). ## What we are looking for A gadget that sources PC or SP from memory we can fill: * carvable heap: any address >= heapbase+0x7f = 0x41d07f (= ctx+0x4f) -- arbitrary bytes, ~256 CodecToken stamps per byte (descending trailing-byte carve, Add.91) * host-written ctx: FE07 puts arg18 at auth[i]+4 and arg10 (8B) at auth[i]+0x10 for 16 slots => ~192 bytes of CHOSEN data at ctx+0x300 + 0x50*i, no lottery needed So the wanted shapes are `mov sp,r4 ; add sp,#>=0x300 ; pop {...,pc}` or `ldr pc,[r4,#imm>=0x50]`. Best found so far: 0x0040371c `mov sp,r4 ; pop.w {r4,r5,r6,r7,r8,sb,sl,fp,pc}` -- pivots to ctx but takes PC from ctx+0x20, which is NOT carve-writable (A=target-0x7f lands in the guard page), so only blob-window values fit there and the only mapped+executable one is 0x00400000. Dead ends: the 61 `blx r4` / `bx r4` sites (r4=ctx, heap is RW-/XN). ## BUILD SENSITIVITY (read this first) All binaries here are **22.0.0.77** (`ta_22-0-0-77_7c426e7f`), the build running on our card. Gadget addresses do NOT carry across builds. Measured at the two addresses used above: | build | 0x40363a | 0x40371c | |---|---|---| | 22.0.0.53/.57/.60 | `f104` add.w r0,r4,#0x30 | `a14f` adr r1,#0x13c | | 22.0.0.62/.64 | `f5b1` cmp.w r1,#0x100 | `f8cd` str.w r0,[sp,#0x79c] | | **22.0.0.68/.71/.73/.77** | **`46a5` mov sp,r4** | **`46a5` mov sp,r4 ; pop.w {r4-r8,sb,sl,fp,pc}** | | 22.0.4.50 | `2210` movs r2,#0x10 | `2010` movs r0,#0x10 ; str r0,[sp,#0x1c] | So the `mov sp,r4 ; pop {...,pc}` pivot exists only on the .68-.77 line. Note the emulator harness (`fuzz_newtas.pick_container`) defaults "gcp" to **ta_22-0-4-50**, which is how one easily ends up disassembling the wrong image -- the same mistake recorded in FINDING Add.49 and Add.55. ## CAVEAT on the gadget catalogues `GADGETS.txt`, `GADGET-CLASSES.txt` and the `*.txt` sweeps decode at EVERY 2-byte offset, so they intentionally include UNINTENDED (misaligned) decodes. Those are valid ROP gadgets -- any halfword is a legal branch target -- but they are not the intended instruction stream. Re-check any candidate with a sequential decode before relying on it. (0x40371c is valid in both senses: `bfc r4,#0,#0xb` at 0x403636 is 4 bytes, so 0x40363a/0x40371c are genuine instruction boundaries.)