feat(dfp): 🔑 RC4 key=APK内嵌appkey常量(datadiv@3912240), 全流程零设备依赖闭环 (R38-R39)

This commit is contained in:
yml2213
2026-08-29 11:01:51 +08:00
parent 4868a3b0e8
commit 5fa1f6d082
13 changed files with 43643 additions and 2 deletions
+58
View File
@@ -0,0 +1,58 @@
#!/usr/bin/env python3
"""R36: hook libz deflate/inflate — 抓 XXTEA 输入明文 + 隐藏加密路径 backtrace."""
import json, subprocess, time
from pathlib import Path
import frida
REMOTE="127.0.0.1:31878"; ADB="5dd8c93f"; PACKAGE="com.duowan.kiwi"
RE=Path("/Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0")
HERE=Path(__file__).resolve().parent.parent
OUT=HERE/"evidence"/("keytrace_"+time.strftime("%H%M%S")+".json")
def clear_turing():
for d in ("app_turingdfp","app_turingfd"):
subprocess.run(["adb","-s",ADB,"shell","su","-c",f"rm -rf /data/data/{PACKAGE}/{d}/*"],capture_output=True)
subprocess.run(["adb","-s",ADB,"shell","su","-c",f"find /data/data/{PACKAGE} -name 'resinfo*' -delete"],capture_output=True)
def main():
clear_turing()
d=frida.get_device_manager().add_remote_device(REMOTE)
subprocess.run(["adb","-s",ADB,"shell","am","force-stop",PACKAGE],capture_output=True)
time.sleep(1.5)
pid=d.spawn([PACKAGE]); print(f"[*] spawn pid={pid}",flush=True)
s=d.attach(pid)
try:
b=s.create_script((RE/"evidence/scripts/bypass_msaoaid_maps_skip_cleanup.js").read_text()); b.load()
except Exception as e: print(f"[*] bypass err {e}",flush=True)
d.resume(pid)
result={}; got={"post":False,"out":False}
seen_fns=set()
def events_ok(p):
seen_fns.add(p.get('fn')); return True
def on(m,_):
if m.get("type")=="error":
txt=str(m)
if "ClassNotFoundException" in txt: return
print(f"[JS] {txt[:160]}",flush=True); return
p=m.get("payload") or {}
ev=p.get("event")
if ev=="post": got["post"]=True; print(f"[+] POST {p['num']}B",flush=True)
elif ev=="armed-hy": print("[*] hy chain armed",flush=True)
elif ev=="call":
if len(seen_fns)<99: pass
elif ev=="call" and events_ok(p): got["out"]=True
elif ev=="deflate-found": print(f"[*] deflate export in {p['mod']}",flush=True)
elif ev=="inflate-in": print(f"[+] inflate-in {p['len']}B via {p['mod']}",flush=True)
result.setdefault(ev or "misc",[]).append(p)
sc=s.create_script((HERE/"tools/frida/hook_keytrace.js").read_text())
sc.on("message",on); sc.load()
t0=time.time()
while time.time()-t0<150:
time.sleep(2)
if got["out"] and got["post"]: time.sleep(4); break
json.dump(result,open(OUT,"w"),indent=2)
print(f"[*] saved {OUT}",flush=True)
try: s.detach()
except Exception: pass
if __name__=="__main__": main()
+53
View File
@@ -0,0 +1,53 @@
#!/usr/bin/env python3
"""R38b: RC4 key 诞生点追踪 (MD5 transform 消息积累)."""
import json, subprocess, time
from pathlib import Path
import frida
REMOTE="127.0.0.1:31878"; ADB="5dd8c93f"; PACKAGE="com.duowan.kiwi"
RE=Path("/Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0")
HERE=Path(__file__).resolve().parent.parent
OUT=HERE/"evidence"/("keytrace2_"+time.strftime("%H%M%S")+".json")
def clear_turing():
for d in ("app_turingdfp","app_turingfd"):
subprocess.run(["adb","-s",ADB,"shell","su","-c",f"rm -rf /data/data/{PACKAGE}/{d}/*"],capture_output=True)
subprocess.run(["adb","-s",ADB,"shell","su","-c",f"find /data/data/{PACKAGE} -name 'resinfo*' -delete"],capture_output=True)
def main():
clear_turing()
d=frida.get_device_manager().add_remote_device(REMOTE)
subprocess.run(["adb","-s",ADB,"shell","am","force-stop",PACKAGE],capture_output=True)
time.sleep(1.5)
pid=d.spawn([PACKAGE]); print(f"[*] spawn pid={pid}",flush=True)
s=d.attach(pid)
try:
b=s.create_script((RE/"evidence/scripts/bypass_msaoaid_maps_skip_cleanup.js").read_text()); b.load()
except Exception as e: print(f"[*] bypass err {e}",flush=True)
d.resume(pid)
result={}; state={"post":False,"key":False}
def on(m,_):
if m.get("type")=="error":
t=str(m)
if "ClassNotFoundException" not in t: print(f"[JS] {t[:150]}",flush=True)
return
p=m.get("payload") or {}
ev=p.get("event")
if ev=="post": state["post"]=True; print("[+] POST fired",flush=True)
elif ev=="key-site": state["key"]=True; print(f"[+] KEY ARRIVED: {p.get('key')} md5calls={p.get('md5calls')} states={p.get('nstates')}",flush=True)
elif ev=="hy-armed": print("[*] hy armed",flush=True)
elif ev=="java-md5-hooked": print("[*] java digest hooked",flush=True)
elif ev=="key-copies-done": print(f"[*] key copies: {p.get('n')}",flush=True)
result.setdefault(ev or "misc",[]).append(p)
sc=s.create_script((HERE/"tools/frida/hook_keytrace2.js").read_text())
sc.on("message",on); sc.load()
t0=time.time()
while time.time()-t0<220:
time.sleep(3)
if state["key"] and state["post"]: time.sleep(5); break
json.dump(result,open(OUT,"w"),indent=2)
print(f"[*] saved {OUT} post={state['post']} key={state['key']}",flush=True)
try: s.detach()
except Exception: pass
if __name__=="__main__": main()
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/env python3
"""R39: 登录流程 md5 输入捕获 — 两阶段配方 (与 hook_final_capture.py 同款):
spawn挂起 -> 双bypass装载 -> resume -> 稳定11s -> patch_guard -> 业务钩子
"""
import json, time
from pathlib import Path
import frida
REMOTE="127.0.0.1:31878"; PACKAGE="com.duowan.kiwi"
RE=Path("/Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0")
HERE=Path(__file__).resolve().parent.parent
OUT=HERE/"evidence"/("loginmd5_"+time.strftime("%H%M%S")+".json")
def main():
d=frida.get_device_manager().add_remote_device(REMOTE)
pid=d.spawn([PACKAGE])
print(f"[*] spawned {pid}",flush=True)
s=d.attach(pid)
# 双重防护: callsite bypass + maps 掩盖
s.create_script((RE/"evidence/scripts/bypass_msaoaid_maps_art_callsite.js").read_text()).load()
s.create_script((RE/"evidence/scripts/mask_frida_maps_only.js").read_text()).load()
d.resume(pid)
print("[*] resumed, 稳定 11s...",flush=True)
time.sleep(11)
s.create_script((RE/"evidence/scripts/patch_guard_block_termination.js").read_text()).load()
print("[*] patch_guard on",flush=True)
result={}; state={"udb":0}
def on(m,_):
if m.get("type")=="error":
t=str(m)
if "ClassNotFoundException" not in t: print(f"[JS] {t[:150]}",flush=True)
return
p=m.get("payload") or {}
ev=p.get("event")
if ev=="udb-md5":
state["udb"]+=1
print(f"[+] udb-md5 #{state['udb']} in1={str(p.get('in1'))[:100]} out={str(p.get('out'))[:80]}",flush=True)
elif ev=="udb-armed": print("[*] udb md5 armed",flush=True)
elif ev=="java-digest":
out=p.get('out','')
if out.startswith('865a') or out.startswith('') and False: pass
print(f"[J] digest {p.get('algo')} out={out[:16]} in={repr((p.get('in_parts') or ''))[:70]}",flush=True)
result.setdefault(ev or "misc",[]).append(p)
sc=s.create_script((HERE/"tools/frida/hook_login_md5.js").read_text())
sc.on("message",on); sc.load()
print("[*] 请在 App 中: 退出登录 -> 账号密码重新登录 (窗口 8 分钟)",flush=True)
t0=time.time()
while time.time()-t0<480:
time.sleep(5)
if state["udb"]>=12: time.sleep(6); break
json.dump(result,open(OUT,"w"),indent=2)
print(f"[*] saved {OUT} udb={state['udb']}",flush=True)
try: s.detach()
except Exception: pass
if __name__=="__main__": main()