Add signature-derived-key coverage, PID attach, MMKV; fix stale question count
New: references/signature-derived-keys.md (apps that use their own signing certificate as crypto key material: detection greps, why offline extraction is unreliable -- the runtime value is a certificate DER from inside the PKCS#7 chain, not the .RSA container -- plus the hardcode-then-verify procedure); scripts/sig_probe.py (offline candidates via --apk, authoritative read via --live, both exercised); pitfalls.md P27 (rebuilt APK installs and renders but every signed request returns empty/-1 signing params). Updated: dynamic-frida.md (attach by PID when enumerate_processes omits the target; verify runtime/Java-bridge availability before blaming the script); runtime-data.md (MMKV format, parse/write snippet, crc32 and in-memory-overwrite traps); server-api.md (route the signature-derived-key case to the new reference); SKILL.md and README.md (new classification question, corrected question count, index entries).
This commit is contained in:
@@ -18,6 +18,7 @@ Sometimes the cheapest fix is not code at all, but a value in app data. And some
|
||||
/data/data/<pkg>/ (== /data/user/0/<pkg>)
|
||||
├── files/
|
||||
│ ├── datastore/*.preferences_pb AndroidX DataStore (protobuf)
|
||||
│ ├── mmkv/<name> MMKV (Tencent) — one file per named store
|
||||
│ └── ...
|
||||
├── shared_prefs/*.xml SharedPreferences
|
||||
├── databases/*.db SQLite (Room, etc.)
|
||||
@@ -67,6 +68,68 @@ Verify by reading the file back with `xxd` before launching.
|
||||
|
||||
Simple XML. Edit with the app stopped. Types are explicit (`<boolean>`, `<int>`, `<long>`, `<string>`). Same ownership rules.
|
||||
|
||||
## MMKV (Tencent)
|
||||
|
||||
Common in apps whose SDK stack is Chinese-market. One file per named store under `files/mmkv/`,
|
||||
with a `.crc` companion. It is **not** a database and **not** XML — it is a small custom binary
|
||||
format:
|
||||
|
||||
```
|
||||
offset 0 uint32 actual_size size of the data region
|
||||
offset 4 uint32 crc32 over the data region
|
||||
offset 8 data region repeated: varint key_len, key, varint val_len, value
|
||||
```
|
||||
|
||||
Files are preallocated, so trailing zeroes are normal; `actual_size` is what matters.
|
||||
|
||||
Parsing is mechanical, and no library is needed:
|
||||
|
||||
```python
|
||||
import struct
|
||||
|
||||
def parse(blob):
|
||||
size = struct.unpack_from('<I', blob, 0)[0]
|
||||
pos, end, out = 8, 8 + size, []
|
||||
|
||||
def varint(p):
|
||||
v = s = 0
|
||||
while True:
|
||||
b = blob[p]; p += 1
|
||||
v |= (b & 0x7F) << s
|
||||
if not b & 0x80:
|
||||
return v, p
|
||||
s += 7
|
||||
|
||||
while pos < end:
|
||||
klen, pos = varint(pos); key = blob[pos:pos + klen]; pos += klen
|
||||
vlen, pos = varint(pos); val = blob[pos:pos + vlen]; pos += vlen
|
||||
out.append((key, val))
|
||||
return out
|
||||
```
|
||||
|
||||
Writing a change back means rebuilding the region and **recomputing both header fields**:
|
||||
|
||||
```python
|
||||
import struct, zlib
|
||||
|
||||
body = new_region_bytes
|
||||
blob = bytearray(capacity) # keep the original file length
|
||||
struct.pack_into('<I', blob, 0, len(body))
|
||||
struct.pack_into('<I', blob, 4, zlib.crc32(body) & 0xFFFFFFFF)
|
||||
blob[8:8 + len(body)] = body
|
||||
```
|
||||
|
||||
Cautions:
|
||||
|
||||
- **A wrong crc32 makes the library throw the whole store away.** The visible symptom is "my
|
||||
edit did nothing" or "the app reset every setting", never an error.
|
||||
- **Values are raw bytes**, not always text. JSON is common; a serialized protobuf or a small
|
||||
encrypted payload is also common (`scripts/blob_decode.py` searches the framing).
|
||||
- **The in-memory copy wins until the process restarts.** `am force-stop` before editing and
|
||||
re-launch after, or the running app overwrites your change on exit.
|
||||
- **Do not delete the `.crc` companion.** Leave it in place when hand-editing the store; it is
|
||||
validated and regenerated by the library.
|
||||
|
||||
## SQLite
|
||||
|
||||
```bash
|
||||
|
||||
Reference in New Issue
Block a user