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 不响应的铁证。必配对照实验(同探针打会正常回话的容器)才能排除自身嫌疑。

参考文档 · 随课增补