一、网络协议逆向:从抓包到模拟请求
各位同学好。今天我们来聊聊 Android 网络协议逆向。说实话,这块内容是我在移动安全领域花时间最多、踩坑也最多的方向之一。你想想看,现在哪个 App 不联网?几乎所有的核心业务逻辑都跑在网络上。所以,搞懂网络协议逆向,就等于拿到了 App 的命门。
这一章,我会带你走完一条完整的链路:从配置抓包工具开始,到绕过 HTTPS 证书绑定,再到分析协议内容,最后逆向一个真实的加密 API 并成功模拟请求。嗯,内容不少,但每一步我都会结合我自己的实战经历来讲。
核心目标:掌握 Android 网络协议逆向的完整方法论,能够独立分析并模拟任意 App 的加密网络接口。
抓包工具配置:三剑客的选择
工欲善其事,必先利其器。抓包工具我常用的有三款:Charles、Burp Suite、Fiddler。各有千秋,我分别说说我的使用习惯。
Charles:我最常用的代理工具
Charles 是我个人最推荐的抓包工具,尤其适合 Android 逆向。为什么?因为它对 SSL 的支持最友好,界面也直观。
配置步骤:
- PC 端开启 SSL Proxying,添加需要抓包的域名
- 手机设置代理:IP 填 PC 的局域网地址,端口默认 8888
- 访问 chls.pro/ssl 下载并安装 CA 证书
- Android 7.0+ 需要将证书安装到系统证书目录(需 root)
我的经验:Android 7.0 之后,用户安装的证书默认不被信任。我曾经在一个项目里折腾了两天才发现是这个问题。解决办法是把证书 push 到 /system/etc/security/cacerts/ 目录下,记得格式要改成 hash.0 的形式。
Burp Suite:适合协议深度分析
Burp Suite 我主要用于需要修改请求包、重放攻击的场景。它的 Repeater 模块和 Intruder 模块在协议逆向中非常实用。
配置要点:
- Proxy 监听端口建议用 8080
- 导入 CA 证书方式与 Charles 类似
- 配合 Xposed 模块 JustTrustMe 可绕过部分 SSL Pinning
Fiddler:Windows 用户的备选
说实话,Fiddler 在 Android 逆向中我用得不多。但它有一个优势:对 Windows 系统下的抓包支持很好,尤其是配合 .NET 开发的 App。
| 工具 | 优点 | 缺点 | 推荐场景 |
|---|---|---|---|
| Charles | SSL 支持好,界面友好 | 收费,功能有限 | 日常抓包分析 |
| Burp Suite | 功能强大,可重放攻击 | 配置稍复杂 | 协议深度分析 |
| Fiddler | 免费,Windows 友好 | Android 支持一般 | Windows 环境 |
HTTPS 证书绑定绕过:SSL Pinning Bypass
配置好代理后,你可能会发现:咦,怎么抓不到包?或者全是乱码?这大概率是 App 做了 SSL Pinning(证书绑定)。说白了,就是 App 只信任它自己内置的证书,不信任你安装的代理证书。
为什么会这样?因为很多 App 为了防止中间人攻击,会在代码里固定校验服务端证书的指纹或公钥。你代理工具提供的证书,自然就被拒绝了。
绕过方法一:Hook 框架
我个人最常用的方法是使用 Xposed 或 Frida 来 Hook 证书校验函数。以 Frida 为例:
// Frida 脚本:绕过 SSL Pinning
Java.perform(function() {
var TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');
TrustManagerImpl.checkTrustedRecursive.implementation = function() {
return true;
};
var SSLSocketFactory = Java.use('javax.net.ssl.SSLSocketFactory');
SSLSocketFactory.createSocket.overload('java.net.Socket', 'java.lang.String',
'int', 'boolean').implementation = function() {
console.log('Bypassing SSL Pinning...');
return this.createSocket.apply(this, arguments);
};
});
注意:有些 App 会检测 Frida 或 Xposed 的运行状态。我曾经遇到过一款金融 App,检测到 Hook 环境后直接闪退。这种情况下,需要先绕过反调试,或者使用定制化的 Frida Gadget。
绕过方法二:JustTrustMe 模块
如果你不想写代码,可以直接用 Xposed 模块 JustTrustMe。它自动 Hook 了常见的证书校验逻辑,一键绕过。但缺点也很明显:容易被检测,且无法定制化。
绕过方法三:重打包修改
这是最彻底的方法。直接反编译 App,找到证书校验的代码,修改 smali 指令让它永远返回 true。嗯,这个方法工作量最大,但最稳定。我在逆向某社交 App 时就用过这招,效果很好。
HTTP/HTTPS 协议分析:从请求到响应
抓包工具配置好、SSL Pinning 绕过之后,我们就能看到明文请求了。但看到不等于看懂。你需要理解 HTTP 协议的结构。
一个典型的 HTTP 请求包含:
- 请求行:方法(GET/POST)、URL、协议版本
- 请求头:User-Agent、Content-Type、Cookie、Authorization 等
- 请求体:表单数据、JSON、二进制数据等
响应结构类似:
- 状态行:状态码(200、401、500 等)
- 响应头:Set-Cookie、Content-Type 等
- 响应体:返回的数据
我个人习惯先看请求头里的 User-Agent,它能告诉我 App 的版本和平台信息。再看 Authorization 字段,这里往往藏着 Token 或签名信息。
Protobuf/自定义协议逆向
现在很多 App 不再使用纯 JSON 或 XML 传输数据,而是用 Protobuf 或自定义的二进制协议。为什么?因为体积小、解析快、而且更难被直接看懂。
Protobuf 逆向
Protobuf 的数据是二进制的,但它的结构是有规律的。如果你能拿到 .proto 文件,直接反序列化即可。但大多数情况下,你需要自己逆向出协议结构。
我的方法:
- 抓取多组请求数据,对比二进制差异
- 使用 protobuf-inspector 工具分析字段编号和类型
- 结合反编译的代码,找到对应的 proto 定义
# 使用 protobuf-inspector 分析
pip install protobuf-inspector
protobuf-inspector -i captured_data.bin
自定义协议逆向
自定义协议就更麻烦了。我遇到过用自定义加密 + 自定义序列化的 App。这种情况下,只能硬着头皮逆向 native 层代码。
步骤:
- 用 IDA Pro 或 Ghidra 分析 so 文件
- 找到加密函数和序列化函数
- 用 Frida Hook 这些函数,打印输入输出
- 根据 Hook 结果还原协议格式
避坑指南:我曾经逆向一个自定义协议时,发现数据里有个 4 字节的魔数,以为是固定值。结果换了台手机,魔数变了。后来才发现那是设备 ID 的哈希值。所以,不要轻易假设任何字段是固定的。
实战:逆向一个加密 API 接口并模拟请求
理论说完了,我们来动手。假设我们要逆向一个 App 的登录接口,它使用了自定义加密。
第一步:抓包分析
用 Charles 抓取登录请求,发现请求体是一串 Base64 编码的数据。解码后是乱码,说明是加密的。
第二步:定位加密逻辑
反编译 APK,搜索 "encrypt"、"sign"、"aes" 等关键词。找到加密函数所在的类。
// 反编译后的加密代码(简化)
public class CryptoUtil {
public static String encrypt(String data) {
// AES 加密,密钥从 native 层获取
byte[] key = getKeyFromNative();
byte[] iv = "1234567890abcdef".getBytes();
// ... 加密逻辑
return Base64.encodeToString(encrypted);
}
private static native byte[] getKeyFromNative();
}
第三步:Hook 获取密钥
用 Frida Hook getKeyFromNative 方法,获取密钥。
// Frida Hook 获取密钥
Java.perform(function() {
var CryptoUtil = Java.use('com.example.CryptoUtil');
CryptoUtil.getKeyFromNative.implementation = function() {
var key = this.getKeyFromNative();
console.log('Key:', bytesToHex(key));
return key;
};
});
第四步:模拟请求
拿到密钥后,用 Python 实现加密逻辑,然后发送模拟请求。
import requests
import base64
from Crypto.Cipher import AES
def encrypt_data(data, key, iv):
cipher = AES.new(key, AES.MODE_CBC, iv)
padded = data + (16 - len(data) % 16) * chr(16 - len(data) % 16)
encrypted = cipher.encrypt(padded.encode())
return base64.b64encode(encrypted).decode()
# 模拟登录请求
url = "https://api.example.com/login"
key = bytes.fromhex("a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6")
iv = b"1234567890abcdef"
data = '{"username":"test","password":"123456"}'
encrypted_data = encrypt_data(data, key, iv)
response = requests.post(url, data=encrypted_data,
headers={"Content-Type": "application/x-www-form-urlencoded"})
print(response.text)
关键点:模拟请求时,不仅要加密请求体,还要注意请求头里的签名、时间戳等字段。很多 App 会校验这些,少一个都不行。
知识体系总览
下面这张图,是我整理的本章节知识体系。你可以把它当作一张地图,随时回来对照。
这张图把本章的核心内容串起来了。从工具配置到协议分析,再到实战模拟,每一步都是环环相扣的。你可以在学习过程中随时回来对照,看看自己走到了哪一步。
好了,这一章的内容就到这里。网络协议逆向是个实践性很强的领域,光看不动手是学不会的。我建议你找个自己常用的 App,按照今天讲的步骤走一遍。遇到问题很正常,我当年也是从一脸懵逼到逐渐上手的。
记住:抓包是基础,绕过 SSL Pinning 是关键,协议分析是核心,模拟请求是最终目标。把这四步练熟了,大部分 App 的网络协议在你面前就是透明的。
最后提醒一句:逆向分析请遵守法律法规,仅用于学习和安全研究。不要用于非法用途。