为什么要监控 WebView
混合开发 App 的核心逻辑经常不在 Java 层而在 H5 里:登录态的传递、支付回调、加密参数的生成,都通过 WebView 的 JSBridge 在 native 和 H5 之间穿梭。只 hook Java 层会漏掉一半的信息流。监控 WebView 要抓三个点:loadUrl(加载了什么页面)、JSBridge(双向通信内容)、evaluateJavascript(执行了什么 JS)。
监控 loadUrl 与页面加载
Java.perform(function() {
var WebView = Java.use('android.webkit.WebView');
WebView.loadUrl.overload('java.lang.String').implementation = function(url) {
console.log('[loadUrl] ' + url);
// javascript: 伪协议的调用也会走这里,JS 注入一目了然
this.loadUrl(url);
};
WebView.evaluateJavascript.implementation = function(script, cb) {
console.log('[evalJS] ' + script.substring(0, 500));
this.evaluateJavascript(script, cb);
};
// postUrl 带 body,别漏
WebView.postUrl.implementation = function(url, data) {
console.log('[postUrl] ' + url + ' data=' + Java.use('java.lang.String').$new(data));
this.postUrl(url, data);
};
});监控 JSBridge:双向都要抓
JSBridge 的本质是 @JavascriptInterface 注解暴露的 Java 对象。监控分两步:
第一步:找出 bridge 对象名。
var WebView = Java.use('android.webkit.WebView');
WebView.addJavascriptInterface.implementation = function(obj, name) {
console.log('[addJSInterface] name=' + name + ' class=' + obj.getClass().getName());
this.addJavascriptInterface(obj, name);
};跑一次 App 就知道 H5 里 window.xxx 对应哪个 Java 类。
第二步:hook bridge 类的所有方法。
function hookBridge(className) {
var cls = Java.use(className);
cls.class.getDeclaredMethods().forEach(function(m) {
var mName = m.getName();
cls[mName].overloads.forEach(function(overload) {
overload.implementation = function() {
var args = Array.from(arguments).map(String).join(', ');
console.log('[JSBridge] ' + className + '.' + mName + '(' + args.substring(0, 300) + ')');
var ret = this[mName].apply(this, arguments);
if (ret) console.log('[JSBridge ret] ' + String(ret).substring(0, 300));
return ret;
};
});
});
}反向监控:H5 回调 native 的 hidden 通道
很多 App 的 JSBridge 是"伪协议 + shouldOverrideUrlLoading"实现的(H5 跳转 jsbridge://method?params),这种不走 addJavascriptInterface,要 hook WebViewClient:
var WebViewClient = Java.use('android.webkit.WebViewClient');
WebViewClient.shouldOverrideUrlLoading.overload('android.webkit.WebView', 'java.lang.String').implementation = function(view, url) {
if (url.indexOf('jsbridge://') === 0 || url.indexOf('js://') === 0) {
console.log('[Bridge-URL] ' + decodeURIComponent(url));
}
return this.shouldOverrideUrlLoading(view, url);
};精髓:四个实战要点
- 多 WebView 实例。App 里可能有多个 WebView(主页面、广告、支付各一个),hook 是类级的所以全覆盖,但日志里要带上
this.hashCode()区分实例,否则分不清哪条日志是哪个页面的。 - X5/UC 内核的类名不同。腾讯 X5 内核是
com.tencent.smtt.sdk.WebView,UC 是com.uc.webview.export.WebView,方法名类似但包名不同。逆向前先确认 App 用的哪个内核(jadx 搜 import)。 - 加密参数常在 Bridge 里生成。很多 App 的 H5 签名是 H5 调 native bridge 算的——监控 bridge 方法的输入输出,签名算法的入参出参直接到手,比逆 SO 快得多。
- evaluateJavascript 是回调注入点。想主动调 H5 的 JS 函数(比如让 H5 的签名函数给你算签名),用
evaluateJavascript注入调用代码,配合 handler 拿返回值——这是"借鸡生蛋"式签名服务的实现基础。
总结
- WebView 监控三件套:loadUrl、addJavascriptInterface、evaluateJavascript
- 伪协议型 Bridge 要 hook shouldOverrideUrlLoading
- X5/UC 内核实类名不同,先确认内核再写 hook
- Bridge 方法是签名算法的富矿,优先审查
交流微信:run1255