iOS 真机 JS 注入 · 参考
术语表
全课统一命名以此为准。写文档时可直接引用。随课增补,词条标注首次出现的课号。
- pymobiledevice3 — 工具本体 · 第1课
- 纯 Python 实现的 iOS 设备操控工具箱,能和 iPhone 对话(调试、抓包、装包等)。我们用它的
webinspector 子命令。
- lockdownd 锁定守护进程 · 第1课
- iPhone 里的老牌服务,负责响应外部工具经 USB 发来的"启动某服务"请求。iOS 17 前,真机调试都靠它。
- RemoteXPC · 第1课
- iOS 17 起苹果给开发者服务换上的新通信协议。走 IPv6,配对/加密更严。老的 lockdownd 直连不再响应,是"为什么难"的总根源。
- 隧道 / tunneld / start-tunnel tunnel · 第1课
- Mac 与 iPhone 之间的一条虚拟 IPv6 通道。RemoteXPC 要求 IP 层通信,必须先拉起这条隧道,后续命令才有路走。
tunneld 是自动常驻版,start-tunnel 是手动一次性版。
- RSD RemoteServiceDiscoveryService · 第1课
- 隧道里的"服务发现台",跑在设备 IPv6 地址的
58783 端口。作用是告诉调试端"你要的服务在哪个地址端口"。缺它会报 RSDRequired。
- webinspectord · 第1课
- iPhone 里常驻的调试"接待员"进程,掌管哪些网页可被外部远程调试。前置:设备上 Web Inspector 开关要打开。
- WKWebView 网页容器 · 第1课
- App 内嵌的浏览器窗口。飞书/妙记/豆包里承载我们网页的就是它。一个 App 可同时开多个。
- iwdp ios-webkit-debug-proxy · 第2课
- 经典的 iOS 网页调试代理,把设备的网页调试能力翻译成 Chrome 开发者工具能连的形式。依赖老的 lockdownd 门,iOS 17 后作废——"架构变了老工具没跟上"的典型。
- CDP Chrome DevTools Protocol · 第2课
- Chrome 系开发者工具与浏览器内核对话的标准协议(如
Runtime.evaluate 执行 JS)。Android 侧调试直接走它;iOS 侧 webinspector cdp 想把设备能力也暴露成 CDP,但该命令在此环境有 asyncio bug。
- asyncio Python 异步框架 · 第2课
- Python 的异步 I/O 库。这里只需知道:
webinspector cdp 命令是栽在它自己这段异步代码的 bug 上——属"工具不成熟",不是架构问题。
- 两类死因 · 第2课 · 本课核心
- A 架构变了老工具没跟上(iwdp)→ 换工具;B 新工具不成熟/链路太脆(cdp、inspector_session)→ 找同方向更轻更稳的口子。分清两类=缩小搜索范围。
- --userspace / 用户态隧道 PyTCP userspace tunnel · 第3课
- pymobiledevice3 的一种隧道模式:用纯 Python 网络栈(PyTCP)在自己进程内跑完整 TCP/IP,不建内核网卡、不要 root、不需单独 tunneld。代价:host→device 慢一点、隧道只活在本进程不可被别的程序共享。对治死胡同三的"重且脆"。
- TUN/TAP 接口 内核级虚拟网卡 · 第3课
- 操作系统内核里的虚拟网络接口。默认隧道要创建它,因此必须 root/sudo。userspace 模式绕开它。
- WebKit Inspector Protocol WebKit 检查器协议 · 第3课
- 苹果给 Safari/WKWebView 调试用的原生协议。js-shell 靠它发现网页(
Target.targetCreated)、执行 JS(Runtime.evaluate)、取回结果。因是原生协议,天然兼容 iOS 17 新架构。前置:设备开 Web Inspector 即可,无需 Remote Automation。
- Runtime.evaluate 求值命令 · 第3课
- "把这段 JS 丢进网页运行时执行并返回结果"的命令。CDP 和 WebKit Inspector Protocol 里同名同义——"求值"这个动作是共通的,区别在走哪条协议/实现。
- TTY 终端设备 teletype · 第4课
- 操作系统里"终端"的抽象:有回显、行编辑等交互特性。交互式程序(如 js-shell)会向它要参数。管道不是 TTY,喂给它会报
Inappropriate ioctl for device。
- pty 伪终端 pseudo-terminal · 第4课
- 用软件伪造的一对终端(主/从两端)。
pty.openpty() 造一对,把子进程的输入输出接到"从端",脚本从"主端"替人读屏/发键——让交互式程序以为有真人在终端操作。自动化 js-shell 的关键。
- opened-tabs · 第4课
pymobiledevice3 webinspector opened-tabs:列出设备上当前可调试的网页及其完整 URL。动手前先用它备份 URL,防止 --url 导航翻车后找不回现场。
- \x1b[B 下箭头转义序列 · 第4课
- 终端里"按下方向键↓"对应的字符序列(ESC +
[B)。脚本发这串给 js-shell 的选页菜单,等于"替人按下箭头"。
- JSBridge 对讲机 · 第5课
- 网页 JS 与 App 原生代码互相喊话的通道。本次要探的
common.getSettings 就走它。iOS 发送口:webkit.messageHandlers.invokeNative.postMessage(...);Android 发送口:window.Lark_Bridge.invokeNative(...);两端收口相同:LarkWebViewJavaScriptBridge.nativeCallBack。
- 异步桥调用 async bridge call · 第5课
- 网页发出请求后挂回调等 native 回话,结果不在当场。若容器没接该接口,回调永不来。是本次探测的难点。
- callbackID · 第5课
- 每次桥调用带的唯一标识。探针用唯一 callbackID 截获自己这一枪的回话,避免和 App 自身调用串味。
- 两步走探针 two-step probe · 第5课 · 本次核心手法
- 破"异步 + js-shell 独立会话"的招:第一枪发请求并把状态埋进
window.__PROBE_R__={state:'waiting'}(回调命中改 done);第二枪隔几秒读它。靠页面全局变量跨会话保留把"发"与"读"解耦。读到仍 waiting = native 不响应的铁证。必配对照实验(同探针打会正常回话的容器)才能排除自身嫌疑。
参考文档 · 随课增补