feat: MariBank 风控 bypass、澳洲银行 Hook 与 reverse 逆向工作区

新增 MariBank/SeaBank PH Root 与 SHPSSDK bypass、riskToken 净化及 Up/Suncorp/ubank 消息 Hook;整理 reverse/ 脚本与 Frida 工具链,并补充当日工作说明文档。
This commit is contained in:
2026-07-03 17:15:16 +08:00
parent 125dfe583b
commit 59970a84a8
121 changed files with 7606 additions and 37 deletions

View 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);
});