From 777d0ef076c875ebd4fc39a0bb6fa3b6883b1dfd Mon Sep 17 00:00:00 2001 From: SashegDev Date: Mon, 7 Sep 2026 08:34:35 +0000 Subject: [PATCH] dissection: real RM-1127 GPT33/RKH/P6236, ffu_parse.py mmap, edp 10 ELFs --- docs/dissection.md | 58 +++++++++++++++++++++++++ fw/.gitignore | 2 + tools/ffu_parse.py | 105 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 docs/dissection.md create mode 100644 tools/ffu_parse.py diff --git a/docs/dissection.md b/docs/dissection.md new file mode 100644 index 0000000..3f09469 --- /dev/null +++ b/docs/dissection.md @@ -0,0 +1,58 @@ +# Разбор реальных файлов RM-1127 (zern, fw/dl/) + +Файлы лежат на zern `~/lumia-emu/fw/dl/` (в гит не входят): +- `RM1127_059X5R5_orig.ffu` 1800142848 B, CRC32 `a41e0775` = VPL — ЦЕЛ +- `RM1085_donor.ffu` 2995126272 B (донор WPInternals) +- `MPRG8909_fh.ede` 146180 B ELF32 ARM entry `0x8008700` (идентичен на lumiadb и archive.org) +- `RM1127_fh.edp` 3530240 B Emergency Payload, 10 ELF внутри +- `0x000940e100420050.mbn` 292392 B generic firehose (Nokia 8110, то же семейство) +- `.vpl/.dcp/.nvi/.xml` companions из archive.org + +## Ключи +- `RKH: 56BDC3746226E080146D4D30C8C8432657A5282F` +- `MSM_ID: 009600E1, OEM_ID: 0045, MODEL_ID: 0000, SW_ID: 1A` +- `PlatformID: Microsoft.MSM8909.P6236`, OS `8.15.13333.494`, AntiTheft 1.1 +- FFU: `SignedImage, chunk 128K, SHA256, catalog 2501, hashes 13730`, header `0xA0000` + +## .edp: 10 ELF (смещение → что) +``` +0: 22016 SBL1 (SBL1 Start/End, pm_sbl_boot.c), entry 0x8006b80 +1: 293376 RPM.BF.2.1.1 (Oct 23 2015) +2: 461312 TZ.BF.2.5 (QSEE) +3: 1006080 UEFI EDK2 (Dec 29 2015, PCD strings) +4: 2237440 WINSECAPP (qcom.tz.winsecapp) +5: 2660864 UEFISecApp (qcom.tz.uefisecapp) +6-9: модемные блобы (Oct 15 2015, без строк) +``` +`.ede` — маленький Sahara-загрузчик (577 строк, в основном серты), сам Firehose-XML живет дальше по цепочке. В SBL1-блобе XML-команд не видно в открытом виде. + +## Реальная GPT 550 (Final, 33 раздела!) +Отличается от шаблона 950: `SBL1 LBA 90112` (не 32768!), `QSEE+QHEE` вместо TZ, есть `BOOTMODE`, `TZAPPS 16M`, нет APDP/MSADP/DPO/LIMITS/HYP. + +| Раздел | LBA | Размер | +|---|---|---| +| DPP | 4096..20479 | 8M | +| MODEM_FSG/FS1/FS2 | 20480/24576/28672 | 1.5M x3 | +| MODEM_FSC | 32768..32799 | 16K | +| DDR | 36864..36927 | 32K | +| LogFS | 40960..73727 | 16M | +| SSD | 73728..73759 | 16K | +| UEFI_BS_NV / UEFI_RT_NV | 77824 / 81920 | 256K x2 | +| BOOTMODE | 86016..86047 | 16K | +| SBL1 | 90112..91135 | 512K | +| DBI | 94208..94271 | 32K | +| UEFI | 98304..102399 | 2M | +| RPM | 102400..103423 | 512K | +| QSEE | 106496..108543 | 1M | +| QHEE | 110592..111615 | 512K | +| WINSECAPP | 114688..115711 | 512K | +| TZAPPS | 118784..151551 | 16M | +| BACKUP_SBL1/DBI/UEFI/RPM/QSEE/QHEE/WINSECAPP/TZAPPS | 151552..212991 | — | +| PLAT (pconf.bin!) | 212992..229375 | 8M | +| EFIESP | 229376..360447 | 64M | +| MMOS | 360448..372735 | 6M | +| SEC | 372736..372767 | 16K | +| MainOS | 376832..4089855 | 1813M NTFS | +| Data | 4096000..15150847 | 5397M NTFS | + +MinSectorCount 15154944 = eMMC 7400M. Парсер: `tools/ffu_parse.py` (mmap, ищет валидный GPT по rev/nent). diff --git a/fw/.gitignore b/fw/.gitignore index f3df06a..056290f 100644 --- a/fw/.gitignore +++ b/fw/.gitignore @@ -13,5 +13,7 @@ *.vpl *.rar *.zip +*.log +*.aria2 !*.md !*.txt diff --git a/tools/ffu_parse.py b/tools/ffu_parse.py new file mode 100644 index 0000000..ba5c033 --- /dev/null +++ b/tools/ffu_parse.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +"""ffu_parse.py — разбор FFU v1 (Lumia): security header, manifest, GPT, store. +Использование: ./tools/ffu_parse.py fw/dl/XXX.ffu [--gpt] [--manifest] +WIP: только чтение, без проверки подписей/hashtable. +""" +import struct +import sys +import uuid +import mmap + +ACC = {0: "BEGIN", 1: "SEQ", 2: "END"} + + +def guid_le(b): + return str(uuid.UUID(bytes_le=b)) + + +def parse(path): + raw = open(path, "rb") + f = mmap.mmap(raw.fileno(), 0, access=mmap.ACCESS_READ) + sec = f.read(32) + cb, sig, chunk_kb, alg, cat_sz, hash_sz = struct.unpack(" 0, "no valid GPT" + assert gpt_off > 0, "no GPT" + info["gpt_chunk"] = (gpt_off - hdr_size) // chunk + hdr = bytes(f[gpt_off:gpt_off + 92]) + assert hdr[:8] == b"EFI PART", "no GPT" + nent, esz = struct.unpack("