⚠️ 免责声明:本文仅供安全研究与技术学习交流,严禁用于任何非法目的!
🎯 写在前面
你是否经历过这样的场景?
- 热门演唱会开票,手速快到起飞,结果"已售罄"
- 凌晨定闹钟抢票,刷新无数次,永远"系统繁忙"
- 明明比别人早点进去,订单却始终提交失败
而另一边,某些人轻松拿下多张票,甚至还能"加价转让"...
背后的技术较量,远比你想象的复杂。
📱 为什么必须分析APP?
⚡ 关键信息 :2024年起,某麦仅支持APP端抢票,H5和小程序已无法参与热门演出抢购!
这意味着:
-
❌ 网页端脚本完全失效
-
❌ 传统HTTP请求模拟无法使用
-
✅ 必须深入APP底层,分析native代码和加密逻辑
📦 本文技术栈一览
├── 📱 移动端:APP抓包 → 证书绕过 → 协议分析
├── 🔍 逆向层:APK脱壳 → SO分析 → 签名还原
├── 🛡️ 防护层:反调试 → 完整性校验 → 环境检测
├── 🎭 风控层:设备指纹 → 行为分析 → 验证码
└── ⚡ 实战层:Frida注入 → 自动化框架 → 多设备协同
💡 阅读建议 :本文干货较多,建议收藏后反复阅读。有兴趣的可以后台交流。
📊 技术难度评估
在开始之前,先看看我们要面对的"敌人"有多强:
| 防护维度 | 技术手段 | 难度等级 | 突破关键 |
|---|---|---|---|
| 通信加密 | HTTPS + SSL Pinning | ⭐⭐⭐ | Frida SSL Bypass |
| 签名算法 | HMAC + 动态密钥(SO层) | ⭐⭐⭐⭐ | IDA逆向 + 算法还原 |
| 设备指纹 | 多维度采集 + 环境检测 | ⭐⭐⭐⭐ | 指纹伪造 + Hook |
| 行为风控 | 轨迹分析 + 频率限制 | ⭐⭐⭐⭐⭐ | 行为模拟 + 分布式 |
| SO保护 | VMP + 反调试 + 完整性 | ⭐⭐⭐⭐⭐ | 动态调试 + Patch |
一、移动端APP抓包与协议分析
1.1 为什么APP抓包这么难?
与传统Web抓包不同,APP抓包面临三大核心挑战:
┌─────────────────────────────────────────────────────────────┐
│ 📱 APP抓包难点 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 挑战1:SSL Certificate Pinning(证书锁定) │
│ ├── APP内置服务器证书指纹 │
│ ├── 运行时校验证书是否匹配 │
│ └── 不匹配则拒绝连接 → 代理抓包失败 │
│ │
│ 挑战2:双向认证(Mutual TLS) │
│ ├── 客户端也需要提供证书 │
│ ├── 证书加密存储在APP内 │
│ └── 需要提取客户端证书才能解密 │
│ │
│ 挑战3:非HTTP协议 │
│ ├── 部分接口使用自定义TCP协议 │
│ ├── 数据经过私有加密算法处理 │
│ └── 普通代理工具无法解析 │
│ │
└─────────────────────────────────────────────────────────────┘
1.2 APP抓包环境搭建
硬件与软件准备
| 类型 | 推荐配置 | 说明 |
|---|---|---|
| 测试手机 | Root过的Android 8-12 | 推荐Pixel系列或小米 |
| 抓包工具 | Charles / mitmproxy | 配置系统级代理 |
| 注入框架 | Frida 16.x | 用于绕过证书校验 |
| ADB工具 | 最新版Platform Tools | 设备调试连接 |
抓包流程图
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 1.Root设备│────▶│2.安装证书 │────▶│3.配置代理 │────▶│4.启动Frida│
└──────────┘ └──────────┘ └──────────┘ └──────────┘
│
▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 8.协议分析│◀────│7.获取明文 │◀────│6.SSL绕过 │◀────│5.注入APP │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
1.3 SSL Pinning绕过原理
某麦APP使用了OkHttp3的CertificatePinner进行证书校验,绕过思路如下:
绕过原理示意图:
正常流程:
┌─────────┐ 请求 ┌─────────┐ 校验证书 ┌─────────┐
│ APP │──────────▶│ OkHttp3 │──────────────▶│ Pinner │
└─────────┘ └─────────┘ └─────────┘
│
❌ 证书不匹配
│
▼
连接被拒绝
Hook绕过后:
┌─────────┐ 请求 ┌─────────┐ Hook拦截 ┌─────────┐
│ APP │──────────▶│ OkHttp3 │──────────────▶│ Frida │
└─────────┘ └─────────┘ └─────────┘
│
✅ 直接返回通过
│
▼
正常建立连接
核心Hook点:
javax.net.ssl.X509TrustManager- 信任所有证书okhttp3.CertificatePinner.check()- 跳过证书指纹校验SSLContext.init()- 使用自定义TrustManager
📌 完整绕过脚本见文末资料获取
1.4 核心API协议解析
成功抓包后,可以梳理出某麦APP的完整业务流程:
风控系统 服务端 APP 用户 风控系统 服务端 APP 用户 携带签名、时间戳、风控Token alt [风控通过] [风控拦截] 1. 打开演出详情页 2. 获取演出信息 (itemDetail) 返回场次、票价、库存 3. 点击"立即购买" 4. 本地生成设备指纹 5. 提交指纹获取风控Token 返回Token + 风控策略 6. SO层生成请求签名 7. 创建订单 (order.build) 8. 验证请求合法性 风控结果 9a. 订单创建成功 10. 提交支付 (order.submit) 9b. 需要验证码/账号限制
关键接口说明
| 接口 | 功能 | 关键参数 | 风险点 |
|---|---|---|---|
itemDetail |
获取演出详情 | itemId, performId | 高频访问触发风控 |
order.build |
创建订单 | X-Sign, X-T, skuId | 签名校验最严格 |
order.submit |
提交订单 | orderId, token | 需要先build成功 |
mtop.trade.* |
交易相关 | 多参数签名 | 全链路风控 |
请求头分析
http
# 某麦APP请求头结构(已脱敏)
GET /gw/mtop.alibaba.xxx.detail.getdetail/1.2/
Host: mtop.xxx.cn
User-Agent: MOUMAIAPP/8.x.x (Android; ...)
# 🔑 关键签名字段
X-Sign: a1b2c3d4e5f6... ← SO层native方法生成
X-T: 1699123456789 ← 毫秒时间戳
X-App-Key: 12574478 ← 应用标识
X-Mini-Wua: HHnB... ← 设备指纹(加密)
X-Utdid: XYZ... ← 阿里设备ID
🔑 核心发现 :
X-Sign签名是突破的关键,它由libmtguard.so中的native方法生成,无法通过简单的Java Hook获取。
二、签名算法逆向分析
2.1 签名生成流程
通过动态调试,还原出签名的完整生成流程:
┌─────────────────────────────────────────────────────────────┐
│ 🔐 签名生成流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Step 1: 收集输入参数 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ AppKey + Token + Timestamp + Data + DeviceId │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Step 2: 参数预处理 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 按字典序排序 → URL编码 → 拼接成字符串 │ │
│ │ 格式: key1=v1&key2=v2&key3=v3... │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Step 3: 获取动态密钥(关键!) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ BaseSecret (硬编码) + ServerToken (每小时更新) │ │
│ │ 通过特定算法组合生成最终密钥 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Step 4: HMAC-SHA256加密 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ HMAC(密钥, 待签名字符串) → 32字节摘要 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Step 5: 字节混淆处理 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ XOR运算 → 字节重排 → Base64编码 → 最终签名 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
2.2 SO库结构分析
签名核心逻辑封装在native层,需要逆向分析以下SO库:
📁 lib/arm64-v8a/
│
├── 🔴 libmtguard.so ← 核心签名库(最重要)
│ ├── Java_com_..._generateSign() # JNI签名入口
│ ├── internal_sign() # 内部签名函数
│ ├── get_dynamic_key() # 动态密钥获取
│ └── verify_environment() # 环境检测
│
├── 🟡 libsgmain.so ← 安全SDK
│ ├── getDeviceToken() # 设备指纹
│ └── checkIntegrity() # 完整性校验
│
├── 🟡 libsgsecuritybody.so ← 人机验证
│ └── getCaptchaToken()
│
└── 🔴 libvmp.so ← 代码虚拟化保护
└── (VMP加壳保护,需先脱壳分析)
2.3 分析思路
分析流程:
┌──────────────┐
│ 1. 静态分析 │
│ (IDA Pro) │
└──────┬───────┘
│
▼
┌──────────────┐ ┌──────────────┐
│ 2. 定位JNI │────▶│ 3. 分析调用链 │
│ 入口函数 │ │ 追踪数据流 │
└──────────────┘ └──────┬───────┘
│
┌────────────────────┘
│
▼
┌──────────────┐ ┌──────────────┐
│ 4. 动态调试 │────▶│ 5. Hook验证 │
│ (Frida) │ │ 确认算法正确 │
└──────────────┘ └──────┬───────┘
│
▼
┌──────────────┐
│ 6. 算法还原 │
│ Python实现 │
└──────────────┘
🎓 进阶提示 :完整的SO逆向需要掌握ARM汇编、IDA Pro、Frida动态调试等技能。详细教程见文末资料。
三、SO层Hook与反调试绕过
3.1 Frida注入架构
┌─────────────────────────────────────────────────────────────┐
│ 📱 Frida注入架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ PC端 Android设备 │
│ ┌──────────┐ ┌──────────────────────┐ │
│ │ Python │ USB/WiFi │ 目标APP │ │
│ │ 控制脚本 │◀──────────────▶│ ┌──────────────────┐ │ │
│ └──────────┘ │ │ Frida Agent │ │ │
│ │ │ │ (注入的JS代码) │ │ │
│ │ │ └────────┬─────────┘ │ │
│ ▼ │ │ │ │
│ ┌──────────┐ │ ▼ │ │
│ │ 数据 │ │ ┌──────────────────┐ │ │
│ │ 分析 │ │ │ Java层 Hook │ │ │
│ │ 结果 │ │ │ Native层 Hook │ │ │
│ └──────────┘ │ └──────────────────┘ │ │
│ └──────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
3.2 核心Hook点
| Hook目标 | 层级 | 作用 | 难度 |
|---|---|---|---|
| SSL Pinning | Java | 绕过证书校验 | ⭐⭐ |
| generateSign | Native | 获取签名结果 | ⭐⭐⭐ |
| getDeviceId | Java | 伪造设备ID | ⭐⭐ |
| ptrace | Native | 反调试绕过 | ⭐⭐⭐⭐ |
| verifyEnv | Native | 环境检测绕过 | ⭐⭐⭐⭐ |
3.3 反调试检测与绕过
某麦APP使用了多层反调试机制:
┌─────────────────────────────────────────────────────────────┐
│ 🛡️ 反调试检测机制 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 检测层1:Java层 │
│ ├── Debug.isDebuggerConnected() │
│ ├── ApplicationInfo.flags & FLAG_DEBUGGABLE │
│ └── 检测调试器进程名 │
│ │
│ 检测层2:Native层 │
│ ├── ptrace(PTRACE_TRACEME) 自我附加 │
│ ├── 读取 /proc/self/status 检查 TracerPid │
│ ├── 检测 /proc/self/maps 中的frida特征 │
│ └── 时间差检测(断点会导致执行变慢) │
│ │
│ 检测层3:环境检测 │
│ ├── 检测Root特征文件 (/su, /magisk等) │
│ ├── 检测Xposed框架 │
│ ├── 检测模拟器特征 │
│ └── 检测Hook框架 │
│ │
└─────────────────────────────────────────────────────────────┘
绕过策略:
| 检测方式 | 绕过方法 |
|---|---|
| isDebuggerConnected | Hook返回false |
| ptrace检测 | 提前Hook ptrace函数 |
| TracerPid检测 | Hook fopen/fgets修改返回值 |
| frida特征检测 | 使用魔改版frida或hluda |
| Root检测 | MagiskHide隐藏Root |
| 时间差检测 | Hook时间函数返回正常值 |
四、自动化抢票框架设计
4.1 整体架构
┌─────────────────────────────────────────────────────────────────┐
│ 🎫 抢票系统架构 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 控制中心 │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ 任务调度 │ │ 监控告警 │ │ 日志收集 │ │ │
│ │ │ (Redis) │ │(Grafana) │ │ (ELK) │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────┼───────────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 设备节点1 │ │ 设备节点2 │ │ 设备节点N │ │
│ │ ┌────────┐ │ │ ┌────────┐ │ │ ┌────────┐ │ │
│ │ │Android │ │ │ │Android │ │ │ │Android │ │ │
│ │ │ + Frida│ │ │ │ + Frida│ │ │ │ + Frida│ │ │
│ │ └────────┘ │ │ └────────┘ │ │ └────────┘ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │ │
│ └───────────────┼───────────────┘ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ 某麦 │ │
│ │ (风控 + 业务) │ │
│ └──────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
4.2 核心流程
抢票执行流程:
┌────────────────┐
│ 1. 初始化 │
│ 连接设备 │
│ 注入Frida │
└───────┬────────┘
│
▼
┌────────────────┐ ┌────────────────┐
│ 2. 监控开票 │────▶│ 3. 触发抢票 │
│ 轮询库存状态 │ │ 检测到开票 │
└────────────────┘ └───────┬────────┘
│
┌──────────────────────┘
│
▼
┌────────────────┐ ┌────────────────┐ ┌────────────────┐
│ 4. 获取签名 │────▶│ 5. 提交订单 │────▶│ 6. 处理结果 │
│ 通过Hook获取 │ │ 并发发送请求 │ │ 成功/失败/重试 │
└────────────────┘ └────────────────┘ └───────┬────────┘
│
┌────────────────────┬────────────────────────┘
│ │ │
▼ ▼ ▼
┌────────────────┐ ┌────────────────┐ ┌────────────────┐
│ ✅ 抢票成功 │ │ ⚠️ 需要验证码 │ │ ❌ 已售罄 │
│ 进入支付流程 │ │ 自动识别处理 │ │ 停止重试 │
└────────────────┘ └────────────────┘ └────────────────┘
4.3 关键技术点
| 模块 | 技术要点 | 优化方向 |
|---|---|---|
| 设备管理 | ADB批量控制、Frida多设备注入 | 设备池化、自动重连 |
| 签名获取 | Hook native层、结果缓存 | 预签名、异步获取 |
| 请求发送 | 异步并发、连接复用 | 降低延迟、提高吞吐 |
| 风控对抗 | 设备指纹轮换、行为模拟 | IP池、账号池 |
| 验证码处理 | OCR识别、滑块轨迹生成 | 深度学习模型 |
4.4 效果对比
| 方案 | 成功率 | 响应速度 | 稳定性 | 成本 |
|---|---|---|---|---|
| 👆 手动操作 | 2-5% | 2-3秒 | 高 | 低 |
| 🖥️ 普通自动化 | 10-15% | 1-1.5秒 | 中 | 中 |
| 📱 Frida Hook | 30-40% | 0.5-0.8秒 | 中 | 高 |
| 📱📱 多设备协同 | 50-60% | 0.3-0.5秒 | 低 | 很高 |
📌 说明:以上数据基于实验环境测试,实际效果受网络、风控策略等多种因素影响。
五、风控对抗策略
5.1 设备指纹伪造
设备指纹组成:
┌─────────────────────────────────────────────────────────────┐
│ 📱 设备指纹维度 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 硬件层 │
│ ├── IMEI / MEID(需Root获取) │
│ ├── MAC地址 │
│ ├── 蓝牙地址 │
│ └── CPU/GPU型号、屏幕分辨率 │
│ │
│ 系统层 │
│ ├── Android ID │
│ ├── Build.* 系列属性 │
│ ├── 系统版本、内核版本 │
│ └── 已安装应用列表 │
│ │
│ 应用层 │
│ ├── UTDID(阿里设备ID) │
│ ├── 应用私有存储的唯一ID │
│ └── 运行时生成的特征值 │
│ │
│ 行为层 │
│ ├── 触摸轨迹特征 │
│ ├── 传感器数据(加速度、陀螺仪) │
│ └── 操作时间间隔 │
│ │
└─────────────────────────────────────────────────────────────┘
伪造策略:Hook关键API返回伪造值,保持各维度数据一致性。
5.2 行为模拟原理
人类操作 vs 机器操作的关键差异:
| 特征 | 人类操作 | 机器操作 |
|---|---|---|
| 点击间隔 | 200-800ms,正态分布 | 固定间隔或完全随机 |
| 滑动轨迹 | 贝塞尔曲线,有加减速 | 直线或简单曲线 |
| 操作位置 | 有一定偏移,不精确 | 精确到像素 |
| 思考时间 | 有停顿和犹豫 | 无停顿,连续操作 |
模拟方案:
- 使用正态分布生成随机延迟
- 采用贝塞尔曲线生成滑动轨迹
- 添加微小抖动模拟手指不稳
- 引入随机停顿模拟思考时间
5.3 验证码处理
验证码处理流程:
┌────────────────┐
│ 检测验证码类型 │
└───────┬────────┘
│
┌────┴────┬────────────┐
│ │ │
▼ ▼ ▼
┌──────┐ ┌──────┐ ┌──────────┐
│ 图形 │ │ 滑块 │ │ 点选/拼图 │
│ 验证码│ │ 验证码│ │ 验证码 │
└──┬───┘ └──┬───┘ └────┬─────┘
│ │ │
▼ ▼ ▼
┌──────┐ ┌──────┐ ┌──────────┐
│ CNN │ │ 缺口 │ │ 目标 │
│ 识别 │ │ 检测 │ │ 检测 │
└──┬───┘ └──┬───┘ └────┬─────┘
│ │ │
▼ ▼ ▼
┌──────┐ ┌──────┐ ┌──────────┐
│ 输出 │ │ 轨迹 │ │ 坐标 │
│ 字符 │ │ 生成 │ │ 序列 │
└──────┘ └──────┘ └──────────┘
📢 写在最后
🔐 再次强调:本文仅供技术学习交流,请勿用于任何非法目的!
作者寄语:技术无罪,但使用技术的人需要有底线。希望每一位读者都能将所学知识用于正途,共同维护网络安全生态。