WEBVIEW FINGERPRINT · JS REVERSE
从 App A 跳到 App B
H5 指纹与 JS 逆向实战
从 Deep Link、WebView 到指纹上报请求的一条完整分析链

导语同一个 appb:// Scheme,可以从顶层 location.href 发起,也可以从隐藏 iframe.src 发起。外部效果相同,导航层级不同。
一、两种 Scheme 写法为什么效果一样
H5-A 常见的两种写法如下:
JAVASCRIPTconst url = 'appb://web/open?...&ticket=xxx';location.href = url;const frame = document.createElement('iframe');frame.style.display = 'none';frame.src = url;document.body.appendChild(frame);
src表示子 frame 准备导航到的地址。这里是 appb://...深度链接,不是 HTTP 页面;WebView 会尝试把它交给 Native 或 Android Intent。

图 1 同一个 Scheme 的两种发起位置
关键判断隐藏 iframe 的价值主要是唤起失败后保留 H5-A,继续执行 fallback、下载提示或重试。只有 Activity、进程或 WebView 容器切换,才算真正进入 App B。
二、H5-B 采集的是谁的指纹
App B 被唤起后,H5-B 通常重新采集当前容器的环境,而不是直接读取 App A 的 Cookie、localStorage 或私有数据。

图 2 H5-B 指纹 payload 的主要输入
•WebView 环境:UA、屏幕、Canvas、WebGL、Storage。
•Native Bridge:App 版本、安装 ID、设备 token。
•跳转上下文:scene、ticket、trace_id,用于关联 App A 与 App B。
window.AppBridge不是标准 API。它只有在 Native 通过 addJavascriptInterface(..., "AppBridge")注入后才可能存在;实际名称和数据来源必须通过注册参数、实现类和调用链确认。
核心结论Scheme 传递来源信息,App B 再把跳转上下文、自己的 WebView 环境和 Native 数据组合进风控请求。
三、抓包只看 Scheme 前后
appb://不是 HTTP 请求,所以它通常不会出现在 Reqable、Charles 或 mitmproxy 的列表中。
TEXT10:00:00.120 H5-A 上报点击10:00:00.180 App A 获取跳转 ticket10:00:00.260 执行 appb://...&ticket=xxx10:00:00.520 App B 加载 H5-B10:00:00.680 加载指纹 SDK10:00:00.910 POST /v1/collect

图 3 从抓包时间线回溯参数生成链
•记录完整 Scheme URL 和 Intent Data。
•确认 Activity、进程和首个 H5-B 请求。
•对比 App B 直达与从 App A 跳入两组样本。
•长密文不等于指纹;先区分scene / ticket / data / X-Device-Token的职责。
四、JS 逆向只追最短生成链
TEXTPOST /v1/collect 的 data <- fetch / XHR 写入点 <- payload builder <- 编码或加密函数 <- JS 环境 + Native Bridge + 跳转参数
先对目标接口做一个最小 Hook:
JAVASCRIPTconst rawFetch = window.fetch;window.fetch = function (input, init) { const url = typeof input === 'string' ? input : input.url; if (url.includes('/v1/collect')) { console.log(init?.body); console.trace(); debugger; } return rawFetch.apply(this, arguments);};
•data 是当前生成,还是作为参数传入?
•加密前对象能否在局部变量中看到?
•scene、Native 数据和 JS 环境在哪一层合并?
•请求由 H5 发送,还是交给 Bridge 或 Native 网络栈?
fetch/XHR 没命中时,再检查 Worker、iframe、JSBridge 和 Native SDK。Android 侧可 Hook addJavascriptInterface,或在 JADX 中搜索 @JavascriptInterface、接口域名和 OkHttp Interceptor。
五、最后只保留一条证据链
证据只要能回答下面的问题,链路就已经成立:
TEXT谁触发了跳转?Scheme 携带了什么?H5-B 运行在哪个容器?哪个请求上报环境?哪个函数构造参数?哪些字段来自 JS,哪些来自 Native?
一句话结论App A 通过 Scheme 传递来源参数;App B 打开 H5-B 后,再采集自己的 WebView 与 Native 环境,并与跳转上下文组合成风控请求。
•抓包:确认真实请求和状态流转。
•JS 调试:还原 entry -> builder -> writer。
•Android 逆向:补齐 Bridge、Intent 与 Native 数据来源。
不要把一段随机密文直接贴上“设备指纹”的标签。只有把跳转参数、运行容器、调用栈和差分结果按时间线对齐,才能说明字段真正代表什么。
· END ·
夜雨聆风