一、网络协议逆向:从抓包到模拟请求

各位同学好。今天我们来聊聊 Android 网络协议逆向。说实话,这块内容是我在移动安全领域花时间最多、踩坑也最多的方向之一。你想想看,现在哪个 App 不联网?几乎所有的核心业务逻辑都跑在网络上。所以,搞懂网络协议逆向,就等于拿到了 App 的命门。

这一章,我会带你走完一条完整的链路:从配置抓包工具开始,到绕过 HTTPS 证书绑定,再到分析协议内容,最后逆向一个真实的加密 API 并成功模拟请求。嗯,内容不少,但每一步我都会结合我自己的实战经历来讲。

核心目标:掌握 Android 网络协议逆向的完整方法论,能够独立分析并模拟任意 App 的加密网络接口。

抓包工具配置:三剑客的选择

工欲善其事,必先利其器。抓包工具我常用的有三款:Charles、Burp Suite、Fiddler。各有千秋,我分别说说我的使用习惯。

Charles:我最常用的代理工具

Charles 是我个人最推荐的抓包工具,尤其适合 Android 逆向。为什么?因为它对 SSL 的支持最友好,界面也直观。

配置步骤:

  1. PC 端开启 SSL Proxying,添加需要抓包的域名
  2. 手机设置代理:IP 填 PC 的局域网地址,端口默认 8888
  3. 访问 chls.pro/ssl 下载并安装 CA 证书
  4. 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 文件,直接反序列化即可。但大多数情况下,你需要自己逆向出协议结构。

我的方法:

  1. 抓取多组请求数据,对比二进制差异
  2. 使用 protobuf-inspector 工具分析字段编号和类型
  3. 结合反编译的代码,找到对应的 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 会校验这些,少一个都不行。

知识体系总览

下面这张图,是我整理的本章节知识体系。你可以把它当作一张地图,随时回来对照。

Android 网络协议逆向知识体系 抓包工具配置 SSL Pinning 绕过 协议分析 Charles / Burp Suite / Fiddler 代理配置 + 证书安装 Android 7.0+ 系统证书 Frida Hook / Xposed JustTrustMe 模块 重打包修改 smali HTTP/HTTPS 结构分析 Protobuf 逆向 自定义协议逆向 实战:逆向加密 API 并模拟请求 抓包 → 定位加密 → Hook 密钥 → 模拟请求 成功模拟请求,获取数据

这张图把本章的核心内容串起来了。从工具配置到协议分析,再到实战模拟,每一步都是环环相扣的。你可以在学习过程中随时回来对照,看看自己走到了哪一步。


好了,这一章的内容就到这里。网络协议逆向是个实践性很强的领域,光看不动手是学不会的。我建议你找个自己常用的 App,按照今天讲的步骤走一遍。遇到问题很正常,我当年也是从一脸懵逼到逐渐上手的。

记住:抓包是基础,绕过 SSL Pinning 是关键,协议分析是核心,模拟请求是最终目标。把这四步练熟了,大部分 App 的网络协议在你面前就是透明的。

最后提醒一句:逆向分析请遵守法律法规,仅用于学习和安全研究。不要用于非法用途。

公众号:蓝海资料掘金营,微信deep3321