OnePlus 8T 无线渗透与 AI 实战指南
简体中文 · English concise edition
从会用工具,到理解系统、协议、证据与模型;所有实操以这台真实手机为实验平台。

先说目标:你要成为哪种人?
不是背下十条 nmap 参数的人,也不是把 AI 的答案直接粘进终端的人。读完并完成本书实验后,你应当能够:
- 画出一次请求从 App、Android、VPN、Wi-Fi 到服务器的完整路径;
- 解释 root、SELinux、Android UID、PRoot “假 root”和 Linux capability 的区别;
- 从 RSSI、DNS、TCP、TLS、802.11 管理帧和 Android 日志中找证据;
- 知道这台手机能做什么、为什么能做,以及哪些事受内核和射频硬件限制;
- 对自己构建或明确授权的 App 做静态观察、动态插桩和定向 TLS 调试;
- 理解大模型的 token、attention、上下文、工具调用和幻觉,并让 AI 帮你形成可验证假设;
- 把每次实验沉淀成可复现的笔记、脚本、哈希和结论,而不是只留下聊天记录。
本书的学习循环只有五步:

flowchart LR
O["观察:发生了什么?"] --> H["假设:哪一层可能解释它?"]
H --> E["实验:只改变一个变量"]
E --> V["证据:日志、包、哈希、时间线"]
V --> R["复盘:结论能迁移到别处吗?"]
R --> O
怎么使用 GitHub Pages 和内部 Wiki?
两者不是二选一,而是“教材层”和“研究层”:
| 入口 | 主要内容 | 什么时候看 |
|---|---|---|
| GitHub Pages / 本主教材 | 已校对的原理、推荐顺序、安全实验、当前可靠结论 | 第一次学习、按 12 周路线推进、复习知识框架 |
| 内部 Wiki | 原始来源摘要、现场证据、互斥假设、矛盾、失败路线和仍在变化的设备状态 | 排障、追问“为什么”、核验教材结论、开展新研究 |
推荐循环:先在 Pages 学会一个概念 → 在手机上完成实验 → 把原始证据和疑问写入内部 Wiki → 等结论稳定后再整理回 Pages。 Pages 负责让你学得顺,Wiki 负责让你研究得深;不要从未经校对的原始日志开始背命令,也不要把 Pages 的简化图当成全部证据。
导航
- 第一部分:认识你的实验平台
- 第二部分:Linux、Android 与网络基本功
- 第三部分:无线网络——从电波到协议
- 第四部分:Android App 安全与动态分析
- 第五部分:Magisk、启动链与可恢复工程
- 第六部分:USB 与物理接口
- 第七部分:AI 大模型——从“会问”到“会验证”
- 第八部分:综合项目——从工具使用者到研究者
- 第九部分:日常速查与故障树
- 官方资料与继续学习
安全与授权边界
下面的实验只允许用于:
- 你自己的 OnePlus 8T、路由器、电脑和测试账号;
- 明确隔离的实验 SSID/VLAN;
- 你自己编译的 APK、训练 APK、CTF;
- 有书面授权且范围、时间和目标明确的测试。
本书不会提供邻居 Wi-Fi、公共网络、第三方账号、钓鱼、持久化驻留、凭据窃取、射频干扰或 GPS 欺骗的操作步骤。无线电主动发射还受频谱法规约束,“设备是自己的”不自动等于“可以任意发射”。
[!important] AI 不能替你判断授权。目标清单、授权书和停止条件必须由人确认。
第一部分:认识你的实验平台
1. 当前设备基线
本文命令以 2026-08-07 的实际状态为准:
| 层 | 当前实现 | 角色 |
|---|---|---|
| 硬件 | OnePlus 8T,arm64 | 电池供电的移动实验平台 |
| ROM | LineageOS 21 / Android 14 | 接近 AOSP 的 Android 用户空间 |
| root | Magisk 30.7 | 受策略控制的真实 Android root |
| 终端 | Termux 0.118.3 F-Droid release | Android App UID 下的命令环境 |
| Linux | Kali,经 PRoot-Distro 运行 | Linux 用户态工具箱,不是虚拟机 |
| 网络 | Wi-Fi + CMFA VpnService | always-on、非 lockdown 的路由/DNS 层 |
| AI CLI | OpenCode 1.18.13 glibc arm64 | 在 Kali 内调用模型和工具 |
| 动态分析 | Frida 17.17.0 / Objection 1.12.5 | 只在实验时启动 |
| 移动 AI UI | Happy preview 1.7.0 | 连接本机 127.0.0.1:3005 |
| USB | configfs HID 脚本 | 自有测试机上的安全键盘演示 |
最终安全状态:Magisk 模块目录为空,没有全局 CA、APEX tmpfs 覆盖或 DNS mount;Frida 不自启;GLM key 位于 Kali 私有 0600 文件;Happy API 默认只监听 loopback。
2. 系统架构:五种“权力”不要混在一起
flowchart TB
HW["OnePlus 8T 硬件\nWi-Fi / USB / NFC / BLE"]
K["Android Linux 内核\n驱动 / SELinux / capabilities"]
A["LineageOS 21\nFramework / App Sandbox / VpnService"]
M["Magisk 30.7\n真实 su 与启动阶段"]
T["Termux release\nUID 10205"]
P["PRoot-Distro\nptrace 路径转换"]
KL["Kali 用户空间\n工具、glibc、Python"]
C["CMFA\ntun0 / DNS / 代理规则"]
F["Frida server\nroot,按需启动"]
H["Happy App ↔ 127.0.0.1:3005"]
HW --> K --> A
K --> M
A --> T --> P --> KL
A --> C
M --> F
T --> H

把这张图当作“权限地图”:琥珀色电梯表示 Magisk 取得的真实 Android root;TERMUX UID → PROOT → KALI USERSPACE 是用户空间通道,碰到 capability 锁仍会被挡住;VPN ROUTE 负责改道流量,不负责开权限门。
关键区别:
- Android root:Magisk
su获得 UID 0、capability 和 Magisk SELinux domain。 - Kali 里的 root 提示符:PRoot 把进程“看起来”映射成 root,但宿主仍是 Termux App UID。
- SELinux:即使 UID 0,也仍受 domain 和规则约束。
- Linux capability:例如抓包需要
CAP_NET_RAW;PRoot 的root@kali不会凭空获得它。 - VPN 路由权:CMFA 用 Android
VpnService接收 App 流量,但它不是内核 root。
PRoot-Distro 官方说明其核心是通过 ptrace 拦截系统调用并改写路径;它不是带 namespace、cgroup、seccomp 的容器隔离。参见 PRoot-Distro 工作原理。
3. 五分钟健康检查
在 Termux 中:
selfcheck-lineage.sh
oc --version
stack status
proot-distro list
预期核心输出:
✓ Kali 内官方 glibc OpenCode 可执行
✓ Kali DNS 正常(不依赖 Magisk 模块)
✓ GLM key 位于私有 0600 文件
结果: 3 通过, 0 失败
从电脑的 ADB 中:
adb devices
adb shell su -c id
adb shell "su -c 'magisk --sqlite \"SELECT * FROM settings;\"'"
adb shell settings get secure always_on_vpn_app
adb shell settings get secure always_on_vpn_lockdown
adb shell ip -brief addr show tun0
当前预期:
su -c id是uid=0(root);bootloop=0(启动早期短暂为 1、完成后归零是正常状态机);- always-on 包为 CMFA,lockdown 为 0;
tun0有172.19.0.1/30。
练习:不要只说“网络坏了”
将故障拆成四层:
flowchart LR
L1["链路\nWi-Fi 是否关联"] --> L2["路由\n是否有 default route"]
L2 --> L3["名称\nDNS 是否能解析"]
L3 --> L4["应用\nTLS/API 是否成功"]
分别找一个命令验证,不允许用下一层的失败代替上一层结论。
第二部分:Linux、Android 与网络基本功
4. 终端基本功:先读,再改
4.1 三个环境的提示符
| 环境 | 进入方式 | 适合做什么 |
|---|---|---|
| Android shell | adb shell |
getprop、dumpsys、pm、logcat |
| Termux | 打开 App | 启动 PRoot、Happy、文件编排 |
| Kali | proot-distro login kali |
glibc 工具、Python、协议分析、AI CLI |
不要把命令盲目跨环境复制。pm 是 Android 命令,apt 属于 Kali,pkg 属于 Termux。
4.2 每次实验都建立证据目录
在 Kali 中:
LAB="$HOME/labs/$(date +%Y%m%d-%H%M)-topic"
mkdir -p "$LAB"/{notes,logs,pcap,artifacts}
date -Ins | tee "$LAB/notes/start-time.txt"
uname -a | tee "$LAB/logs/uname.txt"
实验结束:
find "$LAB" -type f ! -name SHA256SUMS -print0 \
| sort -z | xargs -0 sha256sum > "$LAB/SHA256SUMS"
为什么要哈希?因为“我分析的文件”和“你复核的文件”必须是同一个比特序列。
4.3 管道不是魔法
cmd wifi status | tee wifi-status.txt
grep -i rssi wifi-status.txt
| 把前一个进程的 stdout 接到后一个进程的 stdin;tee 同时写文件和屏幕。遇到空结果,先问:数据在 stdout、stderr,还是根本没有产生?
5. 从一条请求理解 TCP/IP
一次 App 请求不是“联网”两个字,而是一条链:
sequenceDiagram
participant App as Android App
participant VPN as CMFA / tun0
participant DNS as DNS 172.19.0.2
participant TCP as TCP/IP
participant TLS as TLS
participant API as 远端 API
App->>VPN: 请求访问域名
VPN->>DNS: 查询 A/AAAA
DNS-->>VPN: 返回 IP
VPN->>TCP: 建立连接
TCP->>TLS: ClientHello / ServerHello
TLS->>API: 加密 HTTP 请求
API-->>App: 加密响应经原路返回

图中青色是出站请求,琥珀色是返回数据。关键观察:VPN 是手机内部的虚拟路由层;最终承载数据离开手机的仍是 Wi-Fi 物理链路。TLS 在 TCP 之上保护应用数据,两者不是同一层。
实操 1:观察当前 Wi-Fi 与路由
adb shell cmd wifi status
adb shell ip -brief addr show wlan0
adb shell ip route
adb shell ip -brief addr show tun0
回答:
wlan0的地址属于哪个 CIDR?- default route 指向哪里?
tun0为什么没有物理 MAC?- VPN 存在时,流量为何仍要经过
wlan0发射?
实操 2:DNS 分层验证
在 Kali:
cat /etc/resolv.conf
getent ahostsv4 open.bigmodel.cn
dig open.bigmodel.cn A
curl -I --max-time 10 https://open.bigmodel.cn/
判断规则:
getent失败:先查 resolver、路由和 CMFA;- 能解析但
curl连接超时:查路由、代理规则、端口; - TCP 成功但证书/HTTP 失败:进入 TLS 或应用层;
- 不要看到
curl失败就直接改/etc/resolv.conf。
这台机器曾经误用 Magisk DNS 模块;最终方案是 CMFA DNS + Kali resolver 文件,没有系统 mount。
不要用一张 VPN 首页截图证明“网络已经修好”:按钮文案、常驻通知和真实转发状态可能不同步。真正的联网证据必须同时覆盖路由、DNS 和应用请求三层;本书因此不把某次现场截图当作长期状态证明。
实操 3:用本机 HTTP 服务理解 socket
在 Kali 终端 A:
python3 -m http.server 8765 --bind 127.0.0.1
在 Kali 终端 B:
curl -v http://127.0.0.1:8765/
ss -ltnp | grep 8765
观察三件事:监听地址、端口、进程。把 127.0.0.1 改成 0.0.0.0 会扩大暴露面,所以本机服务默认使用 loopback。
6. 为什么 Kali 有 tcpdump 却抓不了包?
现场实测:
tcpdump -D
tcpdump -i lo -c 1
第二条会提示需要 CAP_NET_RAW。原因不是“tcpdump 坏了”,而是:
flowchart LR
B["tcpdump 二进制存在"] --> S["请求 packet socket"]
S --> C{"宿主进程有 CAP_NET_RAW?"}
C -- "否:Termux UID + PRoot" --> D["Permission denied"]
C -- 是 --> P["获得原始包"]
因此本书采用三种抓包来源:
- 授权实验 AP/电脑上的 Wireshark;
- Android VPN capture 类工具对本机 App 流量抓包;
- 已有 PCAP 拷入 Kali,用
tshark -r离线分析。
PRoot 中优先使用不要求 raw socket 的 nmap -sT -Pn,不要默认复制需要原始 SYN 包的 -sS。
第三部分:无线网络——从电波到协议
7. 先建立无线分层模型
flowchart TB
RF["物理层:频率、带宽、调制、SNR"]
MAC["802.11 MAC:管理/控制/数据帧"]
SEC["链路安全:WPA2/WPA3、4-way handshake"]
IP["IP:地址、路由、ICMP"]
TRANS["TCP/UDP:端口、可靠性、拥塞"]
APP["DNS/HTTP/TLS/QUIC"]
RF --> MAC --> SEC --> IP --> TRANS --> APP

这是一条“接收路径”:电波先被无线芯片还原成 802.11 帧,链路层完成 WPA2 处理后才露出 IP 包,应用最终在 TLS 会话中解释数据。墙会衰减信号,噪声底则决定信号是否容易辨认——所以 RSSI 强不等于通信质量必然好。
7.1 RSSI 和 SNR
- RSSI 是接收功率的相对/实现相关表示,常见单位近似 dBm;越接近 0 通常越强。
- 噪声底决定“能不能听清”,所以强度不等于质量。
- SNR = 信号功率 − 噪声功率(以 dB 表示)。
- 速率下降、重传和漫游可能来自干扰、遮挡、信道拥挤,而不只是“离路由器远”。
实操 4:做一张自己的室内信号地图
在房间选 5 个点,每个点运行:
adb shell cmd wifi status
记录 RSSI、frequency、link speed、位置和时间。不要自动化到失去观察:先手记 5 点,再思考墙体、人体遮挡和 2.4/5 GHz 的差异。
输出一张表:
| 点位 | RSSI | 频率 | 链路速率 | 障碍物 | 假设 |
|---|---|---|---|---|---|
| 路由器旁 | |||||
| 一堵墙后 | |||||
| 两堵墙后 |
进阶:重复三次,计算均值和离散程度。一次读数不能代表稳定状态。
8. 802.11 帧:无线不只是“以太网在空气里”
802.11 常见帧类型:
| 类别 | 示例 | 你在分析什么 |
|---|---|---|
| 管理帧 | Beacon、Probe、Authentication、Association、Deauthentication | 网络发现与状态机 |
| 控制帧 | ACK、RTS、CTS | 介质访问和可靠性 |
| 数据帧 | QoS Data | 上层 IP 数据 |
这台 OnePlus 8T 当前内核/驱动组合没有可用的 monitor + injection 路径。普通 wlan0 只暴露关联后的接口,不会给你邻居网络的原始 802.11 帧。手机适合做控制、记录和离线分析;原始采集放在你自己的实验 AP 与支持 monitor 的外部采集端。
实验台搭建
flowchart LR
AP["自有实验 AP\nSSID: LAB-8T\n独立访客 VLAN"]
P["OnePlus 8T\n控制 / App / AI / 分析"]
C["旧手机或笔记本\n实验客户端"]
S["支持 monitor 的采集电脑\n只监听实验信道"]
AP --- P
AP --- C
AP -. "授权原始帧采集" .- S
S -->|"PCAP 拷入"| P
实验 AP 不连接工作/家庭敏感网段;SSID、BSSID 和测试密码不要复用真实网络。
实操 5:离线识别管理帧与异常断连
把自己的实验 PCAP 复制进 Kali 后:
capinfos lab-wifi.pcapng
tshark -r lab-wifi.pcapng -Y 'wlan.fc.type == 0' \
-T fields -e frame.time_relative -e wlan.fc.type_subtype -e wlan.sa -e wlan.da \
| head -30
只做检测:列出 deauthentication 帧及 reason code。
tshark -r lab-wifi.pcapng -Y 'wlan.fc.type_subtype == 0x000c' \
-T fields -e frame.time_relative -e wlan.sa -e wlan.da -e wlan.reason_code
思考:一次正常漫游可能有 deauth;大量、周期性、多源伪造才更像异常。检测必须结合时序、信号和上下文。
9. WPA2 四次握手:PCAP 里没有明文密码
简化关系:
sequenceDiagram
participant AP as AP / Authenticator
participant STA as Client / Supplicant
AP->>STA: Message 1: ANonce
STA->>AP: Message 2: SNonce + MIC
AP->>STA: Message 3: GTK + MIC
STA->>AP: Message 4: ACK + MIC

图里的两块“工作台”表示 AP 与客户端使用共同的先验材料和双方 nonce 独立推导出匹配的会话密钥。MIC 是消息完整性校验,不是麦克风;握手线上没有一份可直接读出的明文密码。
WPA2-Personal 的 PMK 来源可概括为:
PMK = PBKDF2-HMAC-SHA1(passphrase, SSID, 4096, 256 bits)
PCAP 提供的是验证候选口令所需的握手材料,不是可直接“解密出来”的密码。
实操 6:用你自己的已知口令理解离线验证
仅对 LAB-8T 使用一个专用测试口令,在采集电脑上获取你自己的握手 PCAP。复制到手机后:
tshark -r lab-wpa2.pcapng -Y eapol
printf '%s\n' wrong-one '你的实验口令' wrong-two > lab-wordlist.txt
aircrack-ng -w lab-wordlist.txt lab-wpa2.pcapng
这里的目标不是跑巨型字典,而是回答:候选口令怎样经 KDF 和握手 MIC 被验证?随后删除包含测试口令的临时 wordlist。
你真正应该学会的防御结论
- 长随机口令抵抗离线猜测;
- SSID 参与 KDF,改 SSID 会改变 PMK;
- WPA3-SAE 改变了离线猜测模型,但配置、兼容模式和客户端实现仍需审计;
- PMF/802.11w 能保护一部分管理帧,检测时要确认协商结果,而不是只看 AP 宣称。
10. BLE、NFC 与 SDR:别把“能扫描”说成“能嗅探”
BLE
adb shell dumpsys bluetooth_manager
Android App 可以主动扫描广告、连接你自己的 BLE 设备并访问 GATT;这不等于能被动看到别的两台设备之间的连接事件。被动链路嗅探需要专用硬件和授权实验。
练习:拿一块你自己的 BLE 开发板,记录 service、characteristic、property(read/write/notify)及 UUID 的语义;先读协议,再写值。
NFC
adb shell dumpsys nfc
内置 NFC 控制器适合 Android API 的标签读写和卡模拟实验,不等同于 Proxmark3 的原始射频、调制与旁路分析能力。
SDR
本机当前没有可用的 RTL-SDR 内核驱动路径。可以把其它设备合法采集的 IQ 文件复制进 Kali,学习频谱、瀑布图和调制;不提供主动干扰/欺骗步骤。
第四部分:Android App 安全与动态分析
11. Android 安全模型
flowchart TB
APK["APK:代码、资源、Manifest、签名"]
UID["安装时分配 App UID"]
SB["Linux DAC + SELinux Sandbox"]
IPC["Binder / Intent / ContentProvider"]
NET["Network Security Config / TLS"]
KEY["Keystore / 文件加密"]
APK --> UID --> SB
SB --> IPC
SB --> NET
SB --> KEY

左侧是静态观察:从 Manifest、代码和资源画出城市图纸;中间的 UID 与 SELinux 是不同的检查层;Binder 是跨进程桥梁,TLS 是出站保护通道;右侧 Frida 显微镜只在受控实验期间观察运行时,不是一个万能解锁按钮。
APK 签名主要证明更新链和发布者连续性,不代表代码“安全”;root 能突破许多 App 沙箱边界,但 SELinux、硬件密钥和服务端校验仍可能限制你。
12. 实操案例:解释 Happy 的 Google Play 报错
Play 版曾出现如下页面:

当时其它手机能正常使用同一 Wi-Fi,因此“网络坏了”不是充分解释。证据链是:
adb shell dumpsys activity activities | grep -m1 mResumedActivity
adb logcat -d | grep -iE 'pairip|license|play store|com.ex3ndr.happy'
前台进入 com.pairip.licensecheck.LicenseActivity,且设备没有 Play Store。结论:这是 Play 分发包装的授权依赖,不是 DNS 或 Wi-Fi 故障。
解决方案是固定官方源码提交自行构建 preview flavor:
adb shell pm list packages | grep happy
adb shell cmd package resolve-activity --brief com.slopus.happy.preview
adb shell am start -W -n com.slopus.happy.preview/.MainActivity
第一次自编 preview 包虽然绕过了 PairIP,却在点击“创建账户”时继续失败。不要把“能打开首页”当成服务可用;真实证据是 logcat:
adb logcat -c
adb shell am start -W -n com.slopus.happy.preview/.MainActivity
# 在手机点击“创建账户”后:
adb logcat -d | grep -iE 'CLEARTEXT|ERR_NETWORK|127.0.0.1:3005'
当时的决定性错误是:
CLEARTEXT communication to 127.0.0.1 not permitted by network security policy
原因是 preview 包 target SDK 36,而 Android 14 默认阻止明文 HTTP。这里不能为了省事设置全局 android:usesCleartextTraffic="true";正确修复是在 preview flavor 中加入 per-app Network Security Config:
<network-security-config>
<base-config cleartextTrafficPermitted="false" />
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="false">127.0.0.1</domain>
<domain includeSubdomains="false">localhost</domain>
</domain-config>
</network-security-config>
这条策略只允许 App 访问本机回环 HTTP;其他主机的 HTTP 仍被拒绝,HTTPS 和外部服务器连接不受影响。公开仓库不分发本机签名 APK。复现时应从 Happy 上游源码固定一个已审阅的 commit,在 preview flavor 中加入上述最小白名单,记录构建环境与产物 SHA-256 后自行签名。覆盖安装可保留原有数据:
adb install -r <你从固定源码构建并签名的-preview.apk>
修复后的验收不能停在首页。实际点击“创建账户”后,server 日志中 /v1/auth 返回 200,后续 /v1/sessions、/v1/machines、/v1/feed 也返回 200,App 进入“终端 / 已连接”:


logcat 中仍会有 requires the Google Play Store, but it is missing 的可选服务警告,但它没有阻塞本机认证。学习点:同一个 UI 错误可能来自网络、分发授权、Android 明文策略、依赖缺失或应用逻辑。先找前台 Activity、客户端 logcat 与服务端请求日志,再下结论。
13. 静态观察:从 Manifest 开始
对你自己编译或明确授权的包:
PKG=com.slopus.happy.preview
adb shell pm path "$PKG"
adb shell dumpsys package "$PKG" | less
adb shell cmd package resolve-activity --brief "$PKG"
关心:
- exported Activity/Service/Receiver;
- permission 及 protection level;
- deep link / intent-filter;
android:debuggable、backup 与 cleartext policy;- target SDK 与行为变化。
如果把 APK 拉到 Kali:
adb shell pm path "$PKG"
# 将输出的 base.apk 路径交给 adb pull;不要假设每个应用只有一个 split。
进阶目标不是“搜到字符串”,而是画出输入 → 信任边界 → 敏感操作 → 输出的数据流。
14. 动态观察:Frida/Objection 最小安全闭环
Frida 官方 Android 文档将 rooted device + frida-server 作为入门模式;Objection 1.12.x 的主入口是 start,不是旧教程里的 explore。参考 Frida Android 与 Objection 使用说明。
14.1 启动 server:只监听 loopback
在 Termux:
su -c '/data/adb/frida/frida-server -l 127.0.0.1:27042 -D'
检查:
su -c 'ss -ltnp | grep 27042'
不要把它监听在 0.0.0.0,也不要放在 world-readable 的 /data/local/tmp 常驻。
14.2 在 Kali 连接
proot-distro login kali
export PATH=/root/.local/bin:$PATH
frida --version
objection version
frida-ps -H 127.0.0.1:27042
以本机自编 Happy preview 做只读实验:
objection -N -h 127.0.0.1 -P 27042 \
-n com.slopus.happy.preview start
在 Objection REPL 中:
env
android hooking list activities
完成后:
exit
su -c 'pkill -x frida-server'
su -c 'pidof frida-server || true'
14.3 学会 hook,而不是背 hook
以一个你自己的训练类为例:
Java.perform(function () {
const Gate = Java.use('com.example.lab.LicenseGate');
Gate.isAllowed.implementation = function () {
const original = this.isAllowed();
console.log('isAllowed original = ' + original);
return original;
};
});
第一步只记录原值,不修改行为。你需要理解:类加载器、方法重载、Java ↔ JNI、实例方法的 this、进程生命周期。先观察再修改,才能区分 hook 错了还是应用逻辑真的如此。
15. Android 14 TLS 调试:定向,不全局
旧方案把用户 CA 全局提升为系统 CA,或 tmpfs 覆盖 Conscrypt APEX,会扩大整机 MITM 面。最终策略:
flowchart TD
Q{"你拥有 APK 源码吗?"}
Q -- 是 --> D["debug build + Network Security Config debug-overrides"]
Q -- 否,但有明确测试授权 --> F["临时 Frida/Objection 定向观察"]
Q -- 否且无授权 --> X["停止"]
D --> C["仅调试证书 / 仅目标 App"]
F --> C
自有源码推荐:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<debug-overrides>
<trust-anchors>
<certificates src="@raw/debug_cas" />
</trust-anchors>
</debug-overrides>
</network-security-config>
debug-overrides 仅在 android:debuggable=true 时生效,release 会忽略。参见 Android Network Security Configuration。
对明确授权、无法重编译的目标,Objection 中可临时尝试:
android sslpinning disable
测试完成立即退出并停止 Frida。银行、支付、他人账号和生产 App 不作为练习目标。
第五部分:Magisk、启动链与可恢复工程
16. Magisk 在启动链的什么位置?
flowchart LR
BL["Bootloader"] --> BI["boot image / ramdisk"]
BI --> MI["Magisk init"]
MI --> PFD["post-fs-data\n阻塞、早期"]
PFD --> Z["Zygote / Android Framework"]
Z --> LS["late_start service\n非阻塞"]
LS --> BC["boot-complete\n计数归零"]
Magisk 官方说明 post-fs-data 是阻塞阶段,常规脚本更适合 late_start service;模块目录位于 /data/adb/modules。参考 Magisk Developer Guides。
17. Safe mode 案例:为什么“事后是 0”不矛盾?
这台设备曾经每次启动都像进入 Magisk safe mode。源码条件可简化为:
boot counter threshold OR safemode property OR key combo
错误做法是只 patch check_key_combo(),因为它没有证明实际命中哪条分支。更关键的是:启动完成会把计数器清零,因此事后看到 0 不能反证早期从未为 1 或更高。

图中 THRESHOLD、PROPERTY 与 KEY COMBO 是并列候选触发分支;没有现场证据时不能擅自指定具体按键。下方的时间戳说明同一次启动里“早期为 1”和“完成后为 0”可以同时为真,决定性信息是何时采样。
受控复测两次都观察到:
启动早期 bootloop=1
boot-complete 后 bootloop=0
safe-mode properties 为空
模块没有被禁用
实操 7:早期时间线采样
在电脑上执行,只做观察:
adb reboot
adb wait-for-device
for i in $(seq 1 45); do
printf '%s boot_completed=' "$(date -Ins)"
adb shell getprop sys.boot_completed | tr -d '\r'
adb shell "su -c 'magisk --sqlite \"SELECT * FROM settings;\"'" 2>/dev/null || true
sleep 1
done | tee magisk-early-boot.log
再补:
adb shell getprop persist.sys.safemode
adb shell getprop ro.sys.safemode
adb shell "su -c 'find /data/adb/modules -maxdepth 2 -name disable -print'"
分析原则:时间戳优先于事后快照;一个变量的最终值不能描述完整状态机。
紧急退路
Magisk 官方 FAQ 建议模块导致 bootloop 时可用 safe-mode 按键组合;ADB 可用时,magisk --remove-modules 会删除全部模块并重启。它是破坏性救援命令,不是日常诊断命令。参见 Magisk FAQ。
18. 备份:能恢复才叫备份
当前主机保留:
- Kali age 加密备份;
- Termux base zstd 备份;
- 原 debug APK;
- Magisk 模块移除前归档;
- Happy preview APK 与专用签名证书。
Kali 密文:
backups/2026-08-06-termux-migration/kali-before-fdroid.tar.gz.age
SHA-256: 4e6715729c628f505e4d6f331aca6405e602882ff69268d70b35329cb7a7271a
私钥存 macOS Keychain service:com.oneplus8t.kali-backup.age。
恢复前先验证密文哈希,再在 macOS zsh 中:
identity=$(security find-generic-password \
-a lazy -s com.oneplus8t.kali-backup.age -w)
age -d -i <(printf '%s\n' "$identity") \
-o kali-before-fdroid.tar.gz \
backups/2026-08-06-termux-migration/kali-before-fdroid.tar.gz.age
unset identity
gzip -t kali-before-fdroid.tar.gz
不要在没验证目标目录和 UID 前直接覆盖手机数据。
第六部分:USB 与物理接口
19. BadUSB 的底层:描述符 + report
USB gadget 让手机作为 USB 设备向电脑声明自己的功能。HID 键盘的关键不是“运行了一条命令”,而是:
sequenceDiagram
participant Phone as OnePlus 8T gadget
participant Host as 自有测试电脑
Phone->>Host: Device/Configuration/HID descriptors
Host-->>Phone: 枚举为键盘
Phone->>Host: 8-byte HID report: modifier + keycodes
Phone->>Host: 全零 report:释放按键
这台设备使用:
g1:日常 ADB/MTP gadget;g2:实验 HID gadget;- 同一个 UDC 在切换时会让 ADB 暂时断开。
20. 实操 8:只在文本编辑器里打一句话
准备:
- 使用你自己的离线电脑;
- 手动打开一个空白文本编辑器并聚焦;
- 不使用 shell、运行框、浏览器或登录页面;
- 手机上脚本已部署为 root:root 0700。
从 ADB 触发时必须脱离会断开的会话:
adb shell su -c \
'setsid sh /data/local/tmp/badusb-ducky.sh "BadUSB OK - OnePlus 8T" >/dev/null 2>&1 &'
脚本会:互斥加锁 → 保存 g1 UDC → 解绑 g1 → 建 g2 HID → 发按键 → 拆 g2 → 恢复 g1。
复盘:
- 为什么每次按键后要发全零 report?
- 为什么
SIGKILL无法被 trap 捕获? - 为什么 UDC 恢复必须幂等?
- 为什么 ADB 会断而脚本不能依赖 ADB 父进程继续存活?
本书不提供绕锁屏、下载执行、凭据获取或驻留 payload。
第七部分:AI 大模型——从“会问”到“会验证”
21. Transformer 到底在做什么?
flowchart LR
T["文本 / 日志 / 代码"] --> TOK["Tokenizer\n切成 token"]
TOK --> EMB["Embedding\n向量表示"]
EMB --> ATT["Self-Attention\n按上下文混合信息"]
ATT --> FFN["Feed-Forward\n非线性变换"]
FFN --> L["多层堆叠"]
L --> P["下一个 token 的概率分布"]
P --> OUT["采样/选择并继续生成"]
它不是数据库检索器,也不是形式证明器。它擅长从上下文中压缩模式并生成后续 token,因此:
- 能快速提出假设、解释日志、写解析器和测试计划;
- 会把“很像真的”当成“真的”,产生幻觉;
- 不知道你是否有授权;
- 上下文中的日志、网页和 README 可能包含 prompt injection;
- 工具输出和模型解释必须分开保存。
22. OpenCode:手机上的 AI 工具调用层
当前启动链:
flowchart LR
U["Termux 用户"] --> OC["$PREFIX/bin/oc"]
OC --> PD["PRoot-Distro login kali"]
PD --> BIN["/opt/opencode-1.18.13/opencode"]
BIN --> CFG["模型配置"]
CFG --> KEY["/root/.secrets/glm-api-key\n0600"]
BIN --> API["模型 API,经 CMFA"]
基本操作:
selfcheck-lineage.sh
oc --version
oc
最小非交互验证:
oc run '只回复:模型链路正常'
不要执行:
cat /root/.secrets/glm-api-key
“我能读出 secret”不是健康检查。健康检查只验证文件存在、权限正确和实际 API 调用成功。
OpenCode 的模型/Provider 配置会变化,参考 OpenCode Config 与 Models。
23. Happy:把 AI 会话带到手机 UI
在 Termux:
stack up
stack status
stack log
stack cli
stack down
架构:
flowchart LR
APP["Happy preview App"] <-->|"E2E 会话 / loopback"| API["Happy server-light\n127.0.0.1:3005"]
API <--> CLI["Happy CLI"]
CLI <--> AGENT["Codex / Claude Code"]
server 不设开机自启是有意设计:用时 stack up,不用时 stack down;默认不监听 Wi-Fi/LAN。Happy 官方组件关系可参考 slopus/happy。
当前 preview APK 是本机专用构建。因为 server 使用 http://127.0.0.1:3005,App 的 Network Security Config 仅对白名单回环地址允许明文,其他 HTTP 地址仍默认拒绝。快速回归:
stack up
stack status
# App 点击“创建账户”或重新打开后
stack log
adb logcat -d | grep -iE 'CLEARTEXT|ERR_NETWORK'
成功标准不是“页面能启动”,而是 App 顶部显示“已连接”,且 stack log 中真实 API 请求返回 200。APK、签名文件、旧失败包和本机服务配置属于私有实验材料;公开报告只保留上游 commit、补丁、构建命令、产物 SHA-256 与脱敏证据。
24. AI 辅助安全研究的正确姿势
24.1 证据契约
给模型的输入应包含:
授权范围:自有 OnePlus 8T 与隔离 LAB-8T SSID
目标:解释 DNS 失败,不修改设备
环境:LineageOS 21 / Android 14 / CMFA / Kali PRoot
观察:原始命令与输出(已去除 token、IP、账号)
限制:只给诊断假设和只读验证命令
要求:区分事实、推断和未知;为每个假设给证伪条件
好问题:
下面是 ip route、resolv.conf、getent 和 curl 的脱敏输出。
请按链路/路由/DNS/TCP/TLS 分层,列出最多 3 个假设。
每个假设给一个只读验证步骤、预期结果和反例。
不要假设手机有 SIM,不要建议修改全局 CA 或 Magisk 模块。
坏问题:
网络坏了,给我一条命令修好。
24.2 模型输出要经过三道门
flowchart LR
M["模型建议"] --> A{"授权范围内?"}
A -- 否 --> STOP["停止"]
A -- 是 --> R{"可逆、单变量?"}
R -- 否 --> REDESIGN["缩小实验"]
R -- 是 --> E["执行并采集证据"]
E --> C{"结果支持假设?"}
C -- 否 --> H["更新假设"]
C -- 是 --> DOC["写入 Wiki"]
24.3 AI 适合做的五件事
- 把
logcat聚类成时间线; - 为 PCAP 写只读
tshark过滤器; - 把 Frida 观察脚本解释成调用链;
- 根据证据提出互斥假设;
- 把实验结果整理成 Wiki、复盘题和下一步。
不应交给 AI:授权判断、secret 管理、不可逆刷写、未知目标上的自动利用、对模型输出无审查地执行 root 命令。
25. 实操 9:让 AI 帮你分析,而不是替你猜
选择“实操 2:DNS 分层验证”的脱敏输出:
- 保存原始输出;
- 手工写一个初始假设;
- 让 OpenCode 给三个互斥假设;
- 只执行只读验证;
- 比较你和模型遗漏了什么;
- 将最终结论写进 Wiki,并链接原始实验记录。
评分标准不是“模型一次答对”,而是:错误假设能否被最小成本证伪。
第八部分:综合项目——从工具使用者到研究者
26. 九个递进项目
| 等级 | 项目 | 交付物 | 证明你掌握了什么 |
|---|---|---|---|
| L0 | 设备健康报告 | 命令、版本、哈希、截图 | 会复现环境 |
| L1 | DNS 故障树 | 四层验证与反例 | 会分层诊断 |
| L1 | 室内 RSSI 地图 | 5 点 × 3 次观测 | 理解信号统计 |
| L2 | 自有 PCAP 解剖 | 管理帧/EAPOL/时序笔记 | 理解 802.11 状态机 |
| L2 | 本机 socket 实验 | listen/connect/loopback 图 | 理解端口和暴露面 |
| L3 | Happy 授权错误复盘 | Activity + logcat 证据链 | 区分网络与应用故障 |
| L3 | 自有 APK 动态地图 | Activity、类、调用图 | 会用 Frida 观察 |
| L4 | Magisk 启动时间线 | 早期/完成状态对照 | 理解状态机和启动阶段 |
| L5 | AI 辅助研究报告 | 事实/推断/未知 + 可证伪实验 | 会把模型当研究助手 |
27. 12 周学习路线
第 1–2 周:系统与终端
- 完成章节 1–6;
- 每天只学一个 shell 概念:进程、FD、管道、权限、路径、环境变量;
- 能解释为什么 PRoot root 没有
CAP_NET_RAW。
第 3–4 周:TCP/IP 与无线物理
- 完成 RSSI 地图;
- 手画 DNS → TCP → TLS 时序;
- 用实验 AP 和外部采集端获得自己的 PCAP。
第 5–6 周:802.11 与防御分析
- 识别 Beacon、Association、EAPOL、Deauth;
- 对异常断连做时间线,不做主动干扰;
- 完成已知测试口令的离线验证实验。
第 7–8 周:Android 安全
- 从 Manifest 画组件与信任边界;
- 对 Happy preview 做只读动态观察;
- 给自己的 debug APK 配定向 CA,不碰全局系统 CA。
第 9–10 周:root、启动链与恢复
- 采一条完整重启时间线;
- 解释 Magisk safe mode 三类触发;
- 在不覆盖手机的前提下验证 age 备份可解密。
第 11–12 周:AI 研究闭环
- 用 OpenCode 分析一份脱敏日志和一份 PCAP 摘要;
- 故意给模型一个错误假设,设计反例;
- 将最终报告摄取到 Wiki,建立交叉引用。
28. “精通”不是工具数量
你达到进阶水平时,应当能回答:
nmap -sS为什么在某环境失败,而-sT可用?tun0、wlan0、loopback 分别在哪一层?- 为什么证书“被安装”不代表 App 会信任?
- 为什么 Frida 版本匹配是必要但不充分条件?
- 为什么启动完成后的计数器不能描述启动早期?
- 为什么模型能写出漂亮错误答案?
- 如何用最小、可逆、单变量实验区分两个假设?
如果只能回答“换个脚本试试”,还没学会;如果能从内核、协议、状态机和证据解释,就开始具备举一反三的能力。
第九部分:日常速查与故障树
29. 日常启动顺序
# Termux
selfcheck-lineage.sh
stack up # 需要 Happy 时才启动
oc --version
proot-distro login kali
结束:
stack down
su -c 'pkill -x frida-server' 2>/dev/null || true
30. 故障速查
| 现象 | 第一证据 | 不要先做 | 合理下一步 |
|---|---|---|---|
| Kali DNS 失败 | ip route、getent |
装 Magisk DNS 模块 | 查 CMFA/tun0/resolver |
| OpenCode 不能跑 | selfcheck-lineage.sh |
换 musl 包 | 查 glibc binary 与 PRoot |
tcpdump permission denied |
capability 错误 | 反复 sudo |
外部采集或 Android VPN capture |
| Objection 找不到 | /root/.local/bin |
全局 pip install |
export PATH=/root/.local/bin:$PATH |
| Frida 连不上 | server PID/端口/版本 | 开放到 0.0.0.0 |
对齐 17.17.0、loopback 检查 |
| Happy 提示 Play Store | 前台 Activity/logcat | 改 Wi-Fi/DNS | 使用自编 preview 包 |
| Happy 首页能开、创建账户失败 | logcat 是否含 CLEARTEXT |
全局允许 HTTP | 安装带 loopback NSC 的 preview 包 |
| Happy 页面连不上 | stack status/log |
监听整个 LAN | stack up,检查 127.0.0.1:3005 与 /v1/auth 状态码 |
| Magisk 模块全禁用 | 早期 DB/props/disable 文件 | patch 二进制 | 采启动时间线 |
| BadUSB 后 ADB 不回 | g1/g2 UDC 状态 | 并发重跑脚本 | 重启/物理重插并复核锁 |
31. 绝不复制回来的旧方案
- 不恢复
trustusercerts全局用户 CA 提权; - 不用 tmpfs 覆盖 Conscrypt APEX;
- 不为 OpenCode DNS 安装 Magisk mount;
- 不把 Frida 放在 world-readable
/data/local/tmp常驻; - 不把 API key 或代理 URL 写进 Wiki、截图、shell history;
- 不运行来源不明且未校验哈希的 wheel/APK/二进制;
- 不为了“好像能用”直接 patch Magisk payload。
官方资料与继续学习
- Magisk 官方文档与 Safe Mode FAQ
- PRoot-Distro 官方仓库
- Frida Android 官方教程与 Java bridge 示例
- Objection 官方 Wiki
- Android Network Security Configuration
- OpenCode 官方配置与 模型说明
- Happy 官方源码
- OWASP Mobile Application Security
- Wireshark Display Filters
项目配套入口
[!note] 工具参数会变,底层原理变化慢。升级前先读 release note、备份、记录版本和哈希;遇到差异时以
--help与官方文档为准,不以旧博客截图为准。
结业模板
每个项目用下面的格式收尾:
## 问题
## 授权与范围
## 环境和版本
## 原始观察
## 互斥假设
## 最小实验
## 证据与哈希
## 结论(事实 / 推断 / 未知)
## 反例
## 可迁移原则
## 下一步
当你能持续产出这种报告时,你就不再是“运行脚本的人”,而是在做真正的安全工程与研究。