feat: MariBank 风控 bypass、澳洲银行 Hook 与 reverse 逆向工作区
新增 MariBank/SeaBank PH Root 与 SHPSSDK bypass、riskToken 净化及 Up/Suncorp/ubank 消息 Hook;整理 reverse/ 脚本与 Frida 工具链,并补充当日工作说明文档。
This commit is contained in:
182
reverse/frida/trace_maribank_register.js
Normal file
182
reverse/frida/trace_maribank_register.js
Normal file
@@ -0,0 +1,182 @@
|
||||
'use strict';
|
||||
/**
|
||||
* MariBank 注册 trace — attach 模式优先,聚焦 Java 层(OkHttp / Gson / 加密包装)
|
||||
*/
|
||||
const TAG = '[MB-TRACE]';
|
||||
const MAX_STR = 2000;
|
||||
|
||||
function log(msg) {
|
||||
console.log(TAG + ' ' + msg);
|
||||
}
|
||||
|
||||
function shouldLogUrl(url) {
|
||||
if (!url) return false;
|
||||
const u = String(url).toLowerCase();
|
||||
return u.indexOf('register') >= 0 || u.indexOf('dfp') >= 0
|
||||
|| u.indexOf('risk') >= 0 || u.indexOf('uapi') >= 0;
|
||||
}
|
||||
|
||||
function hexPreview(arr, limit) {
|
||||
const n = Math.min(arr.length, limit || 64);
|
||||
let hex = '';
|
||||
for (let i = 0; i < n; i++) {
|
||||
const b = (arr[i] & 0xff).toString(16);
|
||||
hex += (b.length === 1 ? '0' : '') + b;
|
||||
}
|
||||
if (arr.length > n) hex += '...';
|
||||
return hex;
|
||||
}
|
||||
|
||||
function dumpJava(tag, obj) {
|
||||
if (obj === null || obj === undefined) {
|
||||
log(tag + ' = null');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const cls = obj.getClass().getName();
|
||||
if (cls === '[B') {
|
||||
const arr = Java.cast(obj, Java.use('[B'));
|
||||
let text = '';
|
||||
try {
|
||||
text = Java.use('java.lang.String').$new(arr, 'UTF-8').toString();
|
||||
} catch (e) {
|
||||
text = '<bin>';
|
||||
}
|
||||
const show = text.length > MAX_STR ? text.substring(0, MAX_STR) + '...' : text;
|
||||
log(tag + ' byte[' + arr.length + '] hex=' + hexPreview(arr, 48) + ' text=' + show);
|
||||
return;
|
||||
}
|
||||
if (cls === 'java.lang.String') {
|
||||
const s = Java.cast(obj, Java.use('java.lang.String')).toString();
|
||||
const show = s.length > MAX_STR ? s.substring(0, MAX_STR) + '...' : s;
|
||||
log(tag + ' String(' + s.length + ') ' + show);
|
||||
return;
|
||||
}
|
||||
log(tag + ' ' + cls + ' = ' + obj.toString());
|
||||
} catch (e) {
|
||||
log(tag + ' err=' + e);
|
||||
}
|
||||
}
|
||||
|
||||
function hookOkHttp() {
|
||||
const RealCall = Java.use('okhttp3.RealCall');
|
||||
const orig = RealCall.execute;
|
||||
RealCall.execute.implementation = function () {
|
||||
const req = this.request();
|
||||
const url = req.url().toString();
|
||||
const method = req.method();
|
||||
if (shouldLogUrl(url)) {
|
||||
log('HTTP >> ' + method + ' ' + url);
|
||||
try {
|
||||
const body = req.body();
|
||||
if (body) {
|
||||
const Buffer = Java.use('okio.Buffer');
|
||||
const buf = Buffer.$new();
|
||||
body.writeTo(buf);
|
||||
const bytes = buf.readByteArray();
|
||||
if (bytes) dumpJava(' reqBody', Java.array('byte', bytes));
|
||||
}
|
||||
} catch (e) {
|
||||
log(' reqBody err: ' + e);
|
||||
}
|
||||
}
|
||||
const resp = orig.call(this);
|
||||
if (shouldLogUrl(url)) {
|
||||
try {
|
||||
const peek = resp.peekBody(Java.use('java.lang.Long').parseLong('1048576'));
|
||||
const s = peek.string();
|
||||
const show = s.length > MAX_STR ? s.substring(0, MAX_STR) + '...' : s;
|
||||
log('HTTP << ' + resp.code() + ' ' + show);
|
||||
} catch (e) {
|
||||
log('HTTP resp err: ' + e);
|
||||
}
|
||||
}
|
||||
return resp;
|
||||
};
|
||||
log('hooked RealCall.execute');
|
||||
}
|
||||
|
||||
function hookGson() {
|
||||
const Gson = Java.use('com.google.gson.Gson');
|
||||
Gson.toJson.overload('java.lang.Object').implementation = function (obj) {
|
||||
const ret = this.toJson(obj);
|
||||
if (ret) {
|
||||
const low = ret.toLowerCase();
|
||||
if (low.indexOf('mobile') >= 0 || low.indexOf('phone') >= 0
|
||||
|| low.indexOf('risktoken') >= 0 || low.indexOf('register') >= 0
|
||||
|| low.indexOf('4067') >= 0) {
|
||||
const show = ret.length > MAX_STR ? ret.substring(0, MAX_STR) + '...' : ret;
|
||||
log('Gson.toJson ' + show);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
log('hooked Gson.toJson');
|
||||
}
|
||||
|
||||
function hookRisk() {
|
||||
const vv = Java.use('com.shopee.shpssdkbank.uwuvuvvww.vvuuuuvvv');
|
||||
vv.wwvuwuwvu.overload('android.content.Context').implementation = function (ctx) {
|
||||
const ret = this.wwvuwuwvu(ctx);
|
||||
dumpJava('riskToken', ret);
|
||||
return ret;
|
||||
};
|
||||
log('hooked vvuuuuvvv.wwvuwuwvu');
|
||||
}
|
||||
|
||||
function hookEncryptWrapper() {
|
||||
const D = Java.use('com.shopee.bke.lib.jni.utils.d');
|
||||
const methods = D.class.getDeclaredMethods();
|
||||
for (let i = 0; i < methods.length; i++) {
|
||||
const m = methods[i];
|
||||
const name = m.getName();
|
||||
if (m.getModifiers() & 0x0100) continue;
|
||||
try {
|
||||
D[name].overloads.forEach(function (ovl) {
|
||||
ovl.implementation = function () {
|
||||
const args = [].slice.call(arguments);
|
||||
log('>> EncryptWrapper.' + name);
|
||||
args.forEach(function (a, idx) { dumpJava(' in' + idx, a); });
|
||||
const ret = ovl.apply(this, args);
|
||||
if (ret && ret.getClass) {
|
||||
const cn = ret.getClass().getName();
|
||||
if (cn === '[Ljava.lang.String;') {
|
||||
const arr = Java.cast(ret, Java.use('[Ljava.lang.String;'));
|
||||
for (let j = 0; j < arr.length; j++) dumpJava(' out' + j, arr[j]);
|
||||
} else {
|
||||
dumpJava(' ret', ret);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
});
|
||||
} catch (e) {}
|
||||
}
|
||||
log('hooked NativeEncryptUtilsWrapper (utils.d)');
|
||||
}
|
||||
|
||||
function installAll() {
|
||||
Java.perform(function () {
|
||||
log('Java.perform OK pid=' + Process.id);
|
||||
try { hookOkHttp(); } catch (e) { log('okhttp fail: ' + e); }
|
||||
try { hookGson(); } catch (e) { log('gson fail: ' + e); }
|
||||
try { hookRisk(); } catch (e) { log('risk fail: ' + e); }
|
||||
try { hookEncryptWrapper(); } catch (e) { log('encrypt fail: ' + e); }
|
||||
log('READY — 请在 App 输入号码点 Next');
|
||||
});
|
||||
}
|
||||
|
||||
function waitForJava(n) {
|
||||
n = n || 0;
|
||||
if (typeof Java === 'undefined' || !Java.available) {
|
||||
if (n % 5 === 0) log('waiting Java.available attempt=' + n);
|
||||
setTimeout(function () { waitForJava(n + 1); }, 500);
|
||||
return;
|
||||
}
|
||||
installAll();
|
||||
}
|
||||
|
||||
setImmediate(function () {
|
||||
log('script loaded pid=' + Process.id);
|
||||
waitForJava(0);
|
||||
});
|
||||
Reference in New Issue
Block a user