Android VPN 应用逆向实战:从APK到节点配置提取
本文记录了一次对某VPN应用的完整逆向分析过程,从静态分析到实机动态调试,最终成功提取全部节点配置。
0. 前置条件
- 真机: 已Root (Magisk)
- ADB: 已配置好环境变量
- 基本工具: strings、sqlite3、unzip
1. 静态分析:解包APK
APK本质是一个ZIP文件,直接解压查看内部结构:
bash
unzip -o -q base.apk -d apk_extracted
解压后目录结构:
code
apk_extracted/
├── AndroidManifest.xml # 二进制格式,需要工具解析
├── classes.dex # 主程序代码 (3.5MB)
├── lib/arm64-v8a/
│ ├── libbox.so # sing-box 核心库 (44MB)
│ └── ...
├── assets/
│ ├── dashboard.html # H5前端页面
│ ├── demo_nodes.json # 节点配置模板
│ ├── h5/ # 前端资源
│ └── ...
└── resources.arsc # 资源表
1.1 分析前端代码
这是一个混合开发应用,前端使用H5 + WebView。查看JavaScript文件可以了解业务逻辑:
bash
find apk_extracted/assets/h5 -name "*.js"
从 dashboard.js 中可以看到:
javascript
// 节点获取通过原生桥接
window.AndroidBridge.fetchNodesFromApi('handleApiNodes');
节点数据不在前端硬编码,而是通过原生层API动态获取。
1.2 提取API地址
从 classes.dex 中提取字符串:
bash
strings apk_extracted/classes.dex | grep -E "https?://[a-zA-Z0-9./:-]+"
找到关键信息:
code
https://appshouye.com:8888 # API基础地址
/api/v1/auth/login # 登录接口
/api/v1/auth/register # 注册接口
/api/v1/user/getSubscribe # 订阅信息接口
1.3 提取硬编码节点
在 classes.dex 中发现一个硬编码的备用节点配置:
bash
strings apk_extracted/classes.dex | grep -E "\"server\"|\"uuid\"|\"server_name\""
找到一个VLESS节点,但这是降级用的备用节点,完整节点列表需要登录后从API获取。
1.4 确定技术栈
从分析中得出:
- 开发语言: Kotlin
- VPN核心: sing-box (libbox.so)
- 前端: H5 + WebView
- 包名:
com.ailian.accelerator
2. 实机安装与登录
2.1 安装APK
bash
adb devices # 确认设备连接
adb install base.apk # 安装应用
2.2 启动应用
bash
adb shell monkey -p com.ailian.accelerator -c android.intent.category.LAUNCHER 1
2.3 登录账号
在手机上完成登录操作。登录后,应用会从API拉取节点配置。
2.4 观察日志
bash
adb logcat | grep -i "NodeDataManager\|DashboardFragment"
登录成功后日志显示:
code
NodeDataManager: [新方式] 没有 token,无法获取订阅配置 # 登录前
DashboardFragment: 返回API节点: 83 个 # 登录后
3. Root权限读取数据
3.1 确认Root权限
bash
adb shell "su -c 'id'"
# 输出: uid=0(root) gid=0(root) groups=0(root) context=u:r:magisk:s0
3.2 查找数据库文件
bash
adb shell "su -c 'ls -la /data/user/0/com.ailian.accelerator/databases/'"
发现关键数据库:
code
profiles.db # VPN配置数据库
settings.db # 应用设置数据库
3.3 分析数据库结构
bash
adb shell "su -c 'sqlite3 /data/user/0/com.ailian.accelerator/databases/profiles.db \".tables\"'"
# 输出: android_metadata profiles room_master_table
adb shell "su -c 'sqlite3 /data/user/0/com.ailian.accelerator/databases/profiles.db \".schema profiles\"'"
# 输出: CREATE TABLE `profiles` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
# `userOrder` INTEGER NOT NULL, `name` TEXT NOT NULL, `typed` BLOB NOT NULL);
3.4 查询配置数据
bash
adb shell "su -c 'sqlite3 /data/user/0/com.ailian.accelerator/databases/profiles.db \"SELECT id, userOrder, name FROM profiles\"'"
输出:
code
1|0|全局模式
2|1|API配置
3.5 解析BLOB字段
typed 字段存储的是文件路径(UTF-16LE编码):
bash
adb shell "su -c 'sqlite3 /data/user/0/com.ailian.accelerator/databases/profiles.db \"SELECT hex(typed) FROM profiles WHERE id=2\"'"
将hex解码后得到文件路径:
code
/data/user/0/com.ailian.accelerator/files/configs/config_2.json
3.6 提取完整配置
bash
adb shell "su -c 'cat /data/user/0/com.ailian.accelerator/files/configs/config_2.json'" > nodes_config.json
这就是完整的 sing-box 配置文件,包含所有节点信息!
4. 配置文件分析
提取到的配置是一个标准的 sing-box JSON 配置,主要结构:
json
{
"dns": { ... }, // DNS配置
"inbounds": [ ... ], // 入站代理 (TUN/SOCKS/混合)
"outbounds": [ ... ], // 出站节点列表 ← 这是我们要的
"route": { ... } // 路由规则
}
节点统计
| 地区 | 数量 | 协议 | 服务器 |
|---|---|---|---|
| 香港 | 22 | VLESS+WS / AnyTLS | Cloudflare CDN / 自建 |
| 台湾 | 10 | AnyTLS | 自建服务器 |
| 新加坡 | 10 | AnyTLS | 自建服务器 |
| 日本 | 10 | AnyTLS | 自建服务器 |
| 美国 | 30 | AnyTLS | 自建服务器 |
协议说明
- VLESS + WebSocket + TLS: 通过Cloudflare CDN中转,伪装性好
- AnyTLS: sing-box独有的TLS代理协议,性能更优
5. 总结
整个逆向流程:
code
APK解包 → 静态分析(找API地址)
↓
安装到真机 → 登录账号(获取节点配置)
↓
Root权限 → 读取数据库 → 找到配置文件路径
↓
直接读取JSON配置文件 → 获得全部节点
关键发现:
- 应用使用 sing-box 作为VPN核心引擎
- 节点配置存储在本地数据库关联的JSON文件中
- 登录后,API返回的完整配置会被缓存到本地
- 有了Root权限,可以直接读取这些缓存文件
免责声明:本文仅用于安全研究和学习目的,请勿用于非法用途。
目录
作者
A
AG666
全栈开发者