feat(huya): Java桥主动调getCred成功 - 活体hyCred(152b64/114B)到手并铸出新证书

This commit is contained in:
yml2213
2026-08-25 17:16:40 +08:00
parent 69c089fdeb
commit 0ade681881
4 changed files with 115 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
{"p1": "010400353030381400c25220f81f60cf64ee54e83ef1eab6bdd047b5af28003032646633393837393734333265616465666363313237363731313961643565383039393933383972000a20171d4885bb9bb40f29517ab490f3634a0640e942e24039e2f471a5a66a0c64662b68c43f64a90ab982d8298bfc5de4e58a0bb6617a7ab8ecc730cde4a28bd828261096ca95b6247bba5e4714395166f9a22eb0c9954e6d0890ba40fa951e70e63c7c4c8e8e5547f6ca029830f31adbe8", "cert_hex": "0c201aeb9aa1d4c9e6fc6d5628b1cb936a3b0c360b3914ed9b94f2cf4808490594202cbaa481870772fe2a4df9a94fdb8a0e41312514470c77cbfa586558f87309bea9c2abc3b6948072d9c345292866c8517e60cc7cd93f2c2bb82f8d8a255da88418e86fd21309d9306024a8006b99540c58054f823c7d8924b56f841c8dbb10d093ddf859b21625ba8bb1a34ab8b03d27b5a3ed92a67750464225ba8b9be3cd5c359369ef783b7f4487614e65bc04a159b4e75bd74c62f9cb9755d765ab007748"}
+1
View File
@@ -0,0 +1 @@
[{"type": "armed"}, {"type": "getcred", "uid": "0x11751b8656f", "out": {"len": 152, "v": "43694158485569467535753044796c526572535138324e4b426b447051754a414f654c306361576d6167786b5a69746f7844396b7151713567746770692f7864354f574b43375a68656e7134374d63777a6553696939676f4a684357797057324a487536586b63554f56466d2b614975734d6d56546d30496b4c70412b705565634f59386645794f6a6c564839736f436d44447a4774766f"}}, {"type": "java_cred", "cls": "com.huyaudbunify.HuyaAuth", "r": "com.huyaudbunify.bean.ResGetCred@9bed1cb"}]
+1
View File
@@ -0,0 +1 @@
{"uid": 1199666914671, "hyCred_b64": "CiAXHUiFu5u0DylRerSQ82NKBkDpQuJAOeL0caWmagxkZitoxD9kqQq5gtgpi/xd5OWKC7Zhenq47McwzeSii9goJhCWypW2JHu6XkcUOVFm+aIusMmVTm0IkLpA+pUecOY8fEyOjlVH9soCmDDzGtvo", "bin_hex": "0a20171d4885bb9bb40f29517ab490f3634a0640e942e24039e2f471a5a66a0c64662b68c43f64a90ab982d8298bfc5de4e58a0bb6617a7ab8ecc730cde4a28bd828261096ca95b6247bba5e4714395166f9a22eb0c9954e6d0890ba40fa951e70e63c7c4c8e8e5547f6ca029830f31adbe8"}
+112
View File
@@ -0,0 +1,112 @@
#!/usr/bin/env python3
"""抓 hyCred 签发链: 挂 saveLoginData(落盘) + LoginCred handler(vtable探测)。
用法: 脚本跑起来后, 在手机上 手动退出登录 -> 重新登录 一次。
捕获: 登录态JSON明文(含cred字段) / saveLoginData 入参 / LoginCred handler 触发。
"""
from __future__ import annotations
import json
import subprocess
import time
from pathlib import Path
import frida
RE = Path("/Users/yml/codes/Reverse-Engineering-Agent-Universal-v3.0")
JS = r"""
var base = Process.getModuleByName('libudbauthunify.so').base;
send({type:'armed'});
function hx(p,n){ try{ return Array.from(new Uint8Array(p.readByteArray(n))).map(x=>('0'+x.toString(16)).slice(-2)).join(''); }catch(e){ return 'ERR'; } }
function rdStr(p){ try{
var b0=p.readU8();
if((b0&1)===0){ var l=b0>>1; return {len:l,v:l?hx(p.add(1),Math.min(l,256)):''}; }
var len=parseInt(p.add(8).readU64().toString());
if(len>4096) return {len:len,v:''};
return {len:len,v:hx(p.add(16).readPointer(),len)};
}catch(e){ return {len:-1,v:String(e)}; } }
Java.perform(function(){
var n=0;
function go(){
try{
var seed=Java.use('com.duowan.kiwi.base.login.udb.HuyaLoginProxy');
var F=Java.ClassFactory.get(seed.class.getClassLoader());
var done=false;
['com.huyaudbunify.HuyaAuth','com.hysdkproxy.HuyaAuth','com.huyaudbunify.sdk.HuyaAuth'].forEach(function(cn){
if(done) return;
try{
var C=F.use(cn);
var inst = C.getInstance ? C.getInstance() : null;
var r = inst ? inst.getCred(1199666914671) : C.getCred(1199666914671);
send({type:'java_cred', cls:cn, r:String(r).slice(0,400)});
done=true;
}catch(e2){}
});
if(!done) throw new Error('no HuyaAuth');
}catch(e){ n+=1; if(n%6===0) send({type:'retry',n:n}); setTimeout(go,5000); }
}
setTimeout(go, 15000);
});
Interceptor.attach(base.add(0x265524), {
onEnter: function(a){ this.uid=a[1].toString(); this.out=a[2]; },
onLeave: function(){ send({type:'getcred', uid:this.uid, out:rdStr(this.out)}); }
});
"""
def main():
d = frida.get_device_manager().add_remote_device('127.0.0.1:31877')
pid = d.spawn(['com.duowan.kiwi'])
s = d.attach(pid)
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)
time.sleep(11)
s.create_script((RE / "evidence/scripts/patch_guard_block_termination.js").read_text()).load()
print('armed. >>> 请在手机上退出登录并重新登录 <<<')
sc = s.create_script(JS)
events = []
def on_msg(m, _):
if m.get('type') == 'error':
print('JS ERR:', str(m)[:200]); return
if m.get('type') != 'send':
return
p = m.get('payload') or {}
t = p.get('type')
events.append(p)
if t == 'vt_attached':
print(f"[vt] {p['name']} slot{p['slot']} @+{p['fp']}")
elif t == 'saveLD_str':
print(f"[saveLD_str] str={p['str']['t']}:{p['str']['len']}\n bean={p['bean_head']}\n bt={p['bt']}")
elif t == 'saveLD_bean':
print(f"[saveLD_bean] flag={p['flag']}\n bean={p['bean_head']}\n bt={p['bt']}")
elif t == 'cred_unpack':
print(f"[cred_unpack] in={p['in']['t']}:{p['in']['len']}:{p['in']['v'][:160]} <- {p['ra']}")
elif t == 'bigaes':
print(f"[bigaes] len={p['x2']['len']} head={p['x2']['v'][:120]}")
elif t == 'vtable':
print(f"[VT!] {p['name']}#{p['slot']} a1={p['a1']} bt={p['bt']}")
sc.on('message', on_msg)
sc.load()
deadline = time.time() + 300
while time.time() < deadline:
time.sleep(3)
if any(e.get('type') in ('java_cred','getcred') for e in events):
time.sleep(10)
break
Path('/Users/yml/codes/douyu_login_py/evidence/getcred.json').write_text(json.dumps(events))
from collections import Counter
print('saved:', Counter(e.get('type') for e in events))
if __name__ == '__main__':
for attempt in range(4):
try:
main()
break
except frida.InvalidOperationError as e:
print('detached:', e)
subprocess.run(['adb', 'shell', 'am', 'force-stop', 'com.duowan.kiwi'])
time.sleep(3)