交互式技术教程
从零理解 WebADB
浏览器如何控制 Android 设备
这个教程会带你深入了解 WebADB Viewer 的每一行代码 — 从 USB 数据包到屏幕截图,从 RSA 密钥到触摸事件。
模块 01ADB 协议:设备间的"暗号"
想象你和朋友发明了一套暗号来传递消息 — 每条消息都有固定格式:先说暗号类型,再说内容。ADB 协议就是电脑和 Android 手机之间的"暗号系统"。
📦 消息结构:每条消息长什么样
ADB 的每条消息都由两部分组成:一个 24 字节的消息头(信封)和可选的数据体(信件内容)。
命令
4字节
+
参数1
4字节
+
参数2
4字节
+
数据长度
4字节
+
校验和
4字节
+
魔数
4字节
💡
魔数是什么? 就是命令的"反码"(每一位取反)。接收方用它来验证消息没有损坏 — 如果
命令 XOR 魔数 ≠ 0xFFFFFFFF,说明数据传输出了问题。
🎭 六种命令:ADB 的全部词汇
ADB 协议只有 6 种命令,就像一门只有 6 个单词的语言:
🔍 代码对照:构建一条消息
static buildMessage(command, arg0, arg1, data) {
const header = new ArrayBuffer(24);
const view = new DataView(header);
view.setUint32(0, command, true);
view.setUint32(4, arg0, true);
view.setUint32(8, arg1, true);
view.setUint32(12, data.length, true);
view.setUint32(16, checksum(data), true);
view.setUint32(20, command ^ 0xFFFFFFFF, true);
}
创建一个 24 字节的空间(信封)
DataView 让我们能按字节精确写入数据
true 表示小端序 — USB 设备的通用字节顺序
前 4 字节放命令类型(如 CNXN)
接着放两个参数(用途取决于命令类型)
然后是数据长度和校验和
最后放魔数(命令的按位取反)用于校验
🧠 小测验
ADB 消息头的大小是多少字节?
12 字节
24 字节
32 字节
48 字节
模块 02WebUSB 传输:浏览器直连硬件
通常只有操作系统驱动程序才能和 USB 设备通信。但 WebUSB 打破了这个限制 — 网页也能直接和 USB 设备"对话"。
🔌 USB 设备的"身份证"
每个 USB 设备都有一组标识码。ADB 接口的标识是固定的:
const ADB_CLASS = 0xFF;
const ADB_SUBCLASS = 0x42;
const ADB_PROTOCOL = 0x01;
🔒
安全限制:WebUSB 要求 HTTPS 环境(或 localhost)。这就是为什么我们需要部署到 Cloudflare Workers 或使用自签名 HTTPS 证书的本地服务器。
🔍 连接流程
requestDevice()
用户选择设备
→
device.open()
打开设备
→
查找 ADB 接口
匹配 FF/42/01
→
claimInterface()
独占接口
📡 数据收发:IN 和 OUT 端点
USB 通信通过端点(Endpoint)进行。ADB 接口有两个端点:
await device.transferOut(
endpointOut.endpointNumber,
message.header
);
const result = await device.transferIn(
endpointIn.endpointNumber,
24
);
transferOut = 电脑 → 手机
把消息头(24字节)发送给设备
transferIn = 手机 → 电脑
从设备读取数据,指定最大读取字节数
返回的 result.data 就是设备发回的数据
⚠️
独占性:USB 接口同一时间只能被一个程序使用。如果电脑上的
adb.exe 正在运行,浏览器就无法连接。必须先运行
adb kill-server。
🧠 小测验
为什么 WebUSB 需要 HTTPS 环境?
因为 USB 数据需要加密传输
因为浏览器要求 Secure Context 才能使用 WebUSB API
因为 Android 设备只接受 HTTPS 连接
模块 03RSA 认证:证明你是谁
当你把手机插到一台新电脑上,手机会弹出"是否允许 USB 调试?"。这背后就是 ADB 的 RSA 认证机制 — 手机需要确认连接的电脑是可信的。
🔑 认证三步曲
📱 手机
发送随机 Token
→
💻 电脑
用私钥签名 Token
→
📱 手机
用公钥验证签名
如果手机已经保存了这台电脑的公钥(用户之前点过"始终允许"),签名验证通过就直接连接。否则手机会弹窗让用户确认。
🧮 关键难点:Prehashed 签名
ADB 发送的 Token 是 20 字节 — 恰好是 SHA-1 摘要的长度。ADB 要求客户端把这 20 字节直接当作 SHA-1 摘要来签名,而不是再做一次哈希。
🚨
这是最大的坑!浏览器的 Web Crypto API 会自动对数据做 SHA-1 哈希再签名(双重哈希),导致签名永远验证失败。解决方案:手动用 BigInt 实现 RSA 运算,跳过自动哈希。
em[0] = 0x00;
em[1] = 0x01;
em[padEnd] = 0x00;
em.set(SHA1_PREFIX, offset);
em.set(token, offset);
const sig = modPow(m, d, n);
PKCS#1 v1.5 格式:00 01 FF...FF 00 [前缀] [数据]
0x01 表示这是签名操作(不是加密)
中间用 0xFF 填满,凑够 256 字节
0x00 分隔符
DigestInfo 告诉验证方"这是 SHA-1 摘要"
直接放入 Token,不做任何哈希!
最后用私钥指数 d 做模幂运算
📜 Android 公钥格式
Android 不使用标准的 PEM/DER 公钥格式,而是自定义了一个 524 字节的结构体:
modulus_size
4字节 = 64
+
n0inv
4字节 Montgomery参数
+
modulus
256字节 小端序
+
rr
256字节 R²mod n
+
exponent
4字节 = 65537
最终发送给手机的是:base64(结构体) + " webadb@browser\0"
🧠 小测验
为什么不能直接用 Web Crypto API 的 sign() 方法来签名 ADB Token?
因为 Web Crypto 不支持 RSA
因为 Token 太短了
因为 Web Crypto 会自动对数据做 SHA-1 哈希,导致双重哈希
因为浏览器不允许签名操作
模块 04实战:截屏、触摸与 Shell
连接成功后,真正有趣的部分开始了。通过 ADB 流(Stream),我们可以执行 shell 命令、截取屏幕、甚至模拟触摸操作。
🌊 ADB 流:多路复用
ADB 在单个 USB 连接上支持多个并发"流",每个流有自己的 localId 和 remoteId。就像一根电话线上同时进行多个通话。
OPEN
"shell:ls"
→
OKAY
流已建立
→
WRTE
返回数据
→
OKAY
确认收到
→
CLSE
流结束
🔒
操作锁:虽然 ADB 支持多路复用,但我们的实现使用了操作锁(mutex),确保同一时间只有一个命令在执行。这避免了消息交错导致的数据混乱。
📸 截屏的秘密
截屏命令 screencap -p 返回 PNG 格式的图片数据。但有个关键区别:
await _execStream(
'exec:screencap -p'
);
await _execStream(
'shell:screencap -p'
);
exec: 直接执行命令,二进制数据原样传输
PNG 图片数据完整无损 ✅
shell: 通过 PTY 执行,会把 \n 转成 \r\n
PNG 数据被破坏,图片无法解码 ❌
👆 触摸与滑动
Android 的 input 命令可以模拟各种输入事件:
await shellText('input tap 500 800');
await shellText('input swipe 500 800 500 200 300');
await shellText('input keyevent 3');
在网页上,我们监听 Canvas 的鼠标事件,把浏览器坐标转换为设备屏幕坐标:
const scaleX = screenWidth / canvas.getBoundingClientRect().width;
const scaleY = screenHeight / canvas.getBoundingClientRect().height;
const deviceX = (mouseX - canvasLeft) * scaleX;
const deviceY = (mouseY - canvasTop) * scaleY;
🧠 小测验
为什么截屏要用 exec: 而不是 shell:?
exec 更快
shell 会把二进制数据中的 \n 转成 \r\n,破坏 PNG 格式
exec 支持更大的数据
shell 不支持 screencap 命令
🔒 隐私政策
最后更新:2025年4月
数据收集
WebADB Viewer 是一个纯前端工具。您的设备数据(截屏、shell 命令输出等)完全在本地浏览器中处理,不会传输到任何远程服务器。RSA 密钥对存储在浏览器的 localStorage 中,仅用于 ADB 设备认证。
第三方服务
本站使用 Google AdSense 展示广告。Google 可能会使用 Cookie 和类似技术来提供个性化广告。详情请参阅 Google 隐私政策。
Cookie
本站本身不设置 Cookie。第三方广告服务(Google AdSense)可能会设置 Cookie 用于广告投放和分析。您可以通过浏览器设置管理 Cookie 偏好。
联系方式
Employed at:Tec-Do · 微信公众号:codgank · 如有隐私相关问题,请通过微信公众号或 GitHub 项目页面联系我们。
⚖️ 免责声明
工具性质
WebADB Viewer 是一个开源的开发者工具,仅供学习、调试和开发用途。本工具通过标准的 ADB(Android Debug Bridge)协议与 Android 设备通信。
使用风险
使用本工具需要在 Android 设备上开启 USB 调试模式。请确保您了解 USB 调试的安全风险。本工具按"原样"提供,不提供任何明示或暗示的保证。对于因使用本工具而导致的任何直接或间接损失,开发者不承担责任。
合法使用
请仅在您拥有合法访问权限的设备上使用本工具。未经授权访问他人设备可能违反法律法规。
第三方内容
本站展示的广告由 Google AdSense 提供,广告内容由 Google 管理,与本站无关。本站不对第三方广告内容负责。
📬 联系我们
Employed at:Tec-Do
微信公众号:codgank
个人微信
© 2025 WebADB Viewer · Tec-Do. All rights reserved.