天翼校园网APP逆向分析项目 - 基于unidbg模拟调用so库和Python实现自动登录
本项目是对海南电信天翼校园网认证客户端的逆向分析研究。客户端使用服务器下发的加密库对认证请求进行加密,本项目通过unidbg框架模拟调用加密库,以及Python脚本,实现了认证协议的完整流程。
CT-Young采用了独特的安全机制:
- 加密库由服务器动态下发,每个设备版本不同
- Algo-ID作为加密库标识,与设备绑定
- Code/DeCode函数偏移地址因版本不同而变化
- 需要在运行时dump解密后的so库才能分析
APK内置的 libzsm.so 并非标准ELF格式,头部为加密存储,运行时需要先解密此库,或通过Frida dump解密后的版本。
ct-young-reverse/ ├── ctyoung-analysis/ # 逆向分析资料 │ ├── CT-Young.py # Python实现登录脚本 │ ├── dump/ # dump出的dex文件 │ ├── dec.c # IDA反编译-解密函数伪代码 │ ├── enc.c # IDA反编译-加密函数伪代码 │ └── source-*.dex/jar # 反编译产物 │ ├── unidbg(模拟调用so库加解密)/ │ ├── unidbg-0.9.4/ # unidbg框架源码 │ └── unidbg-boot-server/ # Spring Boot服务版 │ └── src/main/java/com/anjia/unidbgserver/ │ ├── service/ │ │ ├── cndataService.java # 核心加密调用服务 │ │ ├── cndataServiceWorker.java # 多线程批量登录 │ │ ├── HttpUtils.java # HTTP请求工具 │ │ └── UnidbgPointer.java # 指针操作工具 │ ├── config/ │ │ └── UnidbgProperties.java # 配置类 │ └── utils/ │ └── PrintUtils.java # 打印工具 │ ├── HaiNanCV1.0.2028.20071001.apk # 原始APK └── README.md # 项目说明
Python版本的登录脚本,使用requests库和ddddocr验证码识别:
`python import requests import ddddocr import rsa
urls = { 'login': 'http://202.100.204.142:10001/xyportal/ajax/login', ... }
ocr = ddddocr.DdddOcr()
`
`java // 加载dump出来的加密库 DalvikModule dm = vm.loadLibrary(new File("dump7.so"), true); module = dm.getModule();
// Hook关键函数绕过检查 HookZz hook = HookZz.getInstance(emulator); hook.replace(module.base + 0x2CEC + 1, new ReplaceCallback() { @Override public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) { emulator.getBackend().reg_write(Unicorn.UC_ARM_REG_R0, codebyte.getPointer().peer); return HookStatus.RET(emulator, context.getLR()); } });
// 调用加密函数 Number[] code = module.callFunction(emulator, "Code", codebyte.getPointer()); String encrypted = new UnidbgPointer(emulator, code[0].intValue(), 4).getString(0);
// 调用解密函数 Number[] decode = module.callFunction(emulator, "DeCode", codebyte.getPointer()); String decrypted = new UnidbgPointer(emulator, decode[0].intValue(), 4).getString(0); `
认证请求使用XML格式,通过加密库加密后发送:
`xml
CCTP/android3/2028 00000000-0000-0000-0000-000000000005 172.24.72.4 2021-11-24 16:21:16 `HTTP请求头:
User-Agent: CCTP/android3/2028 Algo-ID: 15838E04-05CF-4627-AAAB-8B58037E9A79 CDC-Checksum: {MD5(加密数据)} Client-ID: {客户端标识} Content-Type: application/x-www-form-urlencoded CDC-SchoolId: 10 CDC-Domain: ctyoung CDC-Area: hn
| 接口 | 功能 | 说明 |
|---|---|---|
| /ticket.cgi | 获取登录凭证 | 返回ticket用于后续认证 |
| /auth.cgi | 用户认证 | 用户名密码登录 |
| /query.cgi | 查询在线状态 | 检查当前是否在线 |
| /term.cgi | 下线 | 注销登录 |
`Bash pip install requests ddddocr rsa
python CT-Young.py `
- Java 8 (JDK 1.8)
- Maven 3.5+
- unidbg框架 (开源项目,需单独引入)
`Bash
mvn package -DskipTests
java -jar target/unidbg-boot-server-0.0.1-SNAPSHOT.jar `
加密函数 Code 和解密函数 DeCode 的伪代码分析详见 ctyoung-analysis/enc.c 和 ctyoung-analysis/dec.c。
- 加密库使用自定义加密算法(非标准AES/DES)
- 包含时间戳校验(字段)
- 使用MD5作为请求校验(CDC-Checksum)
在分析过程中,曾尝试过两种native模拟方案:
最初尝试使用 Python 框架 AndroidNativeEmu 进行分析,但发现该框架存在以下问题:
- 需要手动实现大量 JNI 环境补丁代码
- 不支持多线程并发调用
- 复杂加密库运行不稳定
- 性能较差,不适合批量登录场景
最终采用 Java 版的 unidbg 框架实现完整方案:
- JNI环境自动反射
- 支持 Worker Pool 多线程
- 可与 Spring Boot 集成
本项目展示了:
- 逆向分析流程:从APK解包 → so库分析 → 加密协议破解
- 技术选型:Python框架尝试 → Java框架最终实现
- unidbg应用:使用unidbg模拟调用Android Native库
- 动态下发机制:分析服务器动态下发加密库的安全设计
- Hook技术:使用HookZz绕过so库中的检查函数
- 多线程并发:Spring Boot Worker Pool实现批量登录
- Python实现:使用ddddocr验证码识别和RSA加密
本项目仅用于技术研究和学习交流,不得用于:
- 非法获取网络资源
- 破坏网络服务正常运行
- 任何商业用途
使用本项目代码需遵守当地法律法规。
- unidbg - Android Native模拟框架 (Java)
- unidbg-boot-server - Spring Boot集成方案
- AndroidNativeEmu - Android Native模拟框架 (Python,尝试过但未采用)
MIT License