84 lines
3.1 KiB
Python
84 lines
3.1 KiB
Python
#!/usr/bin/env python3
|
|
"""dfpReport 编解码器 — R37 攻坚定论 (2026-08-29)
|
|
|
|
算法 (R35-R37 三轮活体捕获 + 12/12 历史密文解密验证):
|
|
明文 JSON -> gzip (zlib deflate, gzip wrapper, 头 1f8b08 00 00000000 02 03)
|
|
-> C = RC4(key) keystream XOR gzip (逐字节, 长度保持, 标准 KSA/PRGA 无 drop)
|
|
-> wire body = 密文整段 (前 10B 即所谓 magic 571882cf664bb39401ee = keystream XOR gzip 头,
|
|
不是魔数! 密钥同则 magic 同)
|
|
-> 尾部 10B 为 gzip 流之后的附加段 (decompressobj unused_data)
|
|
|
|
密钥 = 32 字符 hex ASCII 串 (如 865a4924a40897ac1fcfe6b4c2abc798), 每注册轮换.
|
|
捕获点: libhydeviceid.so!0x60e6c onEnter x1 = 密钥串 (tools/frida/hook_hy.js).
|
|
XXTEA/静态密钥 f15e... 与 dfpReport 无关 (那是 hdid 子系统) — 45 函数零调用之谜即此.
|
|
"""
|
|
from __future__ import annotations
|
|
import sys, zlib
|
|
|
|
|
|
def rc4_keystream(key: bytes, n: int) -> bytes:
|
|
S = list(range(256))
|
|
j = 0
|
|
for i in range(256):
|
|
j = (j + S[i] + key[i % len(key)]) & 0xFF
|
|
S[i], S[j] = S[j], S[i]
|
|
out = bytearray()
|
|
i = j = 0
|
|
for _ in range(n):
|
|
i = (i + 1) & 0xFF
|
|
j = (j + S[i]) & 0xFF
|
|
S[i], S[j] = S[j], S[i]
|
|
out.append(S[(S[i] + S[j]) & 0xFF])
|
|
return bytes(out)
|
|
|
|
|
|
def decrypt(body: bytes, key: bytes) -> bytes:
|
|
"""body = wire body (magic 10B + cipher) -> 指纹 JSON 明文."""
|
|
ks = rc4_keystream(key, len(body))
|
|
plain = bytes(a ^ b for a, b in zip(body, ks))
|
|
d = zlib.decompressobj(31) # gzip
|
|
json_bytes = d.decompress(plain, 1 << 20)
|
|
return json_bytes
|
|
|
|
|
|
def encrypt(json_bytes: bytes, key: bytes) -> bytes:
|
|
"""指纹 JSON -> wire body. 尾部 10B 附加段按全 0 处理 (服务端解 gzip 忽略)."""
|
|
gz = gzip_wrap(json_bytes)
|
|
ks = rc4_keystream(key, len(gz) + 10)
|
|
return bytes(a ^ b for a, b in zip(gz + b"\x00" * 10, ks))
|
|
|
|
|
|
def gzip_wrap(json_bytes: bytes) -> bytes:
|
|
co = zlib.compressobj(9, zlib.DEFLATED, 31) # gzip wrapper
|
|
gz = co.compress(json_bytes) + co.flush()
|
|
# 对齐 turing 原生 gzip 头: OS 字节 = 0x03 (Unix), Python 写 0x13
|
|
return gz[:9] + b"\x03" + gz[10:]
|
|
|
|
|
|
def _selftest():
|
|
MAGIC = bytes.fromhex("571882cf664bb39401ee")
|
|
KEY = b"865a4924a40897ac1fcfe6b4c2abc798"
|
|
body = open("evidence/dfp_live/dfp_body_4303.bin", "rb").read()
|
|
i = body.find(MAGIC)
|
|
wire = body[i:]
|
|
js = decrypt(wire, KEY)
|
|
assert js.startswith(b'{"Athena"'), js[:40]
|
|
print(f"decrypt OK: {len(js)}B JSON")
|
|
gz = gzip_wrap(js)
|
|
re_enc = encrypt(js, KEY)
|
|
n = len(gz)
|
|
print(f"re-encrypt: gzip {n}B + 10B tail vs wire {len(wire)}B, "
|
|
f"cipher part {'IDENTICAL' if re_enc[:n] == wire[:n] else 'DIFFERS'} "
|
|
f"(magic10 {'==' if re_enc[:10] == wire[:10] else '!='})")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) >= 3 and sys.argv[1] == "dec":
|
|
key = sys.argv[3].encode()
|
|
body = open(sys.argv[2], "rb").read()
|
|
MAGIC = bytes.fromhex("571882cf664bb39401ee")
|
|
i = body.find(MAGIC)
|
|
sys.stdout.buffer.write(decrypt(body[i:], key))
|
|
else:
|
|
_selftest()
|