ars18
May 1, 2026, 3:18pm
21
Can you send me anyway? I like to verify things, and I can update the docs.
I like documenting the RE it’s cool to look at and can help for other projects.
1 Like
That means I’ll have to also. And I’ll have to update hardcoded links in README and in info in app…
1 Like
ars18
May 1, 2026, 3:42pm
24
net::ERR_NAME_NOT_RESOLVED
1 Like
ars18
May 1, 2026, 3:54pm
26
1 Like
Ah. Interesting. I think I know why but it’s almost shabbos here. I updated my app it now supports dual SIM qin f25. Good shabbos!
4 Likes
ars18
May 1, 2026, 5:18pm
28
Try it out, all functions plz.
ars18
May 1, 2026, 8:36pm
29
Tiq m5 support confirmed.
2 Likes
And @flipphoneguy ’s app works on the tiq as well!
2 Likes
Why does it show dual SIM on F21?
1 Like
So it can support other devices that have dual sim.
2 Likes
True. But it actually shows me ‘both’ of my IMEI’s.
1 Like
What does it say by the second one?
Some random IMEI.
And for some reason it shows both twice.
1 Like
ars18
May 1, 2026, 10:48pm
36
Added support for dual sim.
Current supported devices:
Qin F21 Pro
Qin F25
Tiq M5
committed 10:29PM - 01 May 26 UTC
* Add dual-SIM slot support for F25
imei_tool.py:
- `-s 1|2` flag (default 1)… selects which IMEI slot to read/write
- `read` prints both slots; unpopulated slot prints `(empty)`
- `write` verifies both slots after patching
live_patch.sh:
- Adaptive prompt: dual-SIM → "Change which IMEI? [1/2/n]";
single-SIM → "Change IMEI? [y/N]" (detected from `(empty)` count)
- Passes `-s "$slot"` through to imei_tool.py write
* Document dual-SIM (F25) support and cross-device validation
README:
- Retitle scope to F21 Pro (single-SIM) + F25 (dual-SIM)
- Add `-s 1|2` to usage examples
- Split verification: F21 Pro live (live_patch.sh + fastboot)
vs F25 firmware-image-only (no hardware)
- Add Related section linking flipphoneguy/f21-imei-switcheroo-app
docs/imei_tool.md:
- New `_slot_offset` and `_print_both_imeis` sections
- `read_imei` / `patch_imei` signatures updated with `slot=1`
- main() doc: `-s 1|2` flag, both-slot read output, both-slot verify
docs/live_patch.md:
- Replace single-IMEI awk parsing with the `(empty)`-counting flow
- New "Adaptive prompt" section showing the dual-SIM and single-SIM
branches verbatim
docs/format.md:
- Slot 1 / slot 2 labels in the offset map
- Slot 2: populated on dual-SIM (F25), zero/0xFF on single-SIM
- imei_tool.py patches whichever block `-s 1|2` selects
docs/reverse_engineering.md:
- New "Cross-device validation (F25, firmware-only)" appendix
- Three LD0B_001 copies (two byte-identical live + factory backup
at 0x1c04000); header bytes [0x2a:0x2c] differ between live and backup
- Live filler 00 00, factory-backup filler FF FF (both checksum-valid)
- Both slots populated with distinct 15-digit IMEIs and MD5-XOR-valid
checksums; round-trip confirmed for both slots
- Explicit "what was NOT checked": no live F25 hardware, no F25
bad-checksum behavior, no other dual-SIM device
* Fix _patch_all_copies: patch each copy in place
Old behavior: read the first LD0B_001 from the partition image, compute
one patched 384-byte buffer, blast it onto every header-matching copy.
This works only when same-header copies are body-identical; if any copy
has a different non-target slot, that slot gets clobbered.
Surfaced on TIQ M5 (MT6761), where four LD0B_001 copies share a
byte-identical 0x40-byte header but differ in body — three live copies
plus one with a distinct slot 1 IMEI. Patching slot 2 with the old code
overwrote the live copies' slot 1 with the distinct copy's slot 1.
New behavior: walk every signature match, gate by header equality with
the first match (so unrelated LD0B blobs in other partitions stay
untouched), then patch each copy in place — only the requested slot's
32-byte ciphertext is rewritten in each. Other slots and surrounding
bytes are preserved per copy.
Also adds an explicit length check (`p + LD0B_SIZE > len(img)`) to skip
truncated finds at the end of an image instead of letting bytearray
slice assignment extend the buffer.
Verified byte-identical output on F21 Pro (15-copy real partition image,
slot 1 and slot 2) and F25 (firmware image, slot 1 and slot 2): old and
new code produce identical bytes because those scenarios never had
body-differing same-header copies. Verified correct on TIQ M5 hardware:
flashed a patched nvdata back via mtkclient, both slots read as the
written IMEI in `service call iphonesubinfo`.
* Add TIQ M5 (MT6761) as live-verified third device
imei_tool.py:
- Module docstring widened from "DuoQin F21 Pro / F25 IMEI Tool" to
"MTK NVRAM IMEI Tool" with explicit verification scope per device
- `-s 2` examples mention TIQ M5 alongside F25
README.md:
- F21 Pro + F25 + TIQ M5 in the title description and "How it works"
- Verification status: TIQ M5 added as live-device, dual-SIM, both
slots, mtkclient flash + boot
- "patches every backup copy with a matching header" → tightened to
"patches every header-matching copy in place" with explicit note
that distinct-header copies (F25 factory backup) are skipped
docs/imei_tool.md:
- `_patch_all_copies` description rewritten to match the per-copy
in-place semantic (signature `(img, sig, header_len, slot, imei)`)
- Per-device explanation of when same-header bodies differ — F21 Pro
all 15 byte-identical, F25 backup excluded by header, TIQ M5 four
copies with one distinct body
- Partition-image-mode "verified on F21 Pro" line expanded to also
cite TIQ M5 mtkclient flash + boot
docs/format.md:
- Page intro broadened from F21 Pro–only to MT67xx (verified on
F21 Pro, F25, TIQ M5)
- Slot 2 populated/empty example now lists F25 and TIQ M5
- Signature-stability claim attests across all three verified devices
- "only targets the F21 Pro" replaced with the actual verified set
docs/live_patch.md:
- "live, rooted F21 Pro" → "live, rooted MTK device" with pointer
to README's per-device verification status
- Header code block updated to match the actual stripped script
(just `#!/bin/bash`, no banner comment)
docs/reverse_engineering.md:
- New "Hardware validation (TIQ M5, dual-SIM)" section: firmware-level
constants check, decryption check on the mtkclient-pulled nvdata
(4 copies = 3 byte-identical bodies + 1 distinct body, structural
fact only — no live/leftover inference), the bug surfaced and fixed,
and the live-flash test (both IMEIs = 123456789012345 on the booted
device)
- Tightened the F25 cross-device section's runtime-evidence sentence
to acknowledge TIQ M5 hardware confirmation alongside F21 Pro
* Surface imei_tool.py errors in live_patch.sh; spelling
live_patch.sh:
- "Cannot read LD0B_001 from device" → "Cannot read $IMEI_PATH from
device" (path included; cat's stderr no longer suppressed so its
specific error is shown above the die line)
- "Read failed" → "Read failed (imei_tool.py error above)"; drop
`2>/dev/null` so the python tool's specific error reaches the user
- "Patch failed" → "Patch failed (imei_tool.py error above)" for
consistency
docs/live_patch.md:
- Code blocks updated to match the script's new wording and stderr
handling
- Failure-modes table: stale "run imei_tool.py read backup manually
to surface the underlying error" advice replaced with "the exact
reason is printed above by imei_tool.py"; new rows for the new
"Read failed" / "Patch failed" wording
US spellings:
- docs/live_patch.md: "Artefacts" → "Artifacts"
- README.md: "homogenised" → "homogenized"
* Binary-safe pull on Android 13/Magisk; live verify on TIQ M5
live_patch.sh:
- Pull mechanism switched from `adb exec-out su -c "cat $IMEI_PATH"`
to `cp via su` to /sdcard + `adb pull`. The original form returns
387 bytes on TIQ M5 / Android 13 + Magisk (CRLF injection — every
`0x0a` becomes `0x0d 0x0a`); the cp + SYNC-protocol path is binary-
safe by construction. Verified end-to-end on F21 Pro / Android 11
and TIQ M5 / Android 13 in the same session.
docs/live_patch.md:
- Pull section rewritten to match the new mechanism, with the CRLF
observation called out and a pointer to the RE doc's evidence
- Failure-modes table: rows updated for the new pull errors
(`Cannot stage … at /sdcard/LD0B_001_pull` and `adb pull failed`)
- Artifacts section: corrected the `patched_LD0B_001.bin` annotation —
it's created when you confirm the patch, not when you say "y" to
the (separate) reboot prompt
- Header says live-tested on F21 Pro and TIQ M5
docs/imei_tool.md:
- Partition-image-mode dump example updated to the binary-safe form
(`dd → /sdcard via su` + `adb pull`); the old `adb exec-out su -c dd`
form is kept as a callout with the same CRLF caveat
- `read_imei` description: clarified that `_print_both_imeis` is what
renders `(empty)`; `live_patch.sh` only matches against that string
docs/reverse_engineering.md:
- Reproducibility step 3 now shows the binary-safe pull, with a note
on the older `adb exec-out su -c cat` form working on Android 11
but failing on Android 13 / Magisk
README.md:
- Verification status: TIQ M5 entry extended to cover the
`live_patch.sh` end-to-end runs (both slots, modem persists across
reboot, pull mechanism note)
1 Like
Fixing the double now. Really stupid mistake. As for showing 2 IMEI’s that’s extremely weird. Can you try @ars18 ’s tool and see if ‘read’ also shows 2? I don’t see in what way it can go wrong. Assuming the docs are correct that the test is 0 padded it’s very weird.
Or if you have no patience, can you send me your LD0B_001 file
Edit: while I don’t have a physical f21 to test the app, I tested the Java code in the app on a raw LD0B_001 from a f21 and it only showed 1 IMEI. Can someone else please confirm if it shows 2 IMEI’s by them? The issue of displaying twice will be fixed shortly
@farrict try it now. I fixed the double render and might have fixed the 2 SIM issue. Thanks a ton for reporting the issue!!
@ars18 I updated my termux wrapper for dual SIM and fixed merge conflicts on README. (Next time you edit you’re gonna fix the merge conflicts . Gets annoying in a terminal to edit the diff lines…)
ars18
May 3, 2026, 12:59am
39
It builds character I’m trying to help
Also, I’m gonna have to test the Termux version on both the f21 and m5
1 Like
It’s literally just copy paste your script just instead of adb shell su -c is su -c directly in the shell. Look at it. If live patch works, by definition the termux version should too. No?