#!/usr/bin/env python3 """k1 账号绑定判定: 对多个不同 uid 调 getQUrlData, 看 xxtea key 是否变化。 若 k1(=this+0x10, MD5输入的一半)随 uid 变 -> 账号绑定, 纯协议死路; 若 k1 不变 -> 设备级常量, 任意账号可本地复算 nonce, 纯协议成立! 同时验证 serviceTime/nonce_next 的生成与 uid 无关。 """ 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") UIDS = [1199666914671, 1199666911746] # 可信账号 + 另一账号(新账号uid可能不存在, 但getQUrlData只看参数) def build_js(uids): arr = ",".join(str(u) for u in uids) return r""" 'use strict'; Process.setExceptionHandler(function(d){ send({type:'segv', info:{type:d.type, addr:String(d.address)}}); return true; }); var base = Process.getModuleByName('libudbauthunify.so').base; send({type:'armed', base:String(base)}); function rdStr(p){ try{ var b0=p.readU8(); if((b0&1)===0){ var l=b0>>1; if(l>8192) return {t:'s?',len:l,v:''}; return {t:'s',len:l,v:l?Array.from(new Uint8Array(p.add(1).readByteArray(l))).map(x=>('0'+x.toString(16)).slice(-2)).join(''):''}; } var len=parseInt(p.add(8).readU64().toString()); if(len>65536) return {t:'l?',len:len,v:''}; var dp=p.add(16).readPointer(); return {t:'l',len:len,v:Array.from(new Uint8Array(dp.readByteArray(len))).map(x=>('0'+x.toString(16)).slice(-2)).join('')}; }catch(e){ return {t:'err',len:-1,v:String(e)}; } } function ascii(h){ if(!h) return ''; var s=''; for(var i=0;i=32&&c<127)?String.fromCharCode(c):'.'; } return s; } // gen_biz_token(struct, uid, k1, k2, out) try { Interceptor.attach(base.add(0x3307e4), { onEnter: function(a){ send({type:'gbt_in', struct:hx_s(a[0],0x60), uid:rdStr(a[1]), k1:rdStr(a[2]), k2:rdStr(a[3])}); } }); } catch(e){ send({type:'hookerr',where:'gen_biz_token',msg:''+e}); } // xxtea try { Interceptor.attach(base.add(0x32e83c), { onEnter: function(a){ this.out=a[0]; send({type:'xxtea_in', data:rdStr(a[1]), key:rdStr(a[2]), key_ascii:ascii(rdStr(a[2]).v)}); }, onLeave: function(){ var o=rdStr(this.out); send({type:'xxtea_out', out:o}); } }); } catch(e){ send({type:'hookerr',where:'xxtea',msg:''+e}); } try { Interceptor.attach(base.add(0x32ff10), { onEnter: function(a){ this.m=a[0]; }, onLeave: function(r){ send({type:'nonce_next', m:'0x'+this.m.toString(16), ret:'0x'+r.toString(16)}); } }); } catch(e){} function hx_s(p,n){ try{ return Array.from(new Uint8Array(p.readByteArray(n))).map(x=>('0'+x.toString(16)).slice(-2)).join(''); }catch(e){ return 'ERR'; } } // 依次触发多个 uid Java.perform(function(){ var uids = __UIDS__; 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 inst=F.use('com.hysdkproxy.LoginProxy').getInstance(); for (var i=0;i