feat(dfp): 🔑 RC4 key=APK内嵌appkey常量(datadiv@3912240), 全流程零设备依赖闭环 (R38-R39)
This commit is contained in:
+5
-2
@@ -8,8 +8,11 @@
|
||||
不是魔数! 密钥同则 magic 同)
|
||||
-> 尾部 10B 为 gzip 流之后的附加段 (decompressobj unused_data)
|
||||
|
||||
密钥 = 32 字符 hex ASCII 串 (如 865a4924a40897ac1fcfe6b4c2abc798), 每注册轮换.
|
||||
捕获点: libhydeviceid.so!0x60e6c onEnter x1 = 密钥串 (tools/frida/hook_hy.js).
|
||||
密钥 = 32 字符 hex ASCII 串 = **APK 内嵌静态常量** (非随机、非设备派生!):
|
||||
libhydeviceid.so .data (datadiv 加密) 字符串表 @offset 3912240, 紧邻 "dfpReport"/"appid"/"terminal":
|
||||
[3912240] "865a4924a40897ac1fcfe6b4c2abc798" ← turing appkey/通道密钥 (R39 实锤)
|
||||
同族兄弟: k1=...cbb0e3 (BusinessCfg+0x10), channelKey=...cbb045 (resinfo 服务端下发)
|
||||
新版本 APK 离线重提取: unidbg hydev harness 跑 datadiv 解密, 或 0x60e6c x1 一次抓取.
|
||||
XXTEA/静态密钥 f15e... 与 dfpReport 无关 (那是 hdid 子系统) — 45 函数零调用之谜即此.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
// R38: 追踪 RC4 key (32hex) 的诞生点 — Java MessageDigest + udb md5 + 0x60e6c 反查副本
|
||||
'use strict';
|
||||
function emit(o){ try{ send(o); }catch(e){} }
|
||||
function hexb(p,n){ try{ return Array.from(new Uint8Array(p.readByteArray(n))).map(b=>('0'+b.toString(16)).slice(-2)).join(''); }catch(e){ return ''; } }
|
||||
var nEvents = 0;
|
||||
|
||||
// ---- 1) Java MessageDigest 全量 (md5/sha1) ----
|
||||
setImmediate(function(){
|
||||
Java.perform(function(){
|
||||
try {
|
||||
var MD = Java.use('java.security.MessageDigest');
|
||||
MD.digest.overload().implementation = function(){
|
||||
var algo = this.getAlgorithm();
|
||||
var out = this.digest();
|
||||
try {
|
||||
var hex = Array.prototype.map.call(out, function(b){ return ('0'+(b&0xff).toString(16)).slice(-2); }).join('');
|
||||
nEvents++;
|
||||
emit({event:'java-digest', algo: algo, out: hex});
|
||||
} catch(e){}
|
||||
return out;
|
||||
};
|
||||
MD.digest.overload('[B').implementation = function(inp){
|
||||
var algo = this.getAlgorithm();
|
||||
var out = this.digest(inp);
|
||||
try {
|
||||
var hex = Array.prototype.map.call(out, function(b){ return ('0'+(b&0xff).toString(16)).slice(-2); }).join('');
|
||||
var inHex = Array.prototype.map.call(inp, function(b){ return ('0'+(b&0xff).toString(16)).slice(-2); }).join('');
|
||||
nEvents++;
|
||||
emit({event:'java-digest', algo: algo, out: hex, in_hex: inHex.substring(0,2048)});
|
||||
} catch(e){}
|
||||
return out;
|
||||
};
|
||||
emit({event:'java-md5-hooked'});
|
||||
} catch(e){ emit({event:'java-e', e:String(e).substring(0,150)}); }
|
||||
});
|
||||
});
|
||||
|
||||
// ---- 2) udbauthunify md5 (0x32e71c) 原始参数 ----
|
||||
function armUdb(){
|
||||
var u = Process.findModuleByName('libudbauthunify.so');
|
||||
if (!u) return false;
|
||||
try {
|
||||
Interceptor.attach(u.base.add(0x32e71c), {
|
||||
onEnter(args){
|
||||
this.a = [];
|
||||
for (var i=0;i<4;i++) this.a.push({x:String(args[i]), h:hexb(args[i],96)});
|
||||
this.lr = this.returnAddress;
|
||||
},
|
||||
onLeave(){
|
||||
try {
|
||||
var outs = [];
|
||||
for (var i=0;i<2;i++) outs.push(hexb(this.a[i].x ? ptr(this.a[i].x) : ptr(0), 96));
|
||||
nEvents++;
|
||||
emit({event:'udb-md5', args:this.a, out_re:outs, lr: String(this.lr)});
|
||||
} catch(e){}
|
||||
}
|
||||
});
|
||||
emit({event:'udb-armed'});
|
||||
return true;
|
||||
} catch(e){ return false; }
|
||||
}
|
||||
|
||||
// ---- 3) 0x60e6c 到位点 + 全内存反查 key 副本 ----
|
||||
function armHy(){
|
||||
var h = Process.findModuleByName('libhydeviceid.so');
|
||||
if (!h) return false;
|
||||
try {
|
||||
Interceptor.attach(h.base.add(0x60e6c), {
|
||||
onEnter(args){
|
||||
try {
|
||||
var s = '';
|
||||
try { s = args[1].readCString(64); } catch(e){}
|
||||
nEvents++;
|
||||
emit({event:'key-site', x1:String(args[1]), key:s});
|
||||
if (s && s.length === 32) {
|
||||
setTimeout(function(){
|
||||
var pat = '';
|
||||
for (var i=0;i<16;i++) pat += s.substr(i,2).split('').join('')+' ' ;
|
||||
pat = s.substring(0,16).split('').map(function(c){ return ('0'+c.charCodeAt(0).toString(16)).slice(-2); }).join(' ');
|
||||
var n=0;
|
||||
for (var r of Process.enumerateRanges('rw-')) {
|
||||
if (r.size > 96*1024*1024) continue;
|
||||
var ms=[];
|
||||
try { ms = Memory.scanSync(r.base, r.size, pat); } catch(e){ continue; }
|
||||
for (var m of ms){
|
||||
if (n>=10) break;
|
||||
n++;
|
||||
emit({event:'key-copy', addr:String(m.address), src: r.file? r.file.path : String(r.base), around: hexb(m.address.sub(160), 352)});
|
||||
}
|
||||
if (n>=10) break;
|
||||
}
|
||||
emit({event:'key-copies-done', n:n});
|
||||
}, 50);
|
||||
}
|
||||
} catch(e){ emit({event:'key-e', e:String(e).substring(0,150)}); }
|
||||
}
|
||||
});
|
||||
// 4) JNI 边界 0x20e924 参数
|
||||
Interceptor.attach(h.base.add(0x20e924), {
|
||||
onEnter(args){
|
||||
if (nEvents > 3000) return;
|
||||
var rows=[];
|
||||
for (var i=0;i<3;i++) rows.push({x:String(args[i]), h:hexb(args[i],48)});
|
||||
nEvents++;
|
||||
emit({event:'jni-boundary', args:rows});
|
||||
}
|
||||
});
|
||||
emit({event:'hy-armed'});
|
||||
return true;
|
||||
} catch(e){ emit({event:'hy-e', e:String(e).substring(0,150)}); return false; }
|
||||
}
|
||||
|
||||
var udb=false, hy=false;
|
||||
var poll = setInterval(function(){
|
||||
if (!udb) udb = armUdb();
|
||||
if (!hy) hy = armHy();
|
||||
if (udb && hy) clearInterval(poll);
|
||||
}, 200);
|
||||
|
||||
// ---- 5) SSL_write 同轮密文 ----
|
||||
var done = false;
|
||||
for (var mod of Process.enumerateModules()){
|
||||
var addr = null;
|
||||
try { addr = mod.getExportByName('SSL_write'); } catch(e){}
|
||||
if (!addr) continue;
|
||||
Interceptor.attach(addr, {
|
||||
onEnter(args){
|
||||
if (done) return;
|
||||
try {
|
||||
var num = args[2].toInt32();
|
||||
if (num < 60 || num > 60000) return;
|
||||
var u = new Uint8Array(args[1].readByteArray(num));
|
||||
var s = '';
|
||||
for (var i=0;i<u.length;i++) s += (u[i]>=32 && u[i]<127) ? String.fromCharCode(u[i]) : '.';
|
||||
if (s.indexOf('dfpReport') < 0) return;
|
||||
done = true;
|
||||
var hex = Array.prototype.map.call(u, function(x){return ('0'+x.toString(16)).slice(-2)}).join('');
|
||||
emit({event:'post', num:num, hex:hex});
|
||||
} catch(e){}
|
||||
}
|
||||
});
|
||||
}
|
||||
emit({event:'script-loaded'});
|
||||
@@ -0,0 +1,137 @@
|
||||
// R38b: RC4 key 诞生点终极追踪 — MD5 transform 消息积累 + 到位点反查 + Java digest 输入
|
||||
'use strict';
|
||||
function emit(o){ try{ send(o); }catch(e){} }
|
||||
function hexb(p,n){ try{ return Array.from(new Uint8Array(p.readByteArray(n))).map(b=>('0'+b.toString(16)).slice(-2)).join(''); }catch(e){ return ''; } }
|
||||
var nEvents = 0;
|
||||
var CAP = 2500;
|
||||
|
||||
// ---- 1) MD5 transform 消息积累 (libhydeviceid!0xc37c0, ror#7 核心) ----
|
||||
var md5msgs = {}; // state -> [blockHex,...]
|
||||
var md5order = [];
|
||||
var md5calls = 0;
|
||||
|
||||
function armHy(){
|
||||
var h = Process.findModuleByName('libhydeviceid.so');
|
||||
if (!h) return false;
|
||||
try {
|
||||
Interceptor.attach(h.base.add(0xc37c0), {
|
||||
onEnter(args){
|
||||
if (md5calls > 1200) return;
|
||||
md5calls++;
|
||||
var st = args[0].toString();
|
||||
var blk = hexb(args[1], 64);
|
||||
if (!md5msgs[st]) { md5msgs[st] = []; md5order.push(st); if (md5order.length>60) {} }
|
||||
md5msgs[st].push(blk);
|
||||
}
|
||||
});
|
||||
// ---- 2) 0x60e6c 到位点 ----
|
||||
Interceptor.attach(h.base.add(0x60e6c), {
|
||||
onEnter(args){
|
||||
try {
|
||||
var s = '';
|
||||
try { s = args[1].readCString(64); } catch(e){}
|
||||
if (s.length !== 32) return;
|
||||
nEvents++;
|
||||
emit({event:'key-site', key:s, md5calls: md5calls, nstates: md5order.length});
|
||||
// 倒出全部 MD5 消息 (每 state 拼接 blocks, 截 512B)
|
||||
var dumped = 0;
|
||||
for (var st of md5order){
|
||||
if (dumped >= 40) break;
|
||||
var full = md5msgs[st].join('');
|
||||
nEvents++;
|
||||
emit({event:'md5-msg', state: st, nblk: md5msgs[st].length, hex: full.substring(0, 1024)});
|
||||
dumped++;
|
||||
}
|
||||
// 内存反查 key 副本
|
||||
setTimeout(function(){
|
||||
var pat = s.substring(0,16).split('').map(function(c){ return ('0'+c.charCodeAt(0).toString(16)).slice(-2); }).join(' ');
|
||||
var n=0;
|
||||
for (var r of Process.enumerateRanges('rw-')){
|
||||
if (r.size > 96*1024*1024) continue;
|
||||
var ms=[];
|
||||
try { ms = Memory.scanSync(r.base, r.size, pat); } catch(e){ continue; }
|
||||
for (var m of ms){
|
||||
if (n>=10) break;
|
||||
n++; nEvents++;
|
||||
emit({event:'key-copy', addr:String(m.address), src: r.file? r.file.path : String(r.base), around: hexb(m.address.sub(192), 448)});
|
||||
}
|
||||
if (n>=10) break;
|
||||
}
|
||||
emit({event:'key-copies-done', n:n});
|
||||
}, 30);
|
||||
} catch(e){ emit({event:'key-e', e:String(e).substring(0,150)}); }
|
||||
}
|
||||
});
|
||||
emit({event:'hy-armed'});
|
||||
return true;
|
||||
} catch(e){ return false; }
|
||||
}
|
||||
|
||||
// ---- 3) Java MessageDigest: update 输入积累 ----
|
||||
setImmediate(function(){
|
||||
Java.perform(function(){
|
||||
try {
|
||||
var MD = Java.use('java.security.MessageDigest');
|
||||
var pend = {}; // hashcode -> [hexchunks]
|
||||
MD.update.overload('[B').implementation = function(b){
|
||||
try {
|
||||
var k = this.hashCode();
|
||||
if (!pend[k]) pend[k]=[];
|
||||
if (pend[k].length < 8) {
|
||||
pend[k].push(Array.prototype.map.call(b, function(x){return ('0'+(x&0xff).toString(16)).slice(-2);}).join('').substring(0,2048));
|
||||
}
|
||||
} catch(e){}
|
||||
return this.update(b);
|
||||
};
|
||||
MD.digest.overload().implementation = function(){
|
||||
var algo = this.getAlgorithm();
|
||||
var out = this.digest();
|
||||
try {
|
||||
var k = this.hashCode();
|
||||
var hex = Array.prototype.map.call(out, function(b){ return ('0'+(b&0xff).toString(16)).slice(-2); }).join('');
|
||||
if (nEvents < CAP) { nEvents++; emit({event:'java-digest', algo:algo, out:hex, in_parts:(pend[k]||[]).join('')}); }
|
||||
delete pend[k];
|
||||
} catch(e){}
|
||||
return out;
|
||||
};
|
||||
MD.digest.overload('[B').implementation = function(b){
|
||||
var algo = this.getAlgorithm();
|
||||
var out = this.digest(b);
|
||||
try {
|
||||
var hex = Array.prototype.map.call(out, function(b2){ return ('0'+(b2&0xff).toString(16)).slice(-2); }).join('');
|
||||
var inHex = Array.prototype.map.call(b, function(x){return ('0'+(x&0xff).toString(16)).slice(-2);}).join('');
|
||||
if (nEvents < CAP) { nEvents++; emit({event:'java-digest', algo:algo, out:hex, in_parts:inHex.substring(0,4096)}); }
|
||||
} catch(e){}
|
||||
return out;
|
||||
};
|
||||
emit({event:'java-md5-hooked'});
|
||||
} catch(e){ emit({event:'java-e', e:String(e).substring(0,150)}); }
|
||||
});
|
||||
});
|
||||
|
||||
// ---- 4) SSL_write 同轮标记 ----
|
||||
var done = false;
|
||||
for (var mod of Process.enumerateModules()){
|
||||
var addr = null;
|
||||
try { addr = mod.getExportByName('SSL_write'); } catch(e){}
|
||||
if (!addr) continue;
|
||||
Interceptor.attach(addr, {
|
||||
onEnter(args){
|
||||
if (done) return;
|
||||
try {
|
||||
var num = args[2].toInt32();
|
||||
if (num < 60 || num > 60000) return;
|
||||
var u = new Uint8Array(args[1].readByteArray(num));
|
||||
var s = '';
|
||||
for (var i=0;i<u.length;i++) s += (u[i]>=32 && u[i]<127) ? String.fromCharCode(u[i]) : '.';
|
||||
if (s.indexOf('dfpReport') < 0) return;
|
||||
done = true;
|
||||
nEvents++;
|
||||
emit({event:'post', num:num});
|
||||
} catch(e){}
|
||||
}
|
||||
});
|
||||
}
|
||||
var armed=false;
|
||||
var poll = setInterval(function(){ if (armHy()){ armed=true; clearInterval(poll);} }, 200);
|
||||
emit({event:'script-loaded'});
|
||||
@@ -0,0 +1,82 @@
|
||||
// R39: 登录时 udbauthunify md5 正确捕获 — sret 约定: x0=out槽, x1=in
|
||||
'use strict';
|
||||
function emit(o){ try{ send(o); }catch(e){} }
|
||||
function hexb(p,n){ try{ return Array.from(new Uint8Array(p.readByteArray(n))).map(b=>('0'+b.toString(16)).slice(-2)).join(''); }catch(e){ return ''; } }
|
||||
function rdStr(p){
|
||||
// libc++ std::string: b0&1==0 -> SSO (len=b0>>1, data=+1); else heap (len@+8, data@*+16)
|
||||
try {
|
||||
var b0 = p.readU8();
|
||||
if ((b0 & 1) === 0){
|
||||
var l = b0 >> 1;
|
||||
if (l > 22) return {t:'susp', len:l, v: hexb(p.add(1), 48)};
|
||||
return {t:'s', len:l, v: p.add(1).readUtf8String(l)};
|
||||
}
|
||||
var hl = p.add(8).readU64().toNumber();
|
||||
if (hl > 8192) return {t:'err', v:'too long '+hl};
|
||||
return {t:'b64h', len:hl, v: hexb(p.add(16).readPointer(), Math.min(hl, 512))};
|
||||
} catch(e){ return {t:'err', v:String(e)}; }
|
||||
}
|
||||
var n = 0;
|
||||
function armUdb(){
|
||||
var u = Process.findModuleByName('libudbauthunify.so');
|
||||
if (!u) return false;
|
||||
try {
|
||||
Interceptor.attach(u.base.add(0x32e71c), {
|
||||
onEnter(args){
|
||||
this.outp = args[0];
|
||||
this.in1 = rdStr(args[1]);
|
||||
this.in2 = rdStr(args[2]);
|
||||
this.raw = [hexb(args[1], 64), hexb(args[2], 64)];
|
||||
this.lr = String(this.returnAddress);
|
||||
},
|
||||
onLeave(){
|
||||
if (n > 300) return;
|
||||
n++;
|
||||
emit({event:'udb-md5', in1:this.in1, in2:this.in2, raw:this.raw,
|
||||
out: rdStr(this.outp), lr:this.lr});
|
||||
}
|
||||
});
|
||||
emit({event:'udb-armed'});
|
||||
return true;
|
||||
} catch(e){ emit({event:'udb-e', e:String(e).substring(0,150)}); return false; }
|
||||
}
|
||||
var armed = false;
|
||||
var poll = setInterval(function(){ if (armUdb()){ armed=true; clearInterval(poll); } }, 200);
|
||||
// Java digest 带输入 (登录 Java 侧可能也算)
|
||||
setImmediate(function(){
|
||||
Java.perform(function(){
|
||||
try {
|
||||
var MD = Java.use('java.security.MessageDigest');
|
||||
var pend = {};
|
||||
MD.update.overload('[B').implementation = function(b){
|
||||
try {
|
||||
var k=this.hashCode();
|
||||
if(!pend[k]) pend[k]=[];
|
||||
if (pend[k].length<8) pend[k].push(Array.prototype.map.call(b,function(x){return ('0'+(x&0xff).toString(16)).slice(-2);}).join('').substring(0,2048));
|
||||
} catch(e){}
|
||||
return this.update(b);
|
||||
};
|
||||
MD.digest.overload().implementation = function(){
|
||||
var out=this.digest();
|
||||
try {
|
||||
var k=this.hashCode();
|
||||
var oh=Array.prototype.map.call(out,function(b){return ('0'+(b&0xff).toString(16)).slice(-2);}).join('');
|
||||
emit({event:'java-digest', algo:this.getAlgorithm(), out:oh, in_parts:(pend[k]||[]).join('')});
|
||||
delete pend[k];
|
||||
} catch(e){}
|
||||
return out;
|
||||
};
|
||||
MD.digest.overload('[B').implementation = function(b){
|
||||
var out=this.digest(b);
|
||||
try {
|
||||
var oh=Array.prototype.map.call(out,function(b2){return ('0'+(b2&0xff).toString(16)).slice(-2);}).join('');
|
||||
var ih=Array.prototype.map.call(b,function(x){return ('0'+(x&0xff).toString(16)).slice(-2);}).join('');
|
||||
emit({event:'java-digest', algo:this.getAlgorithm(), out:oh, in_parts:ih.substring(0,4096)});
|
||||
} catch(e){}
|
||||
return out;
|
||||
};
|
||||
emit({event:'java-md5-hooked'});
|
||||
} catch(e){}
|
||||
});
|
||||
});
|
||||
emit({event:'script-loaded'});
|
||||
Reference in New Issue
Block a user