Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
amazon-mustang-hack — Kernel-Exploit-Forschung, die temporären Root auf dem Amazon Fire 7 (Fire OS 7.3.3.1) über den Mali kbase JIT Use-after-free CVE-2022-38181 erreicht, mit einer modprobe_path-Überschreibungskette. | Kitploit
Tools/GitHubGitHub/artur9010/amazon-mustang-hack
Android-SicherheitPrivilege EscalationSchwachstellenanalyseExploitationReverse EngineeringMobile SicherheitPapers & ForschungPayload-EntwicklungBinary-Exploitation

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen
GitHubartur9010/amazon-mustang-hack

amazon-mustang-hack

Kernel-Exploit-Forschung, die temporären Root auf dem Amazon Fire 7 (Fire OS 7.3.3.1) über den Mali kbase JIT Use-after-free CVE-2022-38181 erreicht, mit einer modprobe_path-Überschreibungskette.

Repository anzeigenWebseite
vor 13h 58mNoch nicht geprüft

KI-gestütztes Projekt. Diese Recherche, Exploit-Entwicklung und Dokumentation wurden mit KI-Unterstützung unter Verwendung der Modelle GLM-5.3 und DeepSeek V4.1 Flash erstellt.

amazon-mustang-hack

Root-Exploit-Recherche für das Amazon Fire 7 9. Gen (mustang, MT8163, Mali-T720) auf der finalen Firmware — Fire OS 7.3.3.1, PS7331.4463N, Kernel 4.9.117 (gebaut 2025-05-03, SPL 2024-08-01).

Ziel: LineageOS. Der Bootloader-Pfad ist auf diesem Gerät tot (gepatchtes Bootrom — nur Preloader via CMD-Kurzschluss), daher ist der einzige verbleibende Weg ein Software-Kernel-Exploit.

Schnellstart```

one-shot: build, run the exploit (retries across the probabilistic reclaim),

install a setuid-root su and verify it as an unprivileged user

nix-shell -p android-tools --run './run.sh' # add -p zig too if no zig

root@kitploit:~
Bei Erfolg:```
/data/metrics/su id     # run a command as root
/data/metrics/su        # interactive root shell

Der Reclaim gewinnt ungefähr 1 Boot von 3 und ein Verlust führt zu einer Panik/Neustart des Tablets; run.sh wartet einfach auf den Neustart und versucht es erneut. SELinux wird als Teil des Exploits auf Permissive gezwungen, daher ist root nur zur Laufzeit — ein Neustart stellt den Auslieferungszustand wieder her und du führst run.sh erneut aus.

Vorkompiliertes st3 und su (armv7 static) sind eingecheckt, daher wird keine Toolchain zum Ausführen benötigt. ./run.sh --build baut sie aus poc/*.c neu, wenn du zig hast.

Alles unterhalb ist nur ein Protokoll der vom Modell geleisteten Arbeit, kein menschlicher Input unterhalb.

PRIMÄRES ZIEL (seit Session 5): kbase CVE-2022-38181 — Stufe 2 BEWIESEN

GhostLock (unten) ist geparkt: MTKs BUG_ON-rtmutex-Variante + keine Kernel-Adress-Offenlegung aus der Shell = architektonische Sackgasse in diesem Build (Sessions 2-4). Der kbase JIT UAF wurde neu diagnostiziert (die Destroy-Worker-„bedingungslose Panik" war die JIT_FREE-Dereferenzierung, Log verloren durch adbd-Tod mitten in der Panik) und Stufe 2 ist nun orakel-bewiesen — siehe SESSION 5 Abschnitt.

GEPARKT: GhostLock, CVE-2026-43499

rtmutex remove_waiter() futex-PI Stack-UAF (NebuSec-Offenlegung 2026-07, Fix 3bfdc63936dd gelandet 2026-04). Verwundbarer Bereich 2.6.39–7.1 → unser 4.9.117 (Mai 2025) ist betroffen.

Verifiziert auf unserem exakten Build:

  • CONFIG_FUTEX=y, rtmutex einkompiliert, Bug wörtlich vorhanden: rtmutex.c:1108-1111 verwendet current->pi_lock/current->pi_blocked_on (sollte waiter->task sein); fehlerhafte Aufrufstelle rtmutex.c:1723 (rt_mutex_start_proxy_lock Fehlerpfad)
  • Trigger-Oberfläche = reine futex-Syscalls (WAIT_REQUEUE_PI/CMP_REQUEUE_PI), kein Device-Node, nichts SELinux-geschützt — die fatalen Hindernisse des kbase-Pfads existieren hier nicht
  • Konsument: sched_setattr → __sched_setscheduler → rt_mutex_adjust_pi(p) bei sched/core.c:4706 — dereferenziert veraltetes ✓

TODO (Port-Plan)

  1. Trigger schreiben (3-Thread requeue-PI Deadlock, Cores 0-3) — Port von exp32/main.c
  2. Stamp-Geometrie: rt_waiter Frame-Offset vs do_sys_select fd_set-Bereich — unser vmlinux disassemblieren (do_sys_select stack_fds vs futex_wait_requeue_pi Frame), STAMP_NFDS/STAMP_WAITER_OFF als Tunables offenlegen
  3. Fake-Writer-Encoding für arm32 48-Byte Waiter → „write V to ADDR"-Slots
  4. 2 Slots → modprobe_path, feuern, root script
  5. Fallbacks falls select-Stamp nicht erreicht: setsockopt(MCAST_JOIN_SOURCE_GROUP) Stamp

Status

  • Bootrom (amonet Hardware-Methode) — auf diesem Gerät gepatcht, Sackgasse
  • mtk-su (CVE-2020-0069) — gepatcht, Failed critical init step 3
  • Angriffsflächen-Untersuchung — /dev/mali0 world-RW + SELinux gpu_device, kbase r26p0-01rel0
  • CVE-2022-38181 im exakten Build-Quellcode bestätigt; Stufe-1-Trigger funktioniert
  • CVE-2026-43499 (GhostLock) verifiziert, aber blockiert: MTK BUG_ON rtmutex Variante + keine Kernel-Adress-Offenlegung aus der Shell (Sessions 2-4)
  • CVE-2022-38181 Stufe 2 BEWIESEN (Session 5): Destroy-Worker-Panik war eine Fehldiagnose; UAF-Umleitung auf gesprayte Region, orakel-verifiziert
  • Stufe 1: Trigger + Stamp + Konsument (Crash = Kette live)
  • Stufe 2 (kbase-Pfad): UAF-Umleitung auf gesprayte Region — BEWIESEN Session 5
  • Stufe 2b: Raw-Byte-Slot-Kontrolle (xattr-Stamp-Churn) → unlink Write
  • — nf LOCAL_OUT Hook-Hijack, 2-Paket-Kette: nullen, Fake-Eintrag auf umschreiben. , SELinux Permissive.

Wichtige Erkenntnisse

Gerät / Firmware

  • Modell KFMUWI, Gerät mustang, Fire OS 7.3.3.1 PS7331.4463N/0031575863040
  • Kernel 4.9.117-g08fe75b-dirty, gebaut Sat May 3 01:25:15 UTC 2025 (Linaro GCC 6.3-2017.05)
  • Amazon hat 7.3.3.1 im Mai 2025 stillschweigend neu herausgegeben (neues Incremental, gleicher Versionsstring)
  • Bootrom-Revision nach 2020: Kurzschluss-zu-GND auf eMMC CMD liefert nur Preloader (gepatcht)
  • /dev/kb, /dev/dkb (Amazon Kernel-Backup-Partitionen) root:drmrpc 0660 — gesperrt

Warum CVE-2022-38181 zutrifft

  • Treiber: mali_kbase r26p0-01rel0 (Midgard, Mali-T720), innerhalb des NVD-betroffenen Bereichs r4p0–r31p0
  • Amazons Mai-2025-Rebuild lieferte den Bug von 2018 wörtlich aus — kein Backport
  • Exakter verwundbarer Code, quellcode-verifiziert:
    • mali_kbase_mem.c:2721 kbase_jit_destroy_worker gibt Region frei, löscht nie kctx->jit_alloc[id]
    • mali_kbase_softjobs.c:1270 kbase_jit_free_finish dereferenziert das veraltete jit_alloc[ids[j]]
    • mali_kbase_mem.c:3138 kbase_jit_backing_lost → Destroy-Pfad (feuert während Reclaim)

Ausbeutungsklima (alles verifiziert aus Live-Config-Dump + OTA vmlinux)

  • armv7 32-Bit, non-LPAE → kein KASLR (Kernel bei fester 0xc0008000 VA / 0x40080000 PA)
  • Kein ARM_SW_DOMAIN_PAN → ret2usr gangbar; CONFIG_PANIC_ON_OOPS=y (fehlgeschlagene Versuche = Neustart)
  • Kein SLAB_FREELIST_RANDOM/HARDENED, kein CONFIG_USER_NS/USERFAULTFD/NF_TABLES
  • CONFIG_MODULES=y, kein STATIC_USERMODEHELPER → modprobe_path-Überschreiben = root
  • 1 GB RAM → direkter Reclaim (nötig für Eviction) trivial erreichbar; Druck >~1 GB panikt den Kernel von selbst (unabhängiger lowmem/OOM-Bug) — Spray ≤ 900 MB halten, ~700 MB verwenden

UAPI-Eigenheiten während der PoC-Entwicklung (r26p0, _IOC_TYPE 0x80)

  • MEM_ALLOC Union ist 32 Bytes (in hat 4 × u64 inkl. extent)
  • Flags müssen BASE_MEM_PROT_GPU_RD|WR (Bits 2|3) enthalten, nicht Legacy R|W
  • Tracking-Page-mmap vor jedem Alloc erforderlich: mmap(fd, offset=3<<12, PROT_NONE)
  • JOB_SUBMIT Stride muss gleich sizeof(base_jd_atom_v2) = 48 sein (base_jd_prio/base_jd_dep_type sind u8-Typedefs)
  • JIT: MEM_JIT_INIT (nr 14, v2-Struct), Alloc/Free sind Soft-Jobs via JOB_SUBMIT (BASE_JD_REQ_SOFT_JIT_ALLOC=0x209, ...FREE=0x20a; =User-Ptr, =Anzahl)

Stufe-1-Differential (Beweis, dass der Bug feuert)

Panik tritt während der Eviction selbst auf (evictable_reclaim_scan_objects → backing_lost → Destroy-Worker) — die baumelnden Referenzen (jit_alloc[], Evict-Liste) werden durchlaufen, bevor wir jemals JIT_FREE submitten. Stufe 2 muss das Rennen gewinnen: die freigegebene kbase_va_region mit unserem eigenen MEM_ALLOC-Spray reallozieren, während der Druck noch läuft.

Artefakte

  • poc/stage2.c — Stufe-2-Exploit (Modi: step/uaf/spstep/spfree/spray/keys) — spray 700 = vollständiger Oracle-Lauf; überlebt und pausiert (kill zum Aufräumen)
  • poc/mustang_jit_uaf.c — Stufe-1-PoC (Modi: jit N / control N / pressure N)
  • poc/build.sh — zig Cross-Build (static musl armv7)
  • kernel/vmlinux — Symbole aus dem exakten OTA-Build wiederhergestellt (vmlinux-to-elf)

Build & Ausführen```

nix-shell -p zig --run 'zig cc -target arm-linux-musleabihf -static -O2 -o juaf poc/mustang_jit_uaf.c' adb push juaf /data/local/tmp/juaf && adb shell chmod 755 /data/local/tmp/juaf adb shell /data/local/tmp/juaf jit 700 # full trigger (~reboots device) adb shell /data/local/tmp/juaf control 700 # no-JIT control adb shell /data/local/tmp/juaf pressure 700 # raw memory-pressure control

root@kitploit:~
## Referenzen

- GHSL-2022-054 Advisory: https://securitylab.github.com/advisories/GHSL-2022-054_Arm_Mali/
- Mos Pixel-6-Exploit-Writeup: https://github.blog/2023-01-23-pwning-the-all-google-phone-with-a-non-google-bug/
- Fire HD 10 (trona) Präzedenzfall, gleiche Bug-Familie: ericpardee.github.io/fire-hd-ownership
- Amazon OSS-Portal: amazon.com gp/help/customer/display.html nodeId=200203720
- XDA-Unlock-Thread (tot für diese HW-Revision): xdaforums.com/t/fire-7-2019-mustang-unbrick-downgrade-unlock-root.3944365/


## Sitzung 3 Addendum (tiefe Syscall-Stamp-Untersuchung)

Gemessene Copy-Source-Tiefen (absolut vs. Syscall-Eintritt sp0; Waiter spannt -0x1d8..-0x1a8):
- sendto sockaddr @ -0xc4 | process_vm iov @ -0x104 | recvmsg iov @ -0x11c
- sendmsg iov @ -0x12c | recvmmsg iov @ -0x154 | select fds @ -0x174
- pselect6 fds @ -0x19c | **sendmmsg iov @ -0x1bc (BESTE — 0x1c vor waiter+0x00)**
- poll entries @ -0x3e0 (vollständig darunter; falsche Seite)

In dieser Sitzung ausgeschlossen:
- io_submit-Kette zu flach (~-0x130) | semtimedop: CONFIG_SYSVIPC=n (Stub)
- configfs gemountet, aber NULL Subsysteme registriert (keine mkdir-Ziele)
- /sys/kernel/debug, /config: SELinux-verweigert für Shell
- /proc/sys/kernel: getdents funktioniert (29 Einträge aufgelistet), nur pid_max ÖFFENBAR;
  kptr_restrict/hotplug/hostname/domainname-Lesezugriffe alle verweigert
- Schreibwert ist IMMER waiter+0 (Kernel-Stack-Adresse, ausführbar, Shellcode bei
  +0x1c): rb_link_node *link = node, insert_color schreibt parent-color — keine
  kontrollierter-Wert-Variante möglich ohne Tree-Field-Stamping (Lücke -0x1d8..-0x1bc)
- Double-Deref-Dispatch-Felder lesen *(waiter+0)=1, *(waiter+4/+8)=0 — BLX 1/0
  (nf_hooks, net_families, inet[6]_protos, seq_file->op alle tot)
- timer_list.function@+0xc und work_struct.func@+0xc würden *(waiter+0xc) =
  pi_tree self-ptr = AUSFÜHRBARER waiter+0xc lesen — aber kein Pfad reiht waiter+0 als
  Timer/Work ein (Link-Korruption / keine indirekten Queue-Quellen)
- Tree-Root-Nonzero (sysctl-Handler-Slot) = deterministischer Pointer-Chase durch
  .text als rb-tree; terminiert an einem Nullwort — offline-simulierbar, aber Landung
  in einem nützlichen beschreibbaren Slot ist unplausibel

Verbleibende Ansätze für Sitzung 4:
1. ioctl-Tiefenpfade: dev_ioctl ifreq-Copy (40B User-Daten) — SyS_ioctl→sock_ioctl→dev_ioctl-Kettentiefe vs. -0x1d8 messen
2. Jede andere 0x1c-tiefere Copy als sendmmsg (bisher nichts gefunden)
3. Falls Stamp-Surface-Suche fehlschlägt: Walk-Chained-Konstrukte überdenken oder
   nach beschreibbaren Zero-Called-Slot-Klassen suchen, die noch nicht aufgezählt wurden


## SITZUNG 4 — DIE ZWEI DURCHBRÜCHE

### 1. MTKs rtmutex_common.h ist das ganze Rätsel
MTK ersetzte Upstreams NULL-sicheres rt_mutex_top_waiter durch:```c
w = rb_entry(lock->waiters_leftmost, struct rt_mutex_waiter, tree_entry);
BUG_ON(w->lock != lock);   // compiled to: ldr sb,[lock+8]; ldr r3,[sb+0x1c]; cmp; bne→udf#0x12

NO NULL CHECK + BUG_ON. Jeder All-Null-Anker stirbt bei *(NULL+0x1c); Müll- Anker sterben beim udf. DER WALK ERFORDERT: lock->waiters_leftmost (lock+8) muss auf einen Fake-Waiter W (beschreibbar) zeigen, mit W->lock (+0x1c) == lock.

Walk-Ablauf vollständig kartiert (rt_mutex_adjust_prio_chain @ 0xc0189a58):

  • 9b44-9b54: Retry-Kopf; pi_blocked_on==NULL → sauberer Exit ret 0
  • 9abc-9adc: orig_waiter==NULL → pi_waiters-Checks überspringen (adjust_pi übergibt immer NULL)
  • 9b10-9b28: Prio-Check (prio==task->prio + MIN → Exit 9b58)
  • 9b2c-9b38: trylock(lock+0) — Ticket; schlägt fehl → Retry-Schleife mit Counter-Bailout (9a90-9aa8, Limit @ *(0xc11189c8))
  • 9ba4-9bc0: Deadlock-Checks
  • 9bcc-9bd8: DER BUG_ON (leftmost→W→W->lock==lock oder sterben)
  • 9bdc-9c04: Dequeue (übrig gebliebener Baum RB_CLEAR_NODE'd = LEER → sicherer Skip), Prio/Deadline-Schreiben
  • 9c04 bl: rt_mutex_enqueue → *link = waiter+0 bei lock+4 ← DER SCHREIBVORGANG
  • 9c3c+: owner==NULL → sauberer Exit-Pfad

2. Das Kernel-Stack-Adress-Leak (tötet die adressfreie Anforderung)

/proc/self/task//stat Feld 28 (kstkesp) liefert ECHTEN Kernel-SP für syscall-blockierte Threads aus SHELL-Kontext (verifiziert: Nicht-Null-Werte beobachtet).

  • Waiter blockiert in read(blocking_pipe) → stat → kstkesp
  • Stack-Basis = kstkesp & ~0x1fff (arm32 THREAD_SIZE=8192)
  • rt_waiter Abs-Adresse = Basis + festes Delta (berechenbar: sp0 = Basis+0x2000-0x48 pt_regs; Waiter = sp0-0x1d8)
  • ALLE selbstreferenziellen Stamp-Werte werden berechenbar!

Vollständiger selbstkonsistenter Stamp (nach Leak):

  • L = Waiter+0x24 (Fake-Lock IM FENSTER — alle 4 Wörter kontrollierbar)
  • iov[0].base (Waiter+0x1c Lock) = L
  • iov[0].len (Waiter+0x20 Prio) = 1 (≠139)
  • W = Waiter+0x1c; Stamp *(W+0x1c) = *(Waiter+0x38) = L (BUG_ON besteht)
  • lock+0 (Waiter+0x24) = 0; lock+4 (Waiter+0x28) = 0 (Schreibvorgang landet hier); lock+8 (Waiter+0x2c) = W; lock+0xc (Waiter+0x30) = 0 (owner NULL)

Oracle-Status

  • Crash während Walk = Walk lief (Dead-Lock-Probe: deterministischer Crash, sauberer Code)
  • Sauberer Walk + kein Schreibvorgang = trylock-fail Retry-Bailout (kptr-Anker: Laufzeit-Wort ungleich Null)
  • Alles ist jetzt deterministisch nach Pollution-Fix.

TODO für nächste Session

  1. Leak implementieren: Waiter blockiert auf Pipe, Main liest stat, berechnet Basis
  2. Selbstkonsistentes Fenster stampen, Walk auslösen → crashfreie Vollendung = Schreibvorgang bewiesen
  3. Waffenfähig machen: Schreibvorgang landet immer bei lock+4 (rb_link_node) — Lock muss im Fenster leben (einziger vollständig kontrollierter Speicher), also Zielauswahl-Recherche: entweder Called-Slot-im-Fenster-Trick finden, oder zweistufige Konstruktion.

SESSION 4 ENDZUSTAND — DIE WAND (präzise charakterisiert)

Das vollständige Bild

Der Walk feuert deterministisch (Dead-Lock-Probe: Crash jedes Mal, sauberer Code). Der Schreibvorgang kann nicht landen wegen einer dreifachen Kernel-Hardening-Koinzidenz:

  1. MTK rtmutex BUG_ON-Variante: lock+8 (leftmost) MUSS auf W zeigen mit *(W+0x1c)==lock. All-Null/Müll-Anker sterben. Kein statisches selbstreferenzielles Muster existiert (6571 Kandidaten gescannt, 0 Treffer). Laufzeit-Pointer unbekannt.
  2. Keine Kernel-Adress-Offenlegung aus Shell:
    • kstkesp auf arm32 = USER SP (task_pt_regs->ARM_sp) — nicht Kernel-Stack. TOT.
    • dmesg/pstore/pagetypeinfo/kallsyms/stack — alle verweigert.
    • kptr_restrict=1 zur Laufzeit (fops-Anker-Wörter ebenfalls Laufzeit-ungleich-Null — der kptr-Anker-Lauf endete via trylock-fail Retry-Bailout, nicht trylock-Erfolg)
  3. fops-Tabellen in rodata: trylock strex bricht ab (Session-3-Sweep-Crashes).

Das Stamp-Fenster (Waiter+0x1c..0x5b) ist der einzige kontrollierte+inhaltlich bekannte Speicher, aber seine ADRESSE ist das Unbekannte, das wir brauchen. Selbstreferenzielle Konstruktionen erfordern alle das Stempeln einer Kernel-Adresse als Konstante — zirkulär ohne Leak.

gitchw-Vergleich (warum deren ARM32-Schreibvorgang funktionierte, unserer noch nicht)

Deren 5.4-Kernel hat UPSTREAM rtmutex_top_waiter (NULL-sicher: if (!leftmost) return NULL) — Empty-Tree-Anker überleben, deren Schreibvorgang landete auf null_fops (beschreibbar auf deren Kernel). Sogar SIE stecken beim Dispatch fest ("ioctl reboot"). Mustangs 4.9.117 MTK-Tree hat die BUG_ON-Variante — Fire OS 8 Tablets (GhostLock-5.10) hatten Erfolg, weil deren 5.10-Kernel Upstream-Stil sind.

Session-4-verifizierte Fakten

  • Walk-Retry-Schleife hat einen Counter-Bailout (Limit @ *(0xc11189c8)); trylock-fail bei Laufzeit-ungleich-Null-Anker-Wörtern → sauberer Retry-Bailout-Exit (kptr-Anker-Läufe)
  • No-Requeue-Pfad (9ce4, VOLLSTÄNDIGER Walk) dereferenziert ebenfalls leftmost bei 9d64 — kein Entkommen
  • RB_CLEAR_NODE-Selbstzeiger existieren als Überbleibsel im Fenster (Waiter+0 und +0xc enthalten ihre eigenen Adressen), aber kein Check-Vergleich nutzt sie in einer Weise, die das Stempeln bekannter Adressen vermeidet
  • Echte-Mutex-Kandidaten (Chain-Mutex hat Live-Waiter = BUG_ON würde bestehen) — aber &chain_mutex ist eine Heap-Adresse, unerreichbar ohne Leak

OPTIONEN FÜR NÄCHSTE SESSION (gerankt)

  1. logcat Kernel-Pointer-Jagd: Amazon HALs/Daemons sind geschwätzig; jeder geloggte Kernel-Pointer (auch veraltet) entsperrt die Konstruktion. Günstig zu testen.
  2. /proc/net %pK-Verhalten auf DIESEM Build: manche 4.9-Trees drucken ungehashte Pointer in /proc/net/tcp,udp,unix für unprivilegierte Leser. Live testen.
  3. Thread-Exit-Pfade bei baumelndem pi_blocked_on (One-Shot, andere Derefs).
  4. Zurückgestellten kbase-JIT-Bug mit angesammeltem 4.9-Wissen erneut angehen.

SESSION 4 ADDENDUM — LEAK-JAGD: ERSCHÖPFT (definitiv)

Getestet und tot aus Shell-Domain:

  • /proc/net/{tcp,unix,packet,netlink,ptype}: %pK-gehasht zu 00000000 (kptr_restrict=1)
  • /proc/timer_list: LESBAR aber Pointer %pK-genullt (Symbole sichtbar, keine Adressen)
  • logcat: keine Kernel-Pointer in Amazon/wpa-Geschwätz
  • kstkesp (stat f28): USER SP auf arm32 (task_pt_regs->ARM_sp)
  • MTK-Knoten (/proc/ged, mtk_cmdq_debug, mtktz, ptp, chip, aed, driver/*): alle SELinux-verweigert
  • /proc/{iomem,vmstat,kmsg,keys,crypto,slabs...}: verweigert
  • /sys/kernel/notes: verweigert
  • CONFIG_VECTORS_BASE=0xffff0000 (High Vectors — NULL+0x1c faultet)
  • CONFIG_KUSER_HELPERS=y (kuser bei 0xffff0000, nicht Page 0)

SCHLUSSFOLGERUNG: GhostLock auf mustang erfordert eine Kernel-Adress-Offenlegung, die dieser Kernel der Shell-Domain nicht preisgibt. Das selbstreferenzielle Fake-Lock kann ohne sie nicht konstruiert werden.

ENTSCHEIDUNGSPUNKT

(a) Boot-deterministisches Grinding: Reboot → Stack-Adresse via Crash- Oracle kalibrieren (~20-30 Reboots), Reproduzierbarkeit verifizieren. Long Shot — Late-Boot- Thread-Stack-Allokation wahrscheinlich nicht stabil. (b) PIVOT zurück zu kbase CVE-2022-38181 mit angesammelten Assets: Exact-Build- vmlinux + vollständiger Source + Toolchain + O_SYNC-Trace-Disziplin + tiefes 4.9- Wissen. Ursprünglicher Blocker (Destroy-Worker-Panic während JIT-Eviction) ist ein Spray-Timing-Problem, jetzt besser verstanden. (c) Bei ehrlichen ~45% aufhören: Trigger bewiesen, Walk bis zur Instruktion kartiert, Schreibvorgang blockiert durch MTK BUG_ON + kein Leak.

Empfohlen: (b) — der kbase-Bug ist in dieser exakten Source verifiziert vorhanden, hatte einen funktionierenden Trigger, und sein Blocker ist mechanisch, nicht architektonisch.

SESSION 5 — STAGE 2 BEWIESEN (Option b ausgeführt)

Re-Diagnose: die "unbedingte Destroy-Panic" existierte nie

step-Modus (alloc id=1 → DONT_NEED → 700MB Druck → MEM_QUERY, KEIN free) überlebt: query=-1 (Region vom Destroy-Worker freigegeben, rbtree-sauber). Der Worker-Pfad ist byte-identisch zum legalen JIT_FREE-unter-Druck-Ablauf. Der Crash aus Session 1 war immer der JIT_FREE-Dangling-Deref; seine Log-Zeile ging verloren, weil die Panic adbd mitten im Flush tötet. Zweimal weiter verifiziert mit uaf- Modus (bloßes free → Panic, gleicher Log-Abbruch). Der GHSL-2022-054-Ablauf ist vollständig live auf diesem Build.

Vollständiges Primitiv-Inventar (Exact-vmlinux-Disassembly)

kbase_jit_free(kctx, reg) @ 0xc058495c mit vollständig kontrolliertem Fake-reg:

  • reg->cpu_alloc NULL → Backed Size 0 → Trim-Block übersprungen (0xc0584978)
  • Bin-Dekrement: kctx+0x147dd (Byte) + kctx+0x147de+bin_id (Byte)
  • mark_reclaim(reg->gpu_alloc) @ 0xc059b158: Kette K=*(gpu_alloc+0x38) → *(K+0x1429c)==0 überspringt mm-Atomics → atomic_sub nents@K+0x141c8, D=*(K+4) → atomic_sub nents@D+0x538. Mit nents=0 sind alle Schreibvorgänge No-Op-Stores (strex desselben Werts).
  • reg->flags |= 0x100000 (Schreiben in Fake, harmlos)
  • shrink_cpu_mapping beendet früh, wenn new==old (nents=0 → return)
  • list_add(gpu_alloc->evict_node, &kctx->evict_list): evict_list-Kopf @ kctx+0x1427c; schreibt in gpu_alloc+0x18/0x1c (muss beschreibbar sein)
  • WARN-Pfad (0xc0584bd4) ist nicht fatal (kein panic_on_warn) und FÄHRT FORT
  • UNLINK @ 0xc0584b08/b0c: r3=*(reg+0x3c) prev, r2=*(reg+0x38) next → *(next+4)=prev; *(prev+0)=next — zwei beliebige Write-What-Wheres, dann Relink von reg+0x38 in jit_pool_head @ kctx+0x148e8

Statische Fake-gpu_alloc-Kette (Offline-vmlinux-Scan, /tmp/opencode/scan_s.py)

9 Kandidaten; S=0xc118b7ec (xfrm-Daten, ruhend auf diesem Gerät): *(S+8)=0 (nents), *(S+0x18)=S+0x18 (leerer evict_node → kein WARN), K=*(S+0x38)=0xc118b820 → *(K+0x1429c)=0, K/D+0x141c8/+0x538 alle in beschreibbaren Daten. Oracle-Ziele vorbereitet: init_uts_ns.name.nodename=0xc110d561 ("(none)", lesbar via uname), Scratch P=0xc118bd58 (xfrm-Nullen). S=0xc111cba4 (tracepoint-benachbart) vermeiden. CONFIG_DEBUG_RODATA=y → alle Schreib- Ziele müssen in .data/.bss sein (bss 0xc11d9000-0xc12d9000).

Spray-Engineering (was funktionierte, was nicht)

  • add_key (CONFIG_KEYS=y): SELinux-verweigert für Shell. Tot.
  • setxattr-Value-Buffer: kvmalloc(96)+copy_from_user passiert VOR dem SELinux-Check → Alloc-Dance ist SELinux-sicher, selbst wenn der Call fehlschlägt; transient (am Syscall-Ende freigegeben), Bytes bleiben bei +4..95 erhalten (Freelist-Ptr überschreibt +0..3 = rblink, von kbase_jit_free ungenutzt)
  • kbase_va_region selbst: kzalloc(72) → kmalloc-96! MEM_ALLOC(va=0x40, commit=0x10) legt NUR die Region in kmalloc-96 (phy alloc → 384) → deterministischer Reclaim-Typ. Ein Real-Region-Opfer lässt kbase_jit_free durch vollständig legalen Zustand laufen (leerer jit_node → Self-Unlink).
  • Sequenzieller Post-Druck-Spray: verfehlt IMMER — der Worker gibt den Slot mitten im Druck in partielle Slabs frei (SLUB: Free in nicht-aktiven Slab ≠ cpu Freelist); unter Druck scheitern unsere Allocs → Null-Netto-Volumen → keine Rotation
  • Gepinnte Sprayer + Caps: verfehlen weiterhin (512-Cap erschöpft vor Eviction; Worker kann auf beliebiger CPU laufen)
  • GEWINNER: commit_pages=0-Spray — keine physischen Pages → MEM_ALLOCs gelingen durch den gesamten Druck-Sturm → ~6000 Netto-Allokationen → Partial-List- Rotation garantiert. 8 Threads (2/CPU, CPUs 0-3 hartkodiert — /proc/cpuinfo ist für Shell auf 1 Kern gefiltert, Cpus_allowed_list verwenden) + Druck-Kind auf CPU0 gepinnt + 16-Alloc-Retention-Batch nach Join.
  • query(jit_va)-Falle: nach Reclaim nutzen Spray-Regionen die freigegebene VA in der Custom-Zone wieder → query=0 ist mehrdeutig (Live-Original vs. Spray-deckt-VA ab)

ORACLE-TREFFER — maschinenverifizierte Umleitung

spray 700-Lauf 2026-09-11: 5895 Regionen während Druck gesprayt, JIT_FREE auf baumelndem id=1 vollendet auf einer zurückgewonnenen Region, dann JIT_ALLOC(0x40, bin 0) durchlief jit_pool_head und lieferte die VA der gesprayten Region #4251 (0x142701000) — genau die Region, die der Dangling-Pointer konsumierte. Prozess-Kill danach: kctx-Teardown sauber, kein Crash. Stage 2 vollständig: deterministische UAF-Umleitung mit kontrolliertem Objekttyp + Inhalt.

Stage-3-Plan (Raw-Byte-Unlink)

Region-Typ-Reclaim liefert Überleben des legalen Tanzes, aber jit_node ist INIT'd self → kein Unlink-Primitiv. Brauchen Raw-Bytes bei +0x38/+0x3c:

  1. xattr-Stamping: abwechselnd Region-Alloc-Bursts (Netto-Volumen → Slab- Rotation) mit xattr-Stürmen (jeden Head-Slot stempeln, Bytes bleiben nach Free erhalten) → ruhiges Fenster → Deref
  2. oder gepinnte sendmsg-cmsgs (optmem_max=10240 → ~106 × 96B gehalten)
  3. dann: W1 *(N+4)=P mit P=Userland-Shellcode-Page (kein PAN!) — Kandidaten: const fops sind .rodata (DEBUG_RODATA) → Ziel nicht-const fn ptr in .data, oder binfmt formats-Listenkopf, oder sysctl proc_handler (Tabellen-Beschreibbarkeit verifizieren). Fallback: modprobe_path via byte-verkettete Schreibvorgänge (Werte müssen beschreibbare Adressen sein — pointer-förmige Ziele verwenden)
  4. kein KASLR + Exact-vmlinux: prepare_kernel_cred 0xc0149e3c, commit_creds 0xc014993c

SESSION 5B — STAGE 3: Waffe gebaut, Reclaim-Race noch nicht gewonnen

Erledigt

  • Stage-3-Waffe vollständig & vorbereitet (poc/stage3.c):
    • Ziel: kern_table[pid_max].proc_handler @ 0xc1113f40 (beschreibbar .data, verifiziert via String-Pointer-Scan + handler == proc_dointvec_minmax)
    • N = Shellcode-Einstieg 0x11111112 (mmap 0x11111000; W1 überschreibt Einstieg+4, übersprungen durch b +8; W2 schreibt N bei P = Handler-Feld)
    • arm32 Ring0-Shellcode handkodiert: prepare_kernel_cred(0) + commit_creds + ret 0; Trigger = read /proc/sys/kernel/pid_max (aus Shell lesbar); läuft im eigenen Task-Kontext → Creds gelten für uns
    • Benign-Oracle-Modus schreibt uts nodename (0xc110d561, unaligned ok)
  • Spray-Primitiv-Auswahl:
    • NETLINK_USERSOCK sendmsg-Pins (msg_control kmalloc-96-Kopie, gehalten während blockiert, nie geparst): SELinux-verweigert (Socket-Create EACCES)
    • unix/UDP sendmsg: cmsg-Parsing vergiftet Payload-Bytes ✗
    • inotify-Events: inotify_handle_event kmalloct name_len+0x1d, Name-Bytes (vollständig kontrolliert, NUL/Slash-freie Einschränkung) bei event+0x1c; name_len=60 → kmalloc-96; in Queue → gehalten; 4 Instanzen → 4 Events pro Rename; SELinux-OK aus Shell. Fake NUL-frei neu entworfen: cpu_alloc zeigt auf S (nents@S+8 = 0 → gleiche Semantik wie NULL)
  • Mechanische Kette end-to-end validiert (drain4, No-Eviction-Lauf): 20K gedrainte Events + 13.5K Multi-CPU-Trailing-Renames + JIT_FREE + Oracle + Pause, alles sauber. O_SYNC-Log (/data/local/tmp/s3.log) überlebt Panics — exakte Crash-Punkt-Forensik.

Reclaim-Versuche auf dem freigegebenen Slot (bisher alle verfehlt)

VarianteErgebnis
gleichzeitige Rename-Sprayer während Sturm

Arbeitshypothese: Sturm-Müll-Race — zwischen dem Freigeben des Slots durch den Destroy-Worker (mitten im Sturm) und Child-Kill/Ruhe nimmt Rest-Reclaim- Aktivität den einzigen freien Slot des Opfer-Slabs mit Nicht-Payload- Bytes. Region-Spray (Stage 2) gewinnt, weil es kontinuierlich WÄHREND des Sturms alloziert; Renames können das nicht.

Aufgetretene Fallstricke

  • Spray-Toggle-Bug: Rename-Quelle muss der Payload-Name sein (war Temp- Name → ENOENT nach 2 Wellen → nur 512 Events überhaupt)
  • Geräte-Hostname ist "localhost"/variiert — Oracle vergleicht vor/nach
  • pausiertes st3 + pkill → Gerät WEDGE (Teardown mit 33K Events?!) — pausierte Prozesse nur via Reboot killen; zweiter Hard-Wedge der Session
  • /proc/cpuinfo zeigt 1 CPU für Shell; Cpus_allowed_list verwenden

Nächste Schritte (gerankt)

  1. drain4 @ 500MB (Eviction-Schwelle dort bestätigt), 1ms Poll, sofortiger Kill, 4-CPU-Trailing × 3200 — Sturm-Fenster verkleinern
  2. xattr-Stamp-Churn (setxattr Alloc-Copy passiert VOR SELinux-Check — SELinux-sicher) gleichzeitig mit Sturm + Region-Rotation, End-Mit-Stamp
  3. Region-Reclaim akzeptieren (bewiesen) + ein Second-Stage-Primitiv auf dem Region-Opfer-Zustand finden (Double-jit_free-Analyse bisher negativ)

SESSION 5C — der Blocker, präzise charakterisiert

Empirische Ergebnisse dieser Session

  • drain4@500 (1ms Poll, sofortiger Kill, +4.5K Renames): weiterhin Crash beim Deref
  • Trailing mit Kill überlappen (drain5): crasht FRÜHER (Renames während Kill-Recovery-Sturm treffen einen System-Level-Fault) — Überlappung aufgegeben
  • ISOLIERENDES EXPERIMENT (iso-Modus): identisches Timing, Trailing mit commit-0-REGIONEN + Stage-2-Pool-Reuse-Oracle → ORACLE-TREFFER → Timing/Erreichbarkeit sind IN ORDNUNG; Events sind das Problem
  • masken-zyklierte Events (MOVED_TO/CREATE/DELETE-Rotation zur Umgehung von inotify_merge): weiterhin Crash beim Deref
  • CONFIG_MEMCG=n → Events und Regionen teilen EINEN kmalloc-96 (memcg-Theorie tot); inotify_merge vergleicht auch Namen (Merge-Theorie tot — unsere toggelnden Namen wurden nie gemerged; Events waren die ganze Zeit in Queue und gehalten)
  • /proc/slabinfo fehlt; /proc/self/pagemap lesbar aber PFN-genullt (Post-4.0-Masking, kein CAP_SYS_ADMIN)

DER TATSÄCHLICHE BLOCKER (zwei Teile, beide bewiesen)

  1. Soft-Job-Finish läuft im kbase Job-Scheduler-WORKER-Kontext (jd_run_atom ← js dispatch, mali_kbase_jd.c:81-112/677), nicht inline im Submit-ioctl → current->mm ist das eines Kernel-Threads → das elegante "die Pointer des Fakes in unser eigenes Userspace-mmap zeigen"-Design (kein PAN!) FAULTET nichtdeterministisch. 5/5 Crashes mit ansonsten perfektem Fake.
  2. Daher muss gpu_alloc auf KERNEL-Speicher zeigen mit einer überlebbaren Laufzeit-Kette: K=*(S+0x38) lesbar, *(K+0x1429c)==0 zur Laufzeit (überspringt mm-Atomics), K+0x141c8 beschreibbar, D=*(K+4) → D+0x538 beschreibbar, nents *(S+8) bevorzugt 0. Die 9 Offline-S-Kandidaten wurden gegen DATEI-Bytes validiert — Laufzeit-Drift (xfrm/tracepoint-Init) macht sie unverifiziert. Eine falsche Kette = Crash = Reboot (~3 min Zyklus).

Session-6-Pläne (beide vollständig spezifiziert)

A. Physmap-Spray-Fake (ret2dir, klassisch arm32 ohne PAN): ~450MB User-Pages sprayen, jede enthält das Fake-Muster gebacken für EINE geratene Adresse G (G&0xfff = 0x141 für NUL-freie Name-Bytes; S=G; K=G-0x141b4 so dass K+4 in-Page landet; K+0x141c8/+0x1429c → G+0x10/+0xd4 in-Page; D=G+0x300; verirrte sub-0-Stores treffen zufälliges gemapptes RAM - harmlos mit nents=0). Spray dient gleichzeitig als Eviction-Druck (dirty anon = unevictable → nur ~100-200MB extra nötig). Chancen ≈ 45% (Page-Treffer) × ~50% (fremdes K+0x1429c-Wort ist Null... wenn K+0x1429c laut Layout oben in-Page bleibt, Chancen = nur Page-Treffer). Fehlschlag = Crash = Reboot, Retry. B. Die 9 statischen S-Kandidaten brute-forcen (xfrm 0xc118b7ec zuerst, tracepoint-benachbart 0xc111cba4 zweitens...): 1 Reboot pro Kandidat, Benign-Oracle-Payload zuerst, Waffe bei Treffer. C. pagemap-basiertes exaktes G (tot: PFNs maskiert) — nicht erneut angehen.

SESSION 5D — Physmap-Fake gebaut; G-Sweep 0/3; Confounds eliminiert

Diese Session etabliert (alles binär/geräte-verifiziert)

  • Cache-Identität BESTÄTIGT gleich: Region = kmem_cache_alloc_trace( kmalloc_caches[7], GFP|0x8000, 0x48) [kbase_alloc_free_region-Disasm]; Event = __kmalloc(89, GFP) → kmalloc-96. Events und Regionen KÖNNEN den Cache des Opfers teilen. (MEMCG aus; einzelnes Cache-Set.)
  • inotify-Queue: ≥5000 Events gehalten, kein Overflow, kein Merge-Kollaps (qmeas 1000 & 5000 Läufe) — der Event-Spray persistiert
  • iso2 (Physmap-Spray + Region-Trailing + Oracle): TREFFER — der Physmap- Spray bricht Region-Reclaim NICHT; Maschinerie solide
  • Events vs. Regionen Reclaim: Regionen 3/3 (iso, iso2, Stage-2), Events 0/10 ABER die 3 pmap-Läufe sind durch G-Fehlschläge bei je 0.3-0.45 Chancen erklärt (P(3 Fehlschläge|Events-funktionieren) ≈ 0.2-0.3 — nicht schlüssig)
  • Mix-Modus confounded: 480MB Spray erstickt Post-Kill-Renames (+0); 350MB OK (+4452); spinnende fehlgeschlagene Rename-Threads stören auch Region- Reclaim (Mix crashte, iso2 sauber)
  • query_commit liefert -1 auch bei EINVAL — instrumentiert; EINVAL beobachtet = rbtree-Lookup-Miss = tatsächlich freigegeben ✓ (kein False Positive)

Aktuelles pmap-Design (in stage3.c, Modus pmap/mix/iso2)

  • G in jede gesprayte Page gebacken (Offset 0x2a4): nents@+0x2ac=0, evict self@+0x2bc/0x2c0, K=G+0x100@+0x2dc, D=G+0x200@+0x3a8; K+0x141c8/-0x1429c landen ~20 Pages höher (sub-0-Store harmlos / Read muss 0-oder-gültig sein). PM_SPRAY_MB 350, G-Sweep versucht: c2a412a4, c2f4b2a4, c2a7d2a4 — alle crashen beim Deref
  • Physmap-Bereichs-Sanity: RAM 1GB → Physmap ~0xc0000000-0xc3fffffff; MTK-Carveouts (GPU/M4U/secure) können Chunks belegen — G-Landminen

Session-6-TODO (gerankt)

  1. Vollständige Kernel-Source extrahieren (2.2GB Tarball bei ~/Desktop/amazon-mustang/ — platform.tar): arch/arm + mm/ + drivers/of + MTK-Reserve-Mappings holen → Carveout-Map berechnen → G in verifizierte-RAM-Physmap-Subranges zielen; auch kmalloc- Cache-Geometrie verifizieren (ARCH_KMALLOC_MINALIGN!) und das 0x8000-GFP-Bit
  2. G-Sweep mit platzierungsinformierten Vermutungen (mehrere Reboots, Spray- Größe variieren zur Dekorrelation)
  3. Falls G-Sweep erschöpft: Multi-G-Payload oder S-Kandidaten aus laufzeit-plausiblen Statics erneut erwägen (uts-benachbarte Pointer-Felder scheiterten: NULL-K)

SESSION 6 — zram-Entdeckung, Source-Extraktion, Event-Frage noch offen### Vollständiger Kernel-Quellcode jetzt extrahiert

/tmp/opencode/ksrc2/kernel/mediatek/mt8163/4.9/ (arch/arm inkl. mustang.dtsi, mm/, fs/eventpoll.c, fs/notify) aus ksrc/platform.tar. Erkenntnisse:

  • 0x8000 GFP-Bit = ___GFP_ZERO (nur kzalloc; kein Cache-Split)
  • kmalloc-96 ist ein echter 96-Byte-Cache (kein HWCACHE_ALIGN auf kmalloc-Caches)
  • mustang.dtsi: memory node 0x40000000/512MB — erweitert durch Preloader (Gerät zeigt MemTotal 977MB); CONFIG_VMSPLIT_3G, HIGHMEM=y
  • zram0 AKTIV (SwapCached > 0) → "dirty anon = unevictable" war FALSCH: der physmap-Spray wird unter Druck ausgelagert → G-Alias wird stale → physmap_retouch() nach dem Kill hinzugefügt (faultet alle Spray-Seiten vor dem Trailing/Deref wieder ein)

Läufe dieser Session (alle O_SYNC geloggt, ~6 Reboots)

Urteil zu Events (Bayesianisch, ehrlich)

Regions reclaimen: 3/3. Events: 0/~12 Versuche inklusive 28K exklusiver Allokationen mit Vorsprung und konstruktionskorrektem Fake. Wenn Events mit p_hit(G)≈0.35 reclaimen, fünf pmap-Fehlschläge ≈ 11.6% — möglich, aber nun unwahrscheinlich (~10-15%). Entweder können Events diesen Slot strukturell nicht belegen (Grund unbekannt — gleicher Cache, gleicher Kontext, gleiches Timing) oder unsere G-Vermutungen treffen systematisch daneben (Highmem-Grenzverschiebung, Allocator-Platzierung).

Session-7-Entscheidungsbaum

  1. G zuerst klären (billig, kein Exploit): vorübergehend den ISO2-Flow instrumentieren — Region-Trailing + Oracle — aber die PAYLOAD-Event zu einem physmap-Fake machen und prüfen, ob IRGENDEIN G in einem gesweepten Bereich eine Nodename-Änderung ohne konkurrierende Regions erzeugt (reines pmap, G-Sweep über ~0xc1500000-0xc2a00000 Lowmem-Zentrum, 1 G pro Reboot, 4-5 Reboots)
  2. Falls G-Sweep erschöpft → Events für tot erklärt → Jagd auf alternative Raw-Byte-kmalloc-96-Allokatoren, die von der Shell erreichbar sind (Audit: seq_file, tty ldisc, fdtable, sk_filter (blockiert: Code-Feld bei +0x38), netlink nlmsg (skb ✗), keys (verweigert)) — oder zweistufige Region- Primitive erneut prüfen (Analyse bisher negativ)
  3. UART/ramoops-Unlock via Root später erwägen; nicht weiter verfolgen

SESSION 7 — cmdline-Bomben; Event-Rätsel nun präzise eingegrenzt

mustang_defconfig CONFIG_CMDLINE (Ground Truth für Platzierung):

vmalloc=496M slub_max_order=0 slub_debug=O loglevel=8 initcall_debug

  1. vmalloc=496M → physmap = 0xc0008000..~0xc2080000 NUR (untere 520MB des RAM) — ALLE früheren G-Vermutungen (0xc2a4xxxx+) lagen im VMALLOC-RAUM. Jede "G-Miss"-Schlussfolgerung aus Sessions 5D/6 ist ungültig; die Crash-Interpretation bleibt bestehen, aber der Sweep zielte auf die falsche Map.
  2. slub_max_order=0: alle Slab-Seiten Order-0
  3. KMALLOC_MIN_SIZE = ARCH_KMALLOC_MINALIGN = 64 (L1_CACHE_SHIFT 6) → kmalloc_index()-Sonderfälle für 96/192 sind DEAKTIVIERT → Region kzalloc(0x48=72) → caches[7]; Event __kmalloc(89) → caches[7] (Disasm + include/linux/slab.h:287 verifiziert) — BEIDE im zusammengeführten 128-Byte-"kmalloc-128/96"-Cache. Cache-Identität: ERNEUT BESTÄTIGT gleich.
  4. zram aktiv → ersetzte Anon-physmap-Spray durch kbm_spray: 160 × 2MB kbase MEM_ALLOC-Regions (GFP_KERNEL → ZONE_NORMAL → nur Lowmem, gepinnt → zram-immun), Muster via CPU-mmap geschrieben — korrekter Bereich, ~65% Lowmem-Abdeckung

Läufe (O_SYNC geloggt)

  • kbm + G=0xc16412a4: Crash beim Deref (+4831 Renames)
  • kbm + G=0xc1c4b2a4 @200MB: KEINE Eviction (query=16 — Druck- Kalibrierung variiert mit gepinntem Spray; legal frei, überlebt)
  • kbm + G=0xc1c4b2a4 @400MB: Eviction ✓, +4053 Renames, Crash beim Deref
  • Gültig-Bereich-G-Bilanz: 0/2. Wenn Events mit ~65% Abdeckung funktionieren: P(2 Fehlschläge) ≈ 12%. Frage noch offen, aber enger denn je.

Die Frage, finale Form

Regions belegen den Opfer-Slot 3/3; Events 0/13. Gleicher Cache (bewiesen auf Quellcode- + Disasm-Ebene), gleicher Prozesskontext, gleiche gepinnte CPUs, gleiches Post-Kill-Timing, Tausende Allokationen mit exklusivem Vorsprung. Mechanismus unbekannt. Verbleibende Verdächtige: Allokationsraten-/Frequenz- Korrelation mit Partial-List-Rotation (Region-ioctls ~1ms auseinander vs. Event-Renames ~100µs auseinander — entgegengesetzte Richtungen?), oder SLUB-Freelist- Ordering-Details unter slub_max_order=0, die... unklar.

Session-8 TODO

  1. Instrumentengrad-Experiment: ZWEI Event-Payload-Varianten mit UNTERSCHIEDLICHEN N/P-Werten alternierend (zwei Namenssätze) — falls der Nodename jemals wechselt, ist der LETZTE Gewinner identifiziert; G sweepen in [0xc1200000..0xc2000000] mit kbm-Spray, 3-4 Reboots Budget
  2. Falls immer noch 0/N: Events aufgeben. Alternativen gerankt: a. pipe_buf-Arrays via F_SETPIPE_SZ(4096 → 1 buf? nein — 16 bufs = kcalloc(16, 28)=448→512 ✗) — tot b. fs/notify + fs auf andere namens-/datentragende kmalloc-128- Objekte auditieren (fanotify-Events? mq aus; fanotify braucht Gruppen...) c. seq_file-Puffer (kmalloc(PAGE_SIZE) ✗) d. sock-Filter (Code-Feld-Kollision bei +0x38 ✗) e. den Region-Typ-Reclaim akzeptieren + einen ZWEITEN Bug/Technik anhängen
  3. Erneut untersuchen, WARUM Regions gewinnen — vielleicht via mehrerer jit-ids instrumentieren: N dangling Slots, Region-vs-Event-Race pro Slot, Oracle erkennt, welcher Spray welchen Slot belegte → statistischer Fingerabdruck des Mechanismus

SESSION 8 — ARBITRÄRER WRITE AUF DEM GERÄT ERREICHT; Dispatch-Rätsel bleibt

DER MEILENSTEIN```

[+] uname.nodename="X?lhost" (was "localhost") <<< ORACLE HIT

root@kitploit:~
**Die vollständige Raw-Byte-Kette funktioniert auf dem Live-Gerät**: Das Event reklamiert den
freigegebenen Region-Slot → kbase_jit_free dereferenziert unser Fake (S=physmap-Seite aus
dem kbm-Spray, G=0xc154b2a4) → der Unlink führt unsere beiden Writes aus.
Wiederholt verifiziert mit der benignen Payload (nodename-Write).

### Sitzungskette der Entdeckungen
1. kbm-Seiten waren GFP_HIGHUSER → HIGHMEM, unsichtbar für physmap
   (mali_kbase_mem_pool.c:164!) — behoben durch Zonelist-Spill: 260 × 2MB
   Spray > highmem-free → Überschuss landet in ZONE_NORMAL (physmap)
2. Erste Waffenversuche stürzten ab: W1-Ziel N+4 war eine USER-Seite —
   Unlink läuft im kworker-Kontext (kein mm) → Fault. Behoben durch Einbacken des
   Ring-0-Shellcodes IN das physmap-Muster bei page+0x600 (Direct Map RWX auf
   arm32 non-LPAE) — kernel-residenter Code, kein ret2usr nötig
3. ctl_table-Offset-Bug: proc_handler liegt bei entry+0x14, nicht +0x18 (der
   ursprüngliche Scan hatte es richtig; mein Define war falsch) — schrieb extra1
4. Überdruck-Regression gefunden & zurückgerollt: kid-Budget 20×100MB +
   nachlaufende 10s brachen die Reclaim; die funktionierende Konfiguration ist 2 kids/200MB +
   5s/+3200 nachlaufend (benigner Treffer 1/1 nach Rollback)
5. **diag2: W2 → &pid_max global (0xc1114d7c) → Read liefert unseren Wert
   (-1055861411 = 0xc110d55d als int32) — Write + Readback BEWIESEN**

### Das verbleibende Rätsel (ein Experiment von der Lösung entfernt)
diag1 mit der KORREKTEN Handler-Adresse (0xc1113f3c): W1 feuert (nodename
ändert sich), W2 muss ausgeführt worden sein (nächste Instruktion) — dennoch liefern pid_max-Reads
weiterhin saubere Werte → das Handler-Feld, das wir schreiben, ist nicht das, über das
das Inode dispatcht. diag3 (in Warteschlange; benötigt einen Hit-Boot): W2 →
entry->data FIELD (0xc1113f2c) zeigt auf nodename — wenn der Read dann
nodename-Bytes-als-int zeigt, ist unser entry LIVE und nur der Handler-
Offset ist irgendwie falsch; wenn unbeeinflusst, verwendet das Inode eine Shadow-Table-
Kopie und wir jagen die Live-Version.

### Hit-Rate-Realität
Pro-Boot-Münzwurf (~25-40%), geclustert; mehrere Safe-Miss/Crash-Boots
in Folge sind normal. Ungefähr 1 von 3-4 Boots ist ein Hit. Behalte die funktionierende
Konfiguration EXAKT bei (2 kids, 5s nachlaufend, 260-Region-kbm, G=0xc154b2a4).

### Session-9 TODO
1. diag3 auf einem Hit-Boot abschließen (rollen bis "W1 FIRED")
2. Falls entry live: Handler-Offset empirisch neu prüfen (schreibe
   proc_dostrings Adresse als Handler via... N muss einem nützlichen
   Wert entsprechen — nutze den Unlink, um stattdessen entry->data zu schreiben und zu pivotieren: z. B.
   data=selinux_enforcing-benachbart...)
3. Falls Shadow-Table: die Live-Version lokalisieren — kallsyms hat keine Datensymbole;
   Kandidaten: /proc/sys-Verhalten scannen, oder eine zweite ctl_table-
   Region über das Header-Listen-Muster in .data finden (0x20-Schritt-Einträge
   mit handler=proc_dointvec_minmax und maxlen=4 — ALLE aufzählen und
   jeden diag-schreiben)
4. Alternative Zielklasse, die Dispatch vollständig vermeidet: .data-
   Funktionszeiger, die von shell-erreichbaren Pfaden aufgerufen werden (Audit nötig)
5. Das Write-Primitiv selbst ist FERTIG — jedes zuverlässige Kernel-Adress-
   Ziel genügt jetzt für Root

## SESSION 9 — nf-WEAPON: reclaim+unlink+G-hit IN-WEAPON BEWIESEN; nur der Hook-Walk bleibt

### Das neue Trigger-Design (ersetzt den sysctl-Handler-Pfad vollständig)
Die Idee des Users in Kernel-Speicher übersetzt: keine SUID-Datei (System ist
dm-verity RO; Primitiv schreibt Kernel-RAM). Stattdessen: **Fake-Netfilter-
Hook**. Dieser Kernel hat den Android-common-Backport der NEUEN
nf_hook_entries-API, aber als VERKETTETE LISTE implementiert (verifiziert durch
Disasm von nf_hook_slow + Helper 0xc09897d4):
- `__ip_local_out(net, sk, skb)` lädt die Entries-ZELLE aus
  **[net+0x58c]**, speichert in state+0x1c, ruft nf_hook_slow auf
- Walk: `entry = *cell`; while(entry){ if (state->[4] <= entry->[0x20])
  call entry->[0xc](entry->[0x14], skb, state); entry = entry->[0]; }
  — d. h. **fn@entry+0x0c, priv@entry+0x14, priority@entry+0x20,
  next@entry+0x00**; state+4 = INT_MIN-Schwelle (passiert immer)
- init_net = **0xc1104548** (CONFIG_NET_NS=n → sock_net() inlined die
  Konstante; 6678 movw/movt-Referenzen, Histogramm-Champion; kreuzbestätigt durch
  nf_hook_slows eigenes Literal). ZIEL: **[init_net+0x58c] = 0xc1104ad4**
- LOCAL_OUT-Hook läuft im Prozesskontext des SENDERS → unser hookfn's
  commit_creds(prepare_kernel_cred(0)) rootet den Prozess, der das
  Paket gesendet hat. Trigger = sendto(127.0.0.1:9) UDP.

### nf-Modus-Layout (poc/stage3.c, Modus `nf 200`)
- kbm-Musterseiten (seiten-relativ, einzige Quelle der Wahrheit — die alte
  Waffe hatte DREI Bugs, jetzt behoben: proc_handler@+0x14 nicht +0x18; W1-
  Ziel muss KERNEL-Speicher sein (kworker-Kontext, kein mm); eingebackener Code bei
  page+0x600 vs. entry G+0x600=page+0x8a4-Mismatch):
  - +0x2ac/+0x2bc/+0x2c0/+0x2dc/+0x3a8: Fake-phy-alloc-Kette (unverändert)
  - +0x600: nf_code hookfn (Marker-Store + prepare_kernel_cred +
    commit_creds + return NF_ACCEPT(1))
  - +0x700: Fake-entry {next=0, fn=PM_PAGE+0x600, priv=0, prio=0x100}
  - +0x740: cell → PM_PAGE+0x700
- Payload: N = PM_PAGE+0x740 (0xc154b740), P = 0xc1104ad4
  → W1: *(cell+4)=P (landet in unserer Seite), W2: *(init_net+0x58c)=cell

### SELBSTDIAGNOSTIZIERENDE Instrumentierung (kbm_scan_for)
Die kbm-CPU-Mappings werden beibehalten; nach dem Free scannen wir jede gesprayte
Seite nach einem bekannten Wort:
- scan(HOOKS_PTR_ADDR) bei page+0x744 → beweist Reclaim + Unlink + offenbart,
  welche phys-Seite die G-Vermutung stützt
- scan(0x600d600d) bei page+0x7f0 → beweist, dass die hookfn AUSGEFÜHRT wurde
  (nf_code schreibt diesen Marker als seine 2. Aktion)

### DER RUN, DER ZÄHLT (2026-09-11, späte Session 9)```
[+] W1 CONFIRMED: region 135 page+0x185000 <- 0xc1104ad4 (reclaim + G hit!)
[+] nf trigger done, uid=2000 euid=2000

Die vollständige Waffenkette feuerte bei einem Live-Boot: Das Event reklamierte den Slot, das Fake lief, der Unlink wurde ausgeführt, die G-Guess-Seite (0xc154b000) war tatsächlich unsere (Region 135 Seite 389). W2 = *(0xc1104ad4)=cell ist die benachbarte Instruktion — sie muss ausgeführt worden sein. Dennoch hat uns UDP sendto nicht gerootet → der Fehler liegt INNERHALB des Hook-Pfads: Walk-Semantik, [state+0x1c]-Plumbing, Prioritätsvergleich oder die Entry-Felder. (Das Marker-Experiment zur Unterscheidung hookfn-ran-vs-not wurde hinzugefügt; nur Crash-Boots vor Session-Ende — noch keine sauberen Daten.)

Hit-Rate- / Boot-State-Erkenntnisse (hart erarbeitet)

  • FUNKTIONIERENDE KONFIG (nicht anfassen): 2 Kids × 100MB gestufter Druck, nachlaufend 100×50ms/+3200 Renames, 260×2MB kbm-Spray, G=0xc154b2a4, Pre-Drain ~5000 Renames
  • Überdruck (20 Kids / 10s nachlaufend) BRICHT das Reclaim — zurückgerollt
  • Boot-Settle ist wichtig: Läufe, die direkt nach boot_completed gestartet werden, konkurrieren mit den Startup-Allokationen des Systems → kalte Streaks; 60-90s nach dem Boot settlen lassen, bevor man läuft
  • „W1 hat nicht gefeuert" (nodename-Check) ist BEDEUTUNGSLOS für nf-Payload — W1 schreibt in unsere Seite; stattdessen kbm_scan_for verwenden
  • Crash-bei-Free-Boots ≈ Garbage-Slot oder G-Miss-Konvertierungen; benignes Control (pmap 200) ist der Umgebungs-Sanity-Check (4/4 Treffer wenn warm; Crash-Miss wenn kalt)
  • /data/local/tmp/.w*-Verzeichnisse werden beim Run-Start bereinigt (angesammelte Verzeichnisse degradieren das Reclaim)

Session-10 TODO (Entscheidungsbaum, in Reihenfolge)

  1. nf 200 auf settle-verzögerten Boots laufen lassen, bis die W1-CONFIRMED-Zeile erscheint, dann die MARKER-Zeile lesen: a. Marker VORHANDEN, uid!=0 → die Creds des Shellcodes sind fehlgeschlagen (prüfe prepare_kernel_cred/commit_creds-Adressen; blx-Encodings) b. Marker FEHLT → der Walk hat uns nie aufgerufen: mit einem ZWEITEN Marker verifizieren, geschrieben von... nächste Diagnostik: hookfn, der NUR den Marker schreibt und 1 zurückgibt (keine Creds) — wenn immer noch fehlend:
    • unsere tatsächlichen Entry-Bytes über das CPU-Mapping direkt vor dem Trigger dumpen (sie gehören uns zum Lesen!)
    • prüfen, ob [init_net+0x58c] überhaupt konsultiert wird: stattdessen den Write nutzen, um etwas Beobachtbares zu korrumpieren (z.B. ihn auf eine Cell zeigen lassen, deren *cell = Entry mit fn = eine Kernel-Funktion wie kfree → sofortiger Crash beim Trigger = Feld WIRD konsultiert)
    • 0x58c-Offset erneut verifizieren: vielleicht liegt hooks_ipv4[NF_INET_LOCAL_OUT] an einem anderen Index (NF_INET_POST_ROUTING=4?)
  2. Wenn der Walk uns aufruft: Creds fixen → root → dann der Plan des Nutzers: setenforce 0; cp /system/bin/sh /data/local/tmp/su; chown root; chmod 6755; ls -la verifizieren; Marker-Dateien hinterlassen
  3. Persistenz (post-root): Boot-Image-Patch via /dev/block/by-name/boot
    • dm-verity deaktivieren, oder Magisk-Style; su nur auf /data ist uid0-im- Shell-Domain nach Reboot (SELinux wieder enforcing) — setenforce 0 ist nur zur Laufzeit
  4. Cleanup-Hinweise: pausierte st3-Prozesse haben korrupten kctx-State — nur via Reboot killen; nf-Hijack bricht LOCAL_OUT-Hooks für den gesamten Traffic — nach root rebooten zum Wiederherstellen

Heutige Asset-Ergänzungen

  • poc/stage3.c-Modi: pin/root/drain{,2,3,4,5}/iso — volle Waffe + Oracle + Isolation-Harness, O_SYNC-Crash-Point-Forensik
  • Userland-Fake-Infrastruktur (ufake_prep) — BEHALTEN, aber nur nutzbar, wenn jemals ein Context-Inline-Deref-Pfad gefunden wird
  • tools/: kdis/scan_s/resolve/dumpb/findsysctl Offline-vmlinux-Analyse

SESSION 10 — ROOT ERREICHT (2026-09-11)

Die drei Bugs, die die nf-Waffe blockierten, alle behoben

  1. Falsches init_net: 0xc1104548 ist __stack_chk_guard (das movw/movt- Histogramm war durch Stack-Canary-Loads verunreinigt — 2025 baute den ganzen nf-Plan darauf auf). Echtes init_net = 0xc1185040 (bestätigt: ip_send_skb(net,...) aufgerufen mit diesem Literal; ~994 Refs alle im Net-Stack). IPv4-LOCAL_OUT-Cell = init_net+0x58c = 0xc11855cc.
  2. Double-Deref-Bug: nf_iterate behandelt [init_net+0x58c] als den nf_hook_ops-Pointer selbst — es liest fn@+0xc, priv@+0x14, prio@+0x20 direkt aus diesem Wert. Der Fake-Entry aus Session 9 lag bei PM_PAGE+0x700, wobei die Cell darauf zeigte (unbenutzte next/-Felder an der Cell → → Crash). Der Fake-Entry MUSS (0xc154b740) liegen. Mit dieser Korrektur wurde der Hook-Aufruf bewiesen (-Modus = SAFE_FN verarbeitet alle 200 Sendtos sauber).

Die SELinux-Mauer und der 2-Paket-Bypass

commit_creds(prepare_kernel_cred(0)) / override_creds(&init_cred) gibt uid 0, landet aber in der kernel-SELinux-SID, der diese Fire-OS-Policy nicht erlaubt, nach /data oder /sys/fs/selinux/enforce zu schreiben (verifiziert: EACCES). Echte init-SID (7) ebenfalls verweigert (Fake-struct cred-Test). enforcing_setup ist __init (freigegeben → Crash). mark_reclaims atomic_sub braucht nents=1, was den Early-Exit von shrink_cpu_mapping bricht.

Der Gewinn: Der Exploit-Prozess behält die kbm-CPU-Mappings, sodass der Fake-nf- Entry zwischen Paketen in-place umgeschrieben werden kann:

  • selroot-Modus: Entry = {fn=0xc01d503c (mov r3,#0;str r3,[r0];bx lr), priv=0xc1213ea8 (selinux_state.enforcing)}.
  • Paket 1: *(enforcing)=0 → SELinux Permissive.
  • Den Entry via kbm_cpu[reg]+off auf {fn=commit_creds, priv=&init_cred} umschreiben.
  • Paket 2: commit_creds(&init_cred) im Task des Senders → uid 0 mit permissivem SELinux → nutzbares Root, alles in einem Reclaim, keine Kette nötig.

Auf dem Gerät verifiziert (2026-09-11)```

[+] W1 CONFIRMED: region 67 page+0xad000 <- 0xc11855cc (reclaim + G hit!) [*] sendto 0 -> -1 errno=1 uid=0 euid=0 [+] nf trigger done, uid=0 euid=0 <<< HOOK RAN - commit_creds OK [+] ROOT: uid=0 euid=0 [+] setenforce write=1 [+] su copied bytes=236220

root@kitploit:~
- `getenforce` → **Permissive**; pausiertes st3 ist `Uid: 0 0 0 0`,
  `CapEff: 3fffffffff`.
- `/data` ist **nosuid** gemountet, daher kann ein setuid `su` nicht funktionieren. Eine winzige
  `rootshell` (UDP senden → `commit_creds` auf sich selbst → `execl sh`) liefert eine
  interaktive Root-Shell: `uid=0(root) context=u:r:kernel:s0`.
- Root kann `/dev/block/by-name/*` lesen/schreiben (`dd if=boot ...` OK).

### Stage-3-Codezustand (`poc/stage3.c`)
- Modi: `nf <mb> [probe|uprobe|oc|chain|fc <sid>|notrig|selroot]`
- `selroot` ist die funktionierende Waffe. Wichtige Statics: `init_net=0xc1185040`,
  `HOOKS_PTR_ADDR=0xc11855cc`, `ENFORCING_ADDR=0xc1213ea8`,
  `ZERO_GADGET=0xc01d503c`, `commit_creds=0xc014993c`,
  `init_cred=0xc1114f54`.
- Post-Exploit sind direkte Syscalls (kein `system()`); den kctx am Leben halten
  (`pause()`), um einen Teardown-Crash zu vermeiden.

### Verbleibend (Stage 4/5)
- Persistenz über Reboot hinweg (verity / Boot-Image / Recovery), da die Cell-
  Hijack + permissive SELinux nur zur Laufzeit gelten und ein erneutes Ausführen des Exploits
  den ~1/3-Reclaim-Münzwurf erfordert.
- `su` benötigt ein Nicht-nosuid-Home (`/system`) oder einen Launcher, der erneut auslöst.

## SESSION 11 — PERSISTENCE RECON (Track B + Track A) und die RE-Übergabe

Ziel war persistenter Root. Zwei Tracks wurden abgesteckt:
- **Track B**: Verified Boot deaktivieren (dm-verity / SELinux), damit `/system` gepatcht werden kann.
- **Track A**: den Exploit beim Boot erneut ausführen.

Beide laufen auf denselben Blocker hinaus: **LK dazu bringen, das Gerät als `eng`/`unlocked` zu behandeln.**

### Verified-Boot-Fakten (exakter Build)
- Bootloader gesperrt, AVB `green`, `ro.boot.unlocked_kernel=false`, `ro.boot.secure_cpu=1`,
  `rpmb_state=1`. Bootrom gepatcht (kein BROM); Preloader nur über CMD-Kurzschluss.
- `/system` wird von **Android dm-verity aus der von LK erzeugten Kernel-Cmdline** gemountet:
  `root=/dev/dm-0 dm="system none ro,0 1 android-verity PARTUUID=b6404ef3-… "`,
  `veritykeyid=id:f3530e18f64d11fc25eb2dd762979f078de990bf`, `androidboot.veritymode=eio`,
  `skip_initramfs` (system-as-root). `dm-0` = Verity-Gerät namens `system`; `dm-1` = `/vendor`.
- LK: Amazon **UFBL**, `ro.boot.lk_version=0x0006`, Build `0db73c9-20231025_030009`;
  Preloader `pl_version=0x000a`, Build `80c6fcb-20230523_065640`. `/dev/block/by-name/lk` = mmcblk0p5 (1 MB).
- Vollständige GPT (16 Partitionen, kein `persist`/`seccfg`/`nvram`/`protect`/`para`):
  `proinfo` p0, `PMT` p1, `kb` p2, `dkb` p3, `lk` p4, `tee1` p5, `tee2` p6, `metadata` p7,
  `MISC` p8, `reserved` p9, `boot` p10, `recovery` p11, `system` p12, `vendor` p13,
  `cache` p14, `userdata` p15. eMMC boot0 (1 MB) = Preloader (`EMMC_BOOT`-Magic);
  boot1 (4 MB) = IDME-Speicher.

### LK (UFBL) statische Befunde
`lk.img`-Header: `88 16 88 58 | 00052974 | "LK"`; ARM-Vektortabelle bei 0x200, Rest Thumb-2,
positionsunabhängig/reloziert (Literal Pools nutzen `ldr+add pc`, daher schlägt naives basisrelatives Disasm fehl).
Relevante Strings (Datei-Offsets): `amzn_image_verify`, `amzn_verify_unlock`, `amzn_verify_code_internal`,
`unlock_code`, `unlock code error`, `unlock failed`, `$Common Kernel Signing Engineering CA0`,
`seccfg`, `para`, `ENV_v1`, `LK_ENV`, `Kfos_flags`/`Kdev_flags`/`Kusr_flags`/`Kunlock_code`/`Kunlock_version`,
`FOS_FLAGS_{NONE,ADB_ON,ADB_ROOT,CONSOLE_ON,RAMDUMP_ON,VERBOSITY_ON,ADB_AUTH_DISABLE,FORCE_DM_VERITY,DM_VERITY_OFF,BOOT_DEXOPT}`,
`[DM-VERITY] verify for system(root) is enabled`, `[DM-VERITY] verify off by fos_flags`,
`[DM-VERITY] disabled by fos_flags on eng devices or unlocked device`,
`[SELINUX] set to permissive mode by dev_flags`, `androidboot.prod=1|0`, `androidboot.unlocked_kernel=%s`.
**Fazit: LK koppelt die Sicherheitswirkungen von `fos_flags`/`dev_flags` an eng/unlocked.**

### IDME-Speicher (eMMC **boot1**) — beschreibbar, persistent, von LK und Android gelesen
- Magic `beefdeed` + `"2.1\0"` + count(0x19=25) bei 0x0; Items ab 0x10.
- Item-Format: `char name[16]; u32 size; u32 type(=1); u32 magic(=0x124); u8 data[size] (pad4)`.
- Item-Offsets (unberührt): `board_id@0x10 serial@0x3c mac_addr@0x68 mac_sec@0x94 bt_mac_addr@0xd0
  bt_mfg@0xfc product_name@0x198 productid@0x1d4 productid2@0x210 region@0x24c bootmode@0x26c
  postmode@0x28c bootcount@0x2ac manufacturing@0x2d0 unlock_code@0x4ec sensorcal@0x908 alscal@0x9c4
  KB@0xa00 DKB@0x1e1c device_type_id@0x2238 dev_flags@0x2274 fos_flags@0x2298 usr_flags@0x22bc
  wifi_mfg@0x22e0 unlock_version@0x26fc`. Werte sind ASCII (Flags sind **Hex-Strings**).
- Laufzeit-Lesen: `/proc/idme/<name>` (nur lesbar). Werte des letzten Boots werden gecacht; ein Schreiben nach boot1 wird
  beim nächsten Boot wirksam. Der Schreibpfad erfordert das Löschen von `/sys/block/mmcblk0boot1/force_ro` (Root).
- **Bestätigt: LK liest boot1**: Ändern von `serial` änderte `ro.boot.serialno` beim nächsten Boot.
  Aber LK **kürzt serial auf 16 Bytes** und ignorierte `fos_flags=0x80`, `dev_flags=0xff`,
  alles- Einsen usw. — verity/selinux/`prod` unverändert. Cmdline-Injection über serial schlägt also fehl.

### Android-seitige Konsumenten der IDME-Flags
- `/init.fosflags.sh` (Service `fosflags`, `u:r:fosflags:s0`): `FOS_FLAGS_ADB_ON=0x1`,
  `CONSOLE_ON=0x4`, `RAMDUMP_ON=0x8`, `VERBOSITY_ON=0x10`, `ADB_AUTH_DISABLE=0x20`,
  `BOOT_DEXOPT=0x100`. Verifiziert: Setzen der Flags wirkt (`sys.usb=adb`, `noadbauth=1`).
- **adbd** (unstripped ARM ET_EXEC; `.text` VA 0x8160 / Datei 0x160; fileoff = VA-0x8000):
  - `amzn_is_root_allowed` @0x2d5b8 = `amzn_is_dev_unlocked() && (fos_flags & 0x2)`
  - `amzn_is_adb_auth_disable_allowed` @0x2d5e8 = `fos_flags & 0x20` (ungated)
  - `amzn_is_dev_unlocked` @0x2d5fc = `/proc/cmdline` enthält `androidboot.prod=0` **oder**
    `androidboot.unlocked_kernel=true`
  - `fos_read_debug_flags` @0x2d724 liest `/proc/idme/<name>` und parst **hex**
  - `restart_root_service` @0xcb74 / `restart_unroot_service` @0xcc64
  - Strings: `amzn_fos: ADB: Auto-root succeeded`, `… eng_device=%d`, `… unlocked_kernel=%d`,
    `adbd cannot run as root in production builds`, `ro.debuggable`
  - `adb root` → "cannot run as root in production builds" (`ro.debuggable=0`) — selbst wenn also das
    Auto-Root-Gate erfüllt ist, blockiert die AOSP-Prod-Prüfung den Befehlspfad.

### Warum der Root aus Session 10 nicht persistent ist
- SELinux permissive + Cell-Hijack + Root gelten nur zur Laufzeit.
- `/data/metrics` ist eine **vpartition**: `/system/bin/vpartition.sh` mountet `/data/vp/metrics.img`
  (ext4, non-nosuid/noexec) bei jedem Boot nach `/data/metrics`; ein dort geschriebenes `su` überlebt
  einen Reboot **nicht**. (Auch der Grund, warum setuid `su` uid 0, aber **null Caps** lieferte.)

### Track A (Re-Exploit zur Bootzeit) — blockiert
- Kein init-`.rc`-Trigger führt kontrollierbaren Code aus (Imports alle verifiziert; `persist.*`-Trigger nur
  `start` fester Services; Skripte in `/system`/`/vendor`).
- Root-Services lesen `/data`-Konfigurationen, führen aber niemals daraus aus (`perfmonitord`, `amazonfiled`,
  `vpartition.sh`, `kisd`, …).
- Einziger Boot-Executor = eine **App**, aber der pausierte Footprint des Exploits ist **VmRSS 534 MB**
  (`kbm`-Spray) → lmkd killt sie; zudem panikt ein verlorener Reclaim (`PANIC_ON_OOPS`) → Bootloop.
- **adbd Auto-Root** existiert, ist aber an die von LK erzeugte Cmdline gekoppelt (`prod=0`/`unlocked_kernel=true`).

### Fazit / nächstes Ziel (gewählt: Track B RE)
Alles hängt daran, LK dazu zu bringen, `eng`/`unlocked` zu melden. In Reichweite:
`androidboot.prod=1|0` und `androidboot.unlocked_kernel=false` werden von LK gesetzt. LK reversen, um zu finden:
1. wo es `fos_flags`/`dev_flags`/`usr_flags` (die `K*`-Items) liest und das exakte Gate;
2. die `prod`/`unlocked`-Bestimmung (IDME-Item? buildvariant? `amzn_verify_unlock`-Ergebnis?);
3. `amzn_verify_unlock` (libtomcrypt RSA verify) für einen Bypass oder einen schwachen unlock_code/version-Pfad;
4. den `seccfg`/`para`/`ENV_v1`(LK_ENV)-Speicher (in keiner gedumpten Partition — vielleicht tee-geschützt);
5. Preloader (`boot0`, `EMMC_BOOT`) für einen Bug.
Wenn irgendetwas davon uns erlaubt, eng/unlocked zu setzen (persistent, via boot1 oder einen Raw-Partition-Schreibvorgang), dann
deaktiviert `FOS_FLAGS_DM_VERITY_OFF` die system(root)-Verity und `/system` kann persistent gepatcht werden.

### Artefakte (aus dieser Session)
`/tmp/opencode/mustang-dumps/` (kann bei Host-Reboot gelöscht werden): `lk.img`, `boot1.img` (unberührt),
`boot.img`, `MISC.img`, `metadata*.img`, `pmt.img`, `mbr.img`, `kb.img`, `dkb.img`, `reserved.img`,
`cache.img`, `boot0.img`, `boot1.img`, `adbd.bin`, `perfmonitord.bin`, `amazonfiled.bin`.
Helfer: `tools/findinitnet.py`, `findgadget*.py`, `findstores.py`, `adbd_sym.py` (in /tmp);
Repo enthält `run.sh`, `poc/stage3.c` (`selroot`), `poc/su.c`, `rootcmd.sh`.

### Nützliche Befehle```
# IDME read
/data/metrics/su sh -p -c 'for f in fos_flags dev_flags usr_flags serial region device_type_id unlock_version; do echo -n "$f="; cat /proc/idme/$f; echo; done'
# write boot1 (root; su lives only until reboot -> re-run run.sh first)
/data/metrics/su sh -p -c 'echo 0 > /sys/block/mmcblk0boot1/force_ro; dd if=/data/local/tmp/boot1.img of=/dev/block/mmcblk0boot1 bs=4096 count=4; sync; echo 1 > /sys/block/mmcblk0boot1/force_ro'
# dump a partition to host
adb exec-out '/data/metrics/su dd if=/dev/block/by-name/lk bs=4096 2>/dev/null' > lk.img

SITZUNG 12 — LK RE: Das eng/unlocked-Gate ist real, und unsignierte Flag-Stores existieren nicht

Ziel: LK dazu bringen, das Gerät als eng/unlocked zu behandeln, oder einen Preloader-/LK-Bug finden, damit verity/SELinux dauerhaft deaktiviert werden können. Ergebnis: der relevante LK-Codepfad wurde end-to-end zurückentwickelt; der Flip ist über die verfügbaren Stores nicht erreichbar. Kein Gerät wurde gebrickt; das eine boot1-Experiment wurde auf den Ursprungszustand zurückgesetzt.

LK ist Thumb-2 PIC, reloziert auf Basis 0xFF400000

lk.img beginnt mit einem winzigen ARM-Stub (Datei 0x200). Der Relocator bei 0x224 kopiert von 0x200 an ein literales Ziel und springt zu einem literalen Einstiegspunkt:

Also Laufzeitadresse = 0xFF400000 + Datei-Offset für Offsets >= 0x200. Alles nach dem Stub ist Thumb-2, positionsunabhängig. Strings werden mit ldr rT,[pc,#imm] (T1-Offset = imm8*4; ldr.w-Offset = imm12) gefolgt von add rT, pc gebildet; das Ziel ist (add+4) + *pool. Ein robuster Scanner, der den ARM-Stub und Literal-Pools übersteht, wurde als tools/lk_xref.py hinzugefügt (behandelt 16- und 32-Bit-Formen, scannt alle 2 Bytes). Alle Offsets unten sind Datei-Offsets; addiere 0xFF400000 für Laufzeitadressen.

Dekodierter Kontrollfluss (Offset -> Bedeutung)

Der Unlock-Code ist Amazon-RSA-signiert — nicht fälschbar

0x20b4 liest das unlock_code-IDME-Element (0x400 Bytes, alles Null auf diesem Gerät) und führt amzn_verify_unlock aus (0x222c -> 0x20f0). Diese Funktion treibt libtomcrypt an (Dutzende /features/libtomcrypt/src/pk/asn1/der/...-Pfade und RSA-Verifikation), und das Image enthält das Zertifikatsmaterial: Sunnyvale / Amazon Lab126 / "$Common Kernel Signing Engineering CA0" bei 0x317d9+, plus die Diagnosen Image FAILED AUTHENTICATION on PRODUCTION device (0x3166e), Authentication failed on engineering device with production certificate (0x316a0), Image FAILED AUTHENTICATION on ENGINEERING device (0x31703), Image AUTHENTICATED with PRODUCTION certificate (0x31736). Es gibt keine Abkürzung über leeren Code / Länge / Version: verify(zeros) != 0, daher (bestätigt in ). Ein Umlegen von oder erfordert entweder einen gültigen Amazon-signierten (privater Schlüssel nicht verfügbar) oder einen Code-Execution-Bug im Verifier. Statisch wurde nichts Ausnutzbares (Bounds/Size) in 0x20b4/0x222c/0x20f0 gefunden. =>

Die verity/SELinux-Flags stammen nicht aus einem Store, der existiert

Die Security-Flags werden über den Getter bei 0x57c gelesen. Empirischer Test:```

boot1 IDME item fos_flags data (offset 0x22B4, 8 bytes) set to "00000080"

dd if=/dev/block/mmcblk0boot1 ... ; reboot /proc/idme/fos_flags -> 00000080 (persisted, Android sees it) ro.boot.veritymode -> eio (unchanged!) root=/dev/dm-0 dm="system none ro,0 1 android-verity PARTUUID=..." (unchanged) androidboot.prod=1 / secure_cpu=1 / buildvariant=user (unchanged)

root@kitploit:~
`fos_flags=0x80` ist `FOS_FLAGS_DM_VERITY_OFF`; das dekodierte Gate hätte
Verity deaktiviert, **wenn** der Getter es zurückgegeben hätte.  Das tat er nicht.  Das Gate ist aktiv, kein toter Code: sein einmaliger Cache-Sentinel ist `-1` im Image
(`*(u32*)0x50c74 == 0xffffffff`), also hat die Funktion tatsächlich den
`check_flag("fos_flags",0x80)`-Pfad ausgeführt und 0 erhalten.  Daher liest der Getter (zumindest
zum Zeitpunkt des Verity-Schutzes) **nicht** die boot1-IDME-Einträge.

Der andere Kandidatenspeicher ist die **LK env**, geladen aus einer Partition mit dem buchstäblichen
Namen `"para"` (Loader 0x12fd4, Magic `ENV_v1`, Checksumme @0x3ffc).  LKs eigene
Partitionstabelle (0x4fcc0..0x50340) listet preloader/proinfo/nvram/protect1/
protect2/persist/seccfg/secro/**para**/logo/custom/expdb/tee1/tee2/metadata/
system/cache/userdata — aber der tatsächliche GPT des Tablets hat **nur 16 Einträge**, alle
vom Typ `af3dc60f838472478e793d69d8477de4`:```
#0 proinfo 0x400   #1 PMT 0x1c00    #2 kb 0x4000     #3 dkb 0x4800
#4 lk 0x5000       #5 tee1 0x5800   #6 tee2 0x8000   #7 metadata 0xa800
#8 MISC 0x1e400   #9 reserved 0x1e800  #10 boot 0x22800  #11 recovery 0x2a800
#12 system 0x34800 #13 vendor 0x644000 #14 cache 0x6b4800 #15 userdata 0x7ae800

Es gibt keine para-, seccfg-, nvram-, protect- oder persist-Partition auf diesem Produkt (und PMT/pmt.img-Dumps sind alle null). Die LK-Umgebung ist also leer, die Schlüssel Kfos_flags/Kdev_flags existieren nie, und alle fos_flags/dev_flags- Prüfungen ergeben 0 — unabhängig davon, was die IDME-Einträge enthalten. Die boot1- IDME-Einträge werden von Android konsumiert (/init.fosflags.sh, adbd, /proc/idme/*), aber nicht von LKs Sicherheitsschranken.

Fazit — warum persistentes eng/unlock blockiert wird

  1. unlocked_kernel erfordert einen von Amazon signierten unlock_code (RSA/libtomcrypt, eingebettete CA). Nicht offline fälschbar; kein Verifier-Bug gefunden. Harte Blockade.
  2. Die Flags DM_VERITY_OFF / selinux=permissive werden aus der LK-Umgebung (para/ENV_v1) konsumiert, die auf dieser GPT nicht existiert. IDME fos_flags wird empirisch von LK ignoriert (0x80 persistiert, verity blieb eio). Harte Blockade, es sei denn die Partitionstabelle wird modifiziert.
  3. Selbst ein erfolgreiches fos_flags=0x80 würde nur androidboot.veritymode= disabled und ein nicht-dm-0 root= setzen; es würde nicht entsperren, und SELinux bräuchte weiterhin dev_flags aus derselben fehlenden Umgebung, um permissiv zu werden.

Verbleibende Wege (zukünftig, höheres Risiko; nicht versucht)

  • Einen para/ENV_v1-Store synthetisieren: einen GPT-Eintrag namens para (primäre
    • Backup-GPT müssen beide aktualisiert werden) im freien Speicher nach userdata hinzufügen (userdata endet bei LBA 0x3a3dfde; Disk = 30535680 Sektoren), dann eine Env mit fos_flags=0x80 und dev_flags=0x40 erstellen (Checksumme bei +0x3ffc = Byte-Summe über 0x3ffc). Dies ist der einzige verbleibende Weg zu verity-off. Risiken: Beschädigung der primären/Backup-GPT kann zum Brick führen; und es wurde nicht bewiesen, dass die Verity-Schranke tatsächlich para liest (nur dass es nicht boot1 IDME ist).
  • Preloader (boot0/EMMC_BOOT)-Bug: in dieser Sitzung nicht reversed. Das Schreiben von boot0 ist verboten, bis eine unversehrte Kopie und ein Wiederherstellungspfad existieren.
  • Verifier-Forschung: der Engineering-Zertifikatspfad (0x316a0/0x31703) ist nur mit einer als „engineering" akzeptierten Geräteidentität plus einem mit dem Engineering-Schlüssel signierten Code erreichbar; kein privater Schlüssel ist verfügbar.

Artefakte / Reproduzierbarkeit

  • Hinzugefügtes Tool: tools/lk_xref.py — basisunabhängiger LK-String-Xref-Resolver.
  • Verwendete Dumps: /tmp/opencode/mustang-dumps/lk.img, boot1.img (unversehrt), boot0.img, mbr.img (GPT), pmt.img (alles null).
  • boot1-Experiment-Image (fos_flags=0x80) aufbewahrt unter /tmp/opencode/s12/boot1_f80.img; Gerät auf unversehrtes boot1 zurückgesetzt (verifiziert /proc/idme/fos_flags -> 0).

Nützliche Befehle (Root erforderlich; erneut scharf machen mit ./run.sh)```

re-arm runtime root (~1/3 per boot)

./run.sh --no-build

confirm LK's decisions without a UART

/data/metrics/su /system/bin/sh -p -c 'cat /proc/cmdline'

watch: root=/dev/dm-0 dm="system ... android-verity ..." (verity on)

androidboot.veritymode=eio ; androidboot.selinux=enforce ; prod=1

IDME read (Android copy; NOT what LK's gates use)

for f in fos_flags dev_flags usr_flags unlock_version serial; do cat /proc/idme/$f; echo; done

root@kitploit:~
## SITZUNG 13 — der Preloader ist doch erreichbar (`1949:20ff` = MTK-Preloader, HID-Transport)

Während das Tablet ausgeschaltet und per USB angeschlossen ist, enumeriert es als **`1949:20ff`**
(`Lab126`) — *nicht* Android und *nicht* der `0e8d:0003`-Bootrom.  Deskriptor:```
bInterfaceClass 3 (HID), iConfiguration "HID", iInterface "HID Interface"
HID report descriptor = 05 01 09 00 a1 01 c0   (empty collection!)
EP 0x81 IN  interrupt  4 bytes, bInterval 4
EP 0x01 OUT interrupt  4 bytes, bInterval 4
iSerial = GCC0X90805310009 (the IDME serial)

Identifikation. 0x20FF ist in mtkclients config/usb_ids.py als "MTK Preloader" aufgeführt (unter MediaTek VID 0x0e8d: 0xe8d:{0x0003 Brom, 0x2000/0x2001/0x20ff/0x3000 Preloader}). Amazon behielt die Preloader-PID bei und änderte die VID auf 0x1949 und präsentiert sie als HID-Endpunktpaar mit einem Dummy-Report-Descriptor. Es handelt sich also um den MediaTek Preloader / USBDL-Modus, eine Stufe unterhalb von LK — hier erreicht durch Ausschalten + Einstecken, nicht durch den CMD-Kurzschluss.

Die Descriptor-Strings "HID"/"HID Interface" sind nicht in lk.img, boot0.img, boot.img oder den anderen Dumps vorhanden, d. h. der Modus wird von einer Komponente erzeugt, die wir nicht gedumpt haben (Bootrom/TEE), oder wird zur Laufzeit zusammengesetzt.

Warum das wichtig ist. Der von aftv2-tools verwendete Amazon-Preloader stellt über genau diesen Byte-Stream integrierte, Download-Agent-lose Befehle bereit:``` handshake : host A0 0A 50 05 -> dev 5F F5 AF FA 0xD1 read32 (addr, n_words) : echo cmd/addr/n, 00 00, nu32, 00 00 0xD4 write32(addr, words[]) : echo cmd/addr/n, 00 00, nu32, 00 00

root@kitploit:~
`aftv2-tools/read_mmc.py` verwendet `read32`/`write32`, um den MSDC-Controller
(Basis `0x11230000` auf MT8173; für MT8163 verifizieren) anzusprechen und **rohe eMMC-
Blöcke** ohne DA und somit ohne AVB/Verity im Weg zu lesen/schreiben. Wenn der Preloader
von mustang 0xD1/0xD4 akzeptiert, ist das ein direkter Weg zum persistenten Unlock (Patch von `boot` /
`lk`), unabhängig vom RSA-Unlock-Code und der fehlenden LK-Umgebung.

### Hinzugefügte Tools (Root erforderlich; zuerst chmod auf dem USB-Node ausführen)```
lsusb -d 1949:20ff                 # note Bus/Dev, e.g. Bus 001 Device 003
sudo chmod 666 /dev/bus/usb/001/003
# 1) does it answer the MTK handshake? (no DA, no flash access)
nix-shell -p python3Packages.pyusb --run \
    'python3 tools/mtk_preloader_hid.py handshake'
# 2) read-only arbitrary memory read
nix-shell -p python3Packages.pyusb --run \
    'python3 tools/mtk_preloader_hid.py read32 0x00100000 4'

tools/probe_preloader.py ist die minimale Handshake-only-Sonde; tools/mtk_preloader_hid.py ist der vollständige Transport (handshake/read32/ write32; write32 ist abgesichert und sollte nicht verwendet werden, bis die eMMC-Register- Map bestätigt ist).

Status / nächste Schritte

  • Unbestätigt: ob mustangs Preloader tatsächlich 0xD1/0xD4 implementiert (die Handshake-Sonde entscheidet dies). Falls ja, kann der aftv2-eMMC-Lese-/Schreib- Pfad wahrscheinlich direkt portiert werden.
  • Dann: die MT8163-MSDC-Basis finden (Kernel-DT oder Preloader), eine Partition dumpen (read_mmc), dann boot.img/lk vom Preloader aus patchen und neu starten.
  • Dies ist eine niedrigere Boot-Stufe als alles in SESSION 12, daher hängt es nicht von amzn_verify_unlock oder dem LK-Env-Gate ab.
  • Führen Sie KEINE SP Flash Tool / mtkclient-Schreibvorgänge dagegen aus, bevor das Protokoll und das eMMC-Layout bestätigt sind.
Tool herunterladen
pi_blocked_on
  • Proxy-Waiter lebt auf dem eigenen Stack des Waiter-Threads (futex.c:1975 übergibt this->rt_waiter, deklariert in futex_wait_requeue_pi bei futex.c:2880) → Waiter stempelt seinen eigenen freigegebenen Frame via arm32 select (nr 142) fd_sets
  • Ausbeutungsklima: kein KASLR (feste Basis 0xc0008000), kein PAN, DEBUG_RT_MUTEXES aus → kompakter 48-Byte rt_mutex_waiter (tree_entry@0, pi_tree_entry@0xc, task@0x18, lock@0x1c, prio@0x20, deadline@0x28)
  • Minimale Kette: 2 Write-Slots → modprobe_path @ 0xc111488c (String selbst-lokalisiert in vmlinux; KALLSYMS_ALL aus, daher brauchen Datensymbole diesen Trick) → unknown-binfmt exec → root script (setenforce 0, OTA deaktivieren, su)
  • Referenzen in refs/: NebuSec/CyberMeowfia (Original), GhostLock-5.10 (Fire OS 8 Port, vollständiger 32-Bit-ARM-Trigger in src/exp32/), ghostlock-...-4.19-k40 (Qualcomm 4.19 Android Port)
  • Stufe 3: beliebiger Kernel-Funktionsaufruf → ROOT (Session 10)
    selroot
    selinux_state.enforcing
    commit_creds(&init_cred)
    uid=0
  • [_] Stufe 4: Root-Script (su, permissive, OTA aus) + Persistenz — root erlangt; Persistenz blockiert (siehe SESSION 11): LK gated verity-off/SELinux-permissive auf eng/unlocked, Boot-Zeit-Re-Exploit hat keinen gangbaren Executor. Nächstes: LK/amzn_verify_unlock reversen.
  • Stufe 5: eigene OS-Boot-Kette
  • jc
    nr_extres
  • JIT-Alloc-Ergebnis wird vom Kernel durch info->gpu_alloc_addr geschrieben (eine GPU-VA, die du vorab allozieren und übergeben musst)
  • evictable objectpressureresult
    none900 MBsurvived
    none1300 MBpanic (system lowmem bug — unrelated)
    normal region + DONT_NEED700 MBsurvived
    JIT region + DONT_NEED700 MBpanic in reclaim path
  • kernel/config-* — /proc/config.gz-Dump vom laufenden Gerät
  • ksrc/ — Amazon OSS-Quellcode (platform.tar + extrahierter midgard-r26p0-Baum)
  • OTA: /tmp/opencode/mustang_ota.bin (sha256 6068515a… stimmt mit fireos-archive überein) und 2,2 GB Kernel-Source-Tarball aufbewahrt unter ~/Desktop/amazon-mustang/
  • Quellbaum-Pfad: ksrc/kernel/mediatek/mt8163/4.9/drivers/misc/mediatek/gpu/gpu_mali/mali_midgard/midgard-r26p0/
  • Renames stocken (Journal/GFP_NOFS) → 128 gesamt → Müll-Deref
    Pre-Drain 12K Events + Druck + kleines TrailingCrash beim Deref
    + Kill-Child-bei-Eviction (10ms Poll)Crash beim Deref
    + CPU0-gepinnte Lifecycle (drain3)Crash beim Deref
    gestufter Druck (drain4 v1)Kinder gaben Speicher beim Exit frei → keine Eviction (legaler Pfad validiert)
    LaufErgebnis
    pmap G=c2a412a4 400MBCrash beim Deref
    pmap G=c2f4b2a4 480MBCrash; +0 Post-Kill-Renames (480MB erstickt fs)
    iso2 (Spray + Regions + Oracle)REGION HIT — Spray bricht Reclaim nicht
    mix v1 (gleichzeitige Events+Regions)Crash; konfundiert (spinnende Event-Threads)
    pmap G=c2a7d2a4 350MB + RetouchCrash; +4452 Renames OK
    mix2 (sequenziell: 2s Events DANN Regions)Crash; +7126 Renames (28K Event-Allocs), 2715 Regions
    fn
    fn=0
    an der Cell- Adresse
    PM_PAGE+NF_CELL_OFF
    probe
  • Physmap-Direct-Map ist XN oberhalb kernel_x_end: arch/arm/mm/mmu.c map_lowmem() mappt Lowram unterhalb des Kernel-Texts MT_MEMORY_RWX, aber alles oberhalb kernel_x_end MT_MEMORY_RW → PMD_SECT_XN (Zeile 509). Eingebackener Shellcode bei 0xc154b600 Prefetch-Aborts. Payload muss ein echter Kernel- Funktionspointer sein, kein Code im Physmap.
  • Literal (Datei-Offset)WertBedeutung
    0x2700xFF4002F8str r4,[r6] Scratch
    0x2740xFF40027CZiel (Basis+0x27C)
    0x2780xFF54A440Kopierende (inkl. BSS)
    0x27C0xFF400484Einstiegspunkt
    OffsetFunktion
    0xdf7cis_secure_or_prod() -> byte[ [[g]+0 ] + 0x163 ]; g = global @0x52838. 1 auf diesem Gerät.
    0x20b4verify_stored_unlock() = memset(buf,0,0x100); liest IDME/env unlock_code (0x100) über 0x57c; bl 0x222c; gibt (verify==0) zurück.
    0x222c / 0x20f0amzn_verify_unlock(code,len) — libtomcrypt RSA/PKCS#1-Verifikation (siehe unten).
    0xda3eis_unlocked() = is_secure_or_prod() && verify_stored_unlock().
    0x29a28is_verity_disabled() = (fos_flags & 0x80) && !(is_secure_or_prod() && verify_stored_unlock()); gecacht in global @0x50c74.
    0x29974SELinux-Cmdline-Builder: dev_flags & 0x20 -> androidboot.selinux=enforce, dev_flags & 0x40 -> ...=permissive (jeweils gated durch byte[+0x162]).
    0x118xx/0x11bxxKernel-Cmdline-Builder (unlocked_kernel, prod=1/0, verifiedbootstate, rpmb_state, secure_cpu, Versionen, root=).
    0x27af8UART-Gate: fos_flags & 0x4 -> printk.disable_uart=0, sonst =1.
    0x12fd4LK-Env-Loader: Partition "para", 0x4000 Bytes, Magic ENV_v1, Checksumme = Summe der Bytes über 0x3ffc verglichen mit Word @0x3ffc.
    0x1efd0Partitions-Lookup nach Name (verwendet für "para", "boot", ...).
    0x57cGetter-Dispatcher über Callback-Slot @0x58218; Slots @0x58200..0x5821c werden aus einer Tabelle bei 0x5a8-0x734 registriert.
    0x2a19cfastboot oem unlock: bl 0x222c(code,len); schreibt bei Erfolg unlock_code (0x100) über 0x408.
    unlocked_kernel=false
    /proc/cmdline
    androidboot.unlocked_kernel
    androidboot.prod
    unlock_code
    der eng/unlocked-Flip über den dokumentierten Pfad ist kryptographisch undurchführbar.
  • Track A (Boot-Time-Re-Exploit) bleibt daher genau wie in SESSION 11 blockiert: sein einziger Unlock-Pfad ist dieselbe LK-Schranke.