1. 逆向工程入门:从小程序API签名破解说起
最近在研究微信小程序的逆向工程,发现很多小程序的关键接口都采用了签名验证机制。比如租车查询接口,必须携带正确的sign参数才能正常调用。这让我产生了浓厚兴趣——如果能破解这个签名算法,岂不是可以自由调用这些接口了?
逆向工程就像侦探破案,需要从蛛丝马迹中寻找线索。我决定从一个实际的租车小程序入手,记录下完整的破解过程。整个过程大致分为四个阶段:抓包分析、源码解密、算法还原和本地复现。下面我会详细讲解每个步骤的具体操作和遇到的坑。
2. 抓包分析:Fiddler捕获关键请求
2.1 环境准备
首先需要安装抓包工具Fiddler,配置HTTPS解密功能。这里有个小技巧:在Fiddler的Options > HTTPS中勾选"Decrypt HTTPS traffic",并信任根证书。这样就能捕获到小程序发出的HTTPS请求了。
配置完成后,打开目标小程序进行操作。以租车为例,选择取车时间、地点后点击查询,这时Fiddler会捕获到类似这样的请求:
GET /api/car/query?cid=14&q=%7B%22pickupCityId%22%3A%2214%22...%7D&sign=3a8f7e2b5c6d&uid=123456 HTTP/1.12.2 参数分析
观察请求参数,发现几个关键字段:
- cid:城市ID
- q:经过URL编码的JSON字符串,包含取还车时间地点等信息
- sign:32位的签名值
- uid:用户ID(可选)
通过反复测试发现,修改任何参数都会导致sign校验失败。这说明sign是由其他参数通过某种算法生成的。接下来就需要找出这个算法。
3. 解密小程序源码
3.1 获取.wxapkg包
微信小程序的源码都打包在.wxapkg文件中。在Windows电脑上,这些文件通常存放在:
C:\Users\[用户名]\Documents\WeChat Files\Applet\[小程序ID]\使用工具UnpackMiniApp可以自动解密这些包。操作很简单:
- 关闭微信
- 运行UnpackMiniApp选择目标小程序目录
- 解密后的文件会生成在wxpack文件夹中
3.2 解压源码结构
解密后会得到完整的项目结构:
├── app.js # 主逻辑 ├── app.json # 配置文件 ├── pages/ # 页面目录 │ └── index/ │ ├── index.js │ ├── index.wxml │ └── index.wxss └── utils/ └── sign.js # 签名算法可能在这里4. 分析签名算法
4.1 定位关键代码
全局搜索"sign"相关代码,在utils/sign.js中发现核心逻辑:
function generateSign(params) { const str = `cid=${params.cid};q=${params.q}${params.uid?';uid='+params.uid:''}${secretKey}` return md5(str) }原来签名是通过拼接参数后计算MD5得到的!secretKey是个常量,在代码的其他位置定义。
4.2 算法还原
根据代码可以还原出签名步骤:
- 按固定格式拼接参数:
cid=值;q=值;uid=值(uid可选) - 末尾加上secretKey
- 对拼接后的字符串计算MD5
用Python实现这个算法:
import hashlib def generate_sign(cid, q, uid=None, secret_key="xxxxxx"): s = f"cid={cid};q={q}" if uid: s += f";uid={uid}" s += secret_key return hashlib.md5(s.encode()).hexdigest()5. 本地复现与验证
5.1 模拟请求
使用Python的requests库模拟小程序请求:
import urllib.parse import requests params = { "pickupCityId": "14", "pickupTime": "2024-08-09 12:30", # 其他参数... } q = urllib.parse.quote(json.dumps(params)) sign = generate_sign(cid="14", q=q) response = requests.get( "https://xxx.com/api/car/query", params={"cid": "14", "q": q, "sign": sign} ) print(response.json())5.2 遇到的坑
参数顺序问题:发现如果JSON中字段顺序不同,生成的sign也会不同。后来发现小程序用了
JSON.stringify(),会保持字段顺序。secretKey变化:有些小程序会定期更换secretKey。解决方法是在代码中动态获取,或者监控小程序更新。
请求频率限制:直接调用容易被封IP。建议控制请求频率,或者使用代理IP池。
6. 进阶技巧与防护建议
6.1 对抗混淆
现在很多小程序会做代码混淆,比如:
- 变量名替换为无意义的字符
- 插入无用代码
- 控制流扁平化
对付混淆可以使用AST(抽象语法树)分析工具,逐步还原代码逻辑。或者用浏览器调试工具动态跟踪执行过程。
6.2 给开发者的建议
如果你的小程序需要保护API:
- 不要在前端存储敏感密钥
- 使用非对称加密或动态密钥
- 加入时间戳防止重放攻击
- 关键逻辑放到后端处理
逆向工程是个需要耐心的技术活。每次破解成功都像解开一个谜题,既有成就感又能学到新东西。不过要提醒大家,技术研究可以,但千万别用于非法用途。