Android WebView 动态插桩与自动化测试实战:从抓包到 adb 坐标绘制
原创声明本文系个人学习笔记记录对某教育类 App WebView 通信机制的逆向分析过程。所有代码仅供技术研究请在合法授权环境下使用。作者YANG | 时间2026.05 | 设备Pixel 5 (Android 13) Frida 16.2.1一、前言为什么研究这个最近在研究一个教育类 App 的测试项目发现它的核心交互居然全走 WebView而且题目数据是通过 loadUrl(javascript:...) 注入的。更离谱的是这个 javascript: 参数里塞的是双层 Base64不抓包根本看不到明文。为了搞清楚它的通信结构我搭了一套 Frida 的环境顺手记录一下踩坑过程。全程Frida 运行时插桩——不抓包、不反编译直接在内存里 Hook 关键类让代码自己暴露数据结构。如果你也在做 WebView 相关的动态分析或者想学习怎么通过 Frida 定位网络层的加密逻辑这篇应该能帮你省点时间。二、环境搭建版本对齐是第一步2.1 设备与工具链血的教训我第一次用的是 frida-server 15.2.2PC 端是 16.2.1结果frida -U -f直接报unable to communicate with remote frida-server查了半天才发现是版本不对。后来重新推了 16.2.1 才解决。curl -LO https://github.com/frida/frida/releases/download/16.2.1/frida-server-16.2.1-android-arm64.xz # 解压后 adb push frida-server-16.2.1-android-arm64 /data/local/tmp/frida-server adb shell chmod 755 /data/local/tmp/frida-server # 后台启动手机 root shell 里执行 /data/local/tmp/frida-server # 验证版本 /data/local/tmp/frida-server --version # 16.2.1三、Hook WebView从内存里提取题目明文3.1 定位 Hook 点// hook_webview.js — 核心逻辑 Java.perform(function() { var WebView Java.use(android.webkit.WebView); WebView.loadUrl.overload(java.lang.String).implementation function(url) { if (url url.indexOf(javascript:) ! -1) { // 提取 javascript: 参数里的 Base64 串 var js url.substring(11); var qStart js.indexOf(); var qEnd js.lastIndexOf(); if (qStart ! -1 qEnd - qStart 100) { var b64 js.substring(qStart 1, qEnd); var examData tryDecode(b64); // 双层 Base64 解密 if (examData examData.examVO) { console.log([] 抓到题型: examData.examVO.pointName); // 打印题目... } } } return this.loadUrl(url); }; });3.2 双层 Base64 解密Hook 里直接写解密逻辑不需要外部工具// pk_capture_raw.js Java.perform(function() { console.log([*] 抓包开始...); var WebView Java.use(android.webkit.WebView); WebView.loadUrl.overload(java.lang.String).implementation function(url) { // 看到 javascript: 就打印看看里面塞了啥 if (url url.indexOf(javascript:) ! -1) { // 先打印前200字符太长了刷屏 // console.log(\n[] 抓到 javascript: url.substring(0, 200)); console.log(\n[] 抓到 javascript: url); } return this.loadUrl(url); }; });3.3 运行效果frida -U -f com.fenbi.android.leo -l pk_capture_raw.js# Frida 控制台输入 %resume 恢复主线程进入 App 的口算 PK 房间Frida 终端直接打印(片段)[] 抓到 javascript: javascript:(window.requestConfig_1779082714161_48 window.requestConfig_1779082714161_48(W251bGwseyJkaWQiOiJEVXZya0xHbFRnYzZlSEFlVGtaN1l2bjBBLXRaS1Y1ZHlCZzciLCJzZXNzaW9uSWQiOiJlMzRmMmQzZS1mZDBiLTQxZTAtYTFjNS1hYzYxZmViMDNlODIiLCJ1c2VyQWdlbnQiOiJMZW8vMy4xMzMuMSAoQW5kcm9pZEFPU1Agb24gcmVkZmluOyBBbmRyb2lkIDEzOyBTY2FsZS8yLjc1KSIsIndyYXBwZWRVcmwiOiIvbGVvLXN0YXIvYW5kcm9pZC9leGVyY2lzZS9yYW5rL3BrL3JhdGU/eXRrVXNlcklkXHUwMDNkMFx1MDAyNnJhbmtJZFx1MDAzZDBcdTAwMjZfcHJvZHVjdElkXHUwMDNkNjExXHUwMDI2cGxhdGZvcm1cdTAwM2RhbmRyb2lkMzNcdTAwMjZ2ZXJzaW9uXHUwMDNkMy4xMzMuMVx1MDAyNnZlbmRvclx1MDAzZGZlbmJpXHUwMDI2YXZcdTAwM2Q1XHUwMDI2c2lnblx1MDAzZGUwMGE5OWYwMjRjN2Y2MGZjOGQ2YTczMWY5NGZjNzgwXHUwMDI2ZGV2aWNlQ2F0ZWdvcnlcdTAwM2RwaG9uZVx1MDAyNndlYnZpZXdWZXJzaW9uXHUwMDNkMTAxXHUwMDI2d2hSYXRpb1x1MDAzZDIuMTcifV0))[] 抓到 javascript: javascript:(window.requestConfig_1779082714157_42 window.requestConfig_1779082714157_42(W251bGwseyJkaWQiOiJEVXZya0xHbFRnYzZlSEFlVGtaN1l2bjBBLXRaS1Y1ZHlCZzciLCJzZXNzaW9uSWQiOiJlMzRmMmQzZS1mZDBiLTQxZTAtYTFjNS1hYzYxZmViMDNlODIiLCJ1c2VyQWdlbnQiOiJMZW8vMy4xMzMuMSAoQW5kcm9pZEFPU1Agb24gcmVkZmluOyBBbmRyb2lkIDEzOyBTY2FsZS8yLjc1KSIsIndyYXBwZWRVcmwiOiIvbGVvLWdhbWUtcGsvYW5kcm9pZC9tYXRoL3BrL3Byb3BzL2hvbWU/X3Byb2R1Y3RJZFx1MDAzZDYxMVx1MDAyNnBsYXRmb3JtXHUwMDNkYW5kcm9pZDMzXHUwMDI2dmVyc2lvblx1MDAzZDMuMTMzLjFcdTAwMjZ2ZW5kb3JcdTAwM2RmZW5iaVx1MDAyNmF2XHUwMDNkNVx1MDAyNnNpZ25cdTAwM2RmMTQ5YTBiMGFlYTNiYzVlZjE5MzUwNWE1YmE4YzVlNVx1MDAyNmRldmljZUNhdGVnb3J5XHUwMDNkcGhvbmVcdTAwMjZ3ZWJ2aWV3VmVyc2lvblx1MDAzZDEwMVx1MDAyNndoUmF0aW9cdTAwM2QyLjE3In1d))