- 诊断报告: attach 主进程静默退出/EGL 崩溃, 仅约 4s 窗口可抓帧 - scripts: attach/spawn/hook/emu 系列 Frida 脚本与抓帧/验证工具 - evidence: identity/reqchain/frame/inputbuf/magic_buf/propedge 抓取样本, emu_* 存活对比, diag_* 策略实验, baseline 裸测基准
105 lines
5.1 KiB
Python
105 lines
5.1 KiB
Python
#!/usr/bin/env python3
|
|
"""dfpReport 生成流程 python 验证模型。
|
|
|
|
目标: 用手头真实 wire 验证对格式的理解:
|
|
wire = HTTP POST / (wsapi.huya.com, okhttp/3.14.9)
|
|
+ body(taf/wup): 长度头 + servant + "dfpReport" + "tReq"
|
|
+ MAGIC(571882cf664bb39401ee) + cw
|
|
cw = [明文JSON ^ keystream][collection ^ keystream]
|
|
其中 keystream 是每帧独立随机流(未知生成器)。本脚本验证"格式+布局"理解,
|
|
并验证给定完整明文(JSON+collection)与keystream可精确重建真实wire。
|
|
"""
|
|
from __future__ import annotations
|
|
import json, binascii, struct, re
|
|
|
|
MAGIC = bytes.fromhex('571882cf664bb39401ee')
|
|
PREFIX_JSON = b'{"appId":"5008","appVer":"13.4.22"'
|
|
# 真机已验证的完整明文 JSON(含三元组)
|
|
REAL_JSON = ('{"appId":"5008","appVer":"13.4.22","appkey":"865a4924a40897ac1fcfe6b4c2cbb0e3",'
|
|
'"channel":"xiaomi","deviceId":"02df398797432eadefcc12767119ad5e80999389",'
|
|
'"deviceName":"M2102J2SC","hdid":"7c5387e0539c023c31c4ff0e807e7256117385ee",'
|
|
'"heightPixels":"2120","isCloud":0,"isForbidLog":1,"isHome":0,"isPre":0,'
|
|
'"openAppId":"","savePath":"/data/user/0/com.duowan.kiwi/files/huyaudb",'
|
|
'"sdkVer":"1.0.80138","servantName":"huyaudbwebui",'
|
|
'"shareAppDataPath":"/data/user/0/com.duowan.kiwi/files/huyaudb",'
|
|
'"systemInfo":"android","systemVer":"M2102J2SC,30,11",'
|
|
'"terminalType":1,"testEnv":0,"widthPixels":"1080"}')
|
|
|
|
def build_json(triple=None, device_name='M2102J2SC', system_ver='M2102J2SC,30,11'):
|
|
t = triple or dict(appkey='865a4924a40897ac1fcfe6b4c2cbb0e3',
|
|
channel='xiaomi',
|
|
deviceId='02df398797432eadefcc12767119ad5e80999389',
|
|
hdid='7c5387e0539c023c31c4ff0e807e7256117385ee')
|
|
return ('{"appId":"5008","appVer":"13.4.22","appkey":"%(appkey)s","channel":"%(channel)s",'
|
|
'"deviceId":"%(deviceId)s","deviceName":"'+device_name+'","hdid":"%(hdid)s",'
|
|
'"heightPixels":"2120","isCloud":0,"isForbidLog":1,"isHome":0,"isPre":0,'
|
|
'"openAppId":"","savePath":"/data/user/0/com.duowan.kiwi/files/huyaudb",'
|
|
'"sdkVer":"1.0.80138","servantName":"huyaudbwebui",'
|
|
'"shareAppDataPath":"/data/user/0/com.duowan.kiwi/files/huyaudb",'
|
|
'"systemInfo":"android","systemVer":"'+system_ver+'",'
|
|
'"terminalType":1,"testEnv":0,"widthPixels":"1080"}') % t
|
|
|
|
def parse_wire(wire):
|
|
"""从真实 wire 提取结构化字段. 返回 dict."""
|
|
body_start = wire.find(b'\r\n\r\n') + 4
|
|
body = wire[body_start:]
|
|
# taf 头: 4字节大端长度, 然后 TLV
|
|
# 简化解析: servant名
|
|
mi = body.find(MAGIC)
|
|
cw = body[mi+10:]
|
|
# JSON 密文段长度 + 明文校验
|
|
result = {
|
|
'body': body,
|
|
'cw': cw,
|
|
'magic_offset_in_body': mi,
|
|
'json_len': None, 'coll': None,
|
|
}
|
|
# 用已知JSON前缀恢复ks并反推JSON长度定位
|
|
if len(cw) >= len(PREFIX_JSON):
|
|
# JSON数据是明文XOR (明文可打印). 但我们不知道JSON结束位置(collection开始).
|
|
# 用"JSON固定长度"真机值(586)推断: 若明文JSON=XOR后全是可打印ascii且结构符合.
|
|
jlen = len(REAL_JSON.encode())
|
|
coll = cw[jlen:]
|
|
result['json_len'] = jlen
|
|
result['json_offset_in_cw'] = 0
|
|
result['coll'] = coll
|
|
return result
|
|
|
|
def verify_rebuild(wire):
|
|
"""验证: 用解析出的 cw, 从"明文JSON+keystream"能否精确重建 cw[:json_len]."""
|
|
p = parse_wire(wire)
|
|
cw = p['cw']
|
|
jb = REAL_JSON.encode()
|
|
jlen = len(jb)
|
|
# keystream = cw[:jlen] ^ jb
|
|
ks_json = bytes(cw[i]^jb[i] for i in range(jlen))
|
|
# 重建 encoded_json = jb ^ ks_json = jb (恒等, 因为ks由它们导出)
|
|
# 真正验证: 检查明文JSON在 cw 中位置对应的XOR是否=keystream连续(即JSON在此) — 无法独立验证,
|
|
# 但可验证: 明文JSON偏移与 ta f 头一致.
|
|
# 关键验证: keystream 在 JSON 段与 collection 段是否"同一生成器连续流".
|
|
# 我们对比 JSON 段 ks 和 collection 段(from某plaintext假设). 目前无collection明文故无法.
|
|
# 输出 keystream JSON段, 供分析.
|
|
return {
|
|
'jlen': jlen, 'cw_len': len(cw),
|
|
'ks_head': ks_json[:48].hex(),
|
|
'coll_len': len(p['coll']),
|
|
'ks_json_randomness': len(set(ks_json)),
|
|
}
|
|
|
|
def main():
|
|
frames = json.load(open('evidence/frame_real.json'))
|
|
wire = binascii.unhexlify(frames[0])
|
|
p = parse_wire(wire)
|
|
print("wire 总长: %d, body 长: %d, cw 长: %d" % (len(wire), len(p['body']), len(p['cw'])))
|
|
print("MAGIC 在 body 偏移: %d" % p['magic_offset_in_body'])
|
|
print("JSON 密文长度(586), collection 长度: %d" % len(p['coll']))
|
|
v = verify_rebuild(wire)
|
|
print("JSON keystream 前48B:", v['ks_head'])
|
|
print("keystream JSON段随机性(不同字节):", v['ks_json_randomness'], "/ 586")
|
|
# 打印 taf 头可读字符串
|
|
b = p['body']
|
|
for kw in [b'huyaudbwebui', b'dfpReport', b'android', b'tReq']:
|
|
print("body 含 '%s': @%d" % (kw.decode(errors='replace'), b.find(kw)))
|
|
|
|
if __name__ == '__main__':
|
|
main() |