30、综合实战:某社交App逆向分析:从抓包到脱壳再到协议模拟,完整流程复盘
说实话,做逆向这么多年,最怕的就是「社交App」。为什么?因为社交类App通常集齐了全套防护:加固、反调试、协议加密、证书校验……一个不少。但反过来想,啃下这类App,你的逆向能力基本就毕业了。
今天我就拿一个真实的社交App案例,带你完整走一遍流程。从抓包开始,到脱壳、分析协议、最后模拟登录。嗯,这条路我走过很多次,踩过的坑也不少,这次一并告诉你。
核心目标:通过逆向某社交App,掌握从抓包到协议模拟的完整方法论。
第一阶段:抓包——第一道坎就卡住了
我习惯先用Charles抓包看看基本情况。打开App,登录界面,输入账号密码,点击登录——Charles里一片空白。
为什么会这样?说白了,App做了SSL Pinning(证书绑定)。它只信任自己内置的证书,Charles的中间人证书被直接拒绝了。
我试过几种方案:
- 方案一:用Frida hook SSL验证函数。但App有反Frida检测,一启动就闪退。
- 方案二:用JustTrustMe模块。但App加固了,Xposed模块注入不进去。
- 方案三:用Packet Capture本地VPN抓包。这个能抓到,但数据全是乱码——协议加密了。
嗯,这里要注意:抓包不是目的,拿到明文数据才是。既然直接抓包行不通,那就得先过脱壳这一关。
我的经验:遇到SSL Pinning,别死磕抓包工具。先解决脱壳和Hook环境,后面自然能拿到数据。
第二阶段:脱壳——撕掉App的防护外衣
用APK查壳工具一看,是360加固。这个我熟,之前项目里遇到过好几次。
脱壳工具我选了frida-dexdump。为什么?因为它不需要root,而且对360加固的兼容性不错。
操作步骤:
- 启动App,让它在内存中运行起来
- 用frida-dexdump扫描内存中的dex文件
- dump出所有dex,用jadx打开
代码很简单:
# 安装frida-dexdump
pip install frida-dexdump
# 启动App后,执行dump
frida-dexdump -U -n com.social.app -o ./dump_output
dump出来的dex有3个。用jadx打开后,我一眼就看到了关键类:com.social.app.network.HttpClientWrapper。里面有个方法叫encryptRequest,还有个decryptResponse。
找到了!这就是协议加密的入口。
注意:有些加固会检测frida。如果遇到闪退,试试用frida的spawn模式启动,或者用frida-gadget注入。
第三阶段:协议分析——逆向加密算法
打开encryptRequest方法,代码大概长这样:
public String encryptRequest(String jsonData) {
String key = getDynamicKey();
String iv = "1234567890abcdef";
byte[] encrypted = AES.encrypt(jsonData.getBytes(), key.getBytes(), iv.getBytes());
return Base64.encodeToString(encrypted, Base64.NO_WRAP);
}
关键点在于getDynamicKey()。这个key不是写死的,而是每次从服务器获取的。我继续跟踪:
private String getDynamicKey() {
// 从SharedPreferences读取
String key = sp.getString("session_key", "");
if (TextUtils.isEmpty(key)) {
// 如果本地没有,就请求服务器
key = requestSessionKey();
}
return key;
}
嗯,这里有个逻辑:登录前,App会先请求一个session_key,然后用这个key加密登录数据。所以模拟登录时,必须先拿到session_key。
我写了个Frida脚本,把加密前后的数据都打印出来:
Java.perform(function() {
var HttpClientWrapper = Java.use("com.social.app.network.HttpClientWrapper");
HttpClientWrapper.encryptRequest.implementation = function(jsonData) {
console.log("原始数据: " + jsonData);
var result = this.encryptRequest(jsonData);
console.log("加密后: " + result);
return result;
};
});
跑起来后,控制台输出了完整的加密流程。我拿到了session_key、AES加密模式(CBC)、以及IV向量。
核心发现:加密算法是AES-128-CBC,key动态获取,IV固定。登录协议包含:session_key + 加密后的账号密码 + 时间戳。
第四阶段:协议模拟——用Python复现登录
有了加密算法和协议格式,剩下的就是写代码模拟了。我习惯用Python的requests库,配合pycryptodome做AES加解密。
完整流程:
- 先请求
/api/getSessionKey,拿到session_key - 用session_key加密登录数据(账号+密码+时间戳)
- 发送加密后的数据到
/api/login - 解析返回的加密数据,用session_key解密
代码实现:
import requests
from Crypto.Cipher import AES
import base64
import time
def encrypt_data(data, key):
iv = b"1234567890abcdef"
cipher = AES.new(key.encode(), AES.MODE_CBC, iv)
# PKCS7填充
pad_len = 16 - len(data) % 16
data += chr(pad_len) * pad_len
encrypted = cipher.encrypt(data.encode())
return base64.b64encode(encrypted).decode()
# 第一步:获取session_key
resp = requests.get("https://api.social.com/getSessionKey")
session_key = resp.json()["key"]
# 第二步:构造登录数据
login_data = {
"username": "test_user",
"password": "test_pass",
"timestamp": int(time.time())
}
encrypted_login = encrypt_data(json.dumps(login_data), session_key)
# 第三步:发送登录请求
login_resp = requests.post(
"https://api.social.com/api/login",
json={"data": encrypted_login}
)
# 第四步:解密响应
encrypted_result = login_resp.json()["data"]
decrypted_result = decrypt_data(encrypted_result, session_key)
print("登录结果:", decrypted_result)
跑了一下,返回了{"code":0,"msg":"success","token":"xxx"}。登录成功!
避坑指南:我曾经在时间戳上栽过跟头。App要求时间戳精确到秒,而且服务器会校验时间差是否在5分钟内。如果时间对不上,会返回「请求过期」。所以模拟时一定要用int(time.time()),别用毫秒级的时间戳。
知识体系总览
下面这张图,是我总结的社交App逆向完整流程。每一步都有对应的工具和关键点:
总结与思考
复盘一下这次逆向的完整链路:
- 抓包受阻 → 意识到有SSL Pinning和反调试
- 脱壳突破 → 用frida-dexdump拿到dex源码
- 协议分析 → 找到加密入口,逆向出AES算法
- 协议模拟 → 用Python完整复现登录流程
说实话,这个案例不算特别难。真正难的是那些用了自研加密协议、或者把密钥藏在so层做白盒加密的App。但方法论是一样的:先脱壳,再Hook,最后模拟。
我个人习惯在分析完一个App后,把关键点记下来。比如这次我就记了:session_key的获取方式、AES的IV值、时间戳的格式。下次遇到类似的App,直接复用这套思路,效率会高很多。
最后说一句:逆向分析是为了学习安全防护技术,请勿用于非法用途。理解攻击手段,才能更好地防御。