| Mode | Name | Size | |
|---|---|---|---|
| -rw-r--r-- | GADGET-CLASSES.txt | 16807 | logstatsplainblame |
| -rw-r--r-- | GADGETS.txt | 59679 | logstatsplainblame |
| -rw-r--r-- | ONESHOT-GADGETS.md | 174419 | logstatsplainblame |
| -rw-r--r-- | README.md | 4153 | logstatsplainblame |
| -rw-r--r-- | arm_mode_sled_sweep.py | 5784 | logstatsplainblame |
| -rw-r--r-- | build_sweep_pivot.py | 7137 | logstatsplainblame |
| -rw-r--r-- | gcp_22.0.0.77_code_0x400000.bin | 28672 | logstatsplainblame |
| -rw-r--r-- | gcp_22.0.0.77_image_0x400000.bin | 90368 | logstatsplainblame |
| -rw-r--r-- | gcp_code.arm.txt | 401538 | logstatsplainblame |
| -rw-r--r-- | gcp_code.thumb.txt | 841494 | logstatsplainblame |
| -rw-r--r-- | ptr_return_store.py | 6199 | logstatsplainblame |
| -rw-r--r-- | retaddr_reach.py | 5796 | logstatsplainblame |
| -rw-r--r-- | tlapi_lib.arm.txt | 59319 | logstatsplainblame |
| -rw-r--r-- | tlapi_lib.thumb.txt | 120141 | logstatsplainblame |
| -rw-r--r-- | tlapi_lib_0xf00000.bin | 4096 | logstatsplainblame |
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}orldr pc,[r4,#imm>=0x50]. Best found so far: 0x0040371cmov 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 61blx r4/bx r4sites (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.)
