我来帮你优化一下这篇文章的排版,让它更清晰易读:
小程序国密加密渗透测试:固定SM4密钥与自动化加解密实战
0x01 背景
在针对一个小程序进行安全测试时,发现其请求数据采用 SM2+SM4 国密算法进行加密,且 SM4 密钥为动态生成,这给常规的渗透测试带来了阻碍。
为实现对请求的自动化测试与分析,需要解决动态密钥的问题。本文将详细记录通过修改内存固定密钥,并实现自动化加解密的完整过程。
0x02 工具准备
主要工具
-
Cheat Engine (CE)
-
BurpSuite + Galaxy 插件
-
Reqable 等抓包工具
0x03 使用 CE 固定 SM4 密钥
核心思路
使用 CE 修改小程序进程内存,将动态生成 SM4 密钥的代码逻辑修改为返回固定值。
操作步骤
1. 附加进程
在 CE 中点击左上角电脑图标,选择并附加目标小程序的进程。

2. 定位密钥生成代码
通过搜索字符串 randomstr 来定位动态生成密钥的代码区域。
如何定位?
- 方法一:强制开启开发者工具(F12)跟踪加密函数调用栈
- 方法二:反编译小程序源码进行分析

3. 分析并修改代码
复制出相关代码片段进行分析,发现关键行:
this.sm4Key = this.randomStr(32);
进一步查看 randomStr 函数的实现,发现其核心逻辑为:
t += "0123456789qwertyuiopasdfghjklzxcvbnm"[Math.floor(33*Math.random()+0)];
修改策略:
该行代码通过 Math.random() 生成随机索引。为了固定输出,只需将 33*Math.random()+0 中的 + 号修改为 * 号:
- 修改前:
33*Math.random()+0
- 修改后:
33*Math.random()*0
结果恒为 0,从而每次都取字符串的第一个字符 '0'。
4. 执行内存修改
- 在 CE 中右键该代码行,选择 "Browse this memory region"
- 在内存查看窗口中,找到对应字节
- 将加法操作码修改为乘法操作码(通常将
2B (+) 修改为 2A (*))
- 应用修改

5. 验证修改效果
重新进入小程序触发加密(或刷新页面)。此时,每次调用 randomStr(32) 都将返回由 32 个 '0' 字符组成的固定字符串。
通过抓包可以发现,相同请求的加密密文不再变化。

⚠️ 重要提示:这里的密钥是字符 '0',其十六进制表示为 \x30,而非 \x00。实际密钥为 \x30\x30\x30...(共 32 字节)。
0x04 实现 BurpSuite 自动化加解密
固定密钥后,即可利用 BurpSuite 插件实现测试流量的自动加解密,提升渗透测试效率。
使用 Galaxy 插件
1. 环境准备
在 Burp 的 Extender 中安装 Galaxy 插件。

2. 编写加解密脚本
在 Galaxy 中创建新的 Script Module,编写 Python 脚本。
脚本核心:四个 Hook 函数
| 函数名 |
作用 |
hook_request_to_burp |
将客户端发来的加密请求解密为明文,便于在 Burp 中查看和修改 |
hook_request_to_server |
将 Burp 中修改后的明文重新加密,再发送给服务器 |
hook_response_to_burp |
处理服务器响应(本例中服务器返回明文,故无需处理) |
hook_response_to_client |
处理返回给客户端的响应(本例中无需处理) |
3. 脚本核心逻辑
脚本需包含 SM4 的 ECB 模式加解密实现,并与前面固定的密钥(32 个 '0')保持一致。
关键点: 正确处理 Java 与 Python 之间的字节数组转换(有符号/无符号问题)。

4. 示例脚本概要
from org.m2sec.core.utils import CryptoUtil, JsonUtil
from java.lang import String
from jarray import array
# 算法配置
ALGORITHM = "SM4/ECB/PKCS5Padding"
secret = [0x30] * 32 # 32个'0'字符的ASCII码
requestJsonKey = "encryptJson"
def hook_request_to_burp(request):
"""解密请求:从加密数据还原为明文"""
# 从请求JSON中提取加密的十六进制数据
encrypted_hex = extract_data(request.getContent())
if encrypted_hex:
# 解密
decrypted_bytes = sm4_decrypt(encrypted_hex)
# 将解密后的明文替换原请求体
request.setContent(decrypted_bytes)
return request
def hook_request_to_server(request):
"""加密请求:将明文加密后发送给服务器"""
# 获取Burp中编辑后的明文
plain_data = request.getContent()
# 加密
encrypted_bytes = sm4_encrypt(plain_data)
# 包装成JSON格式并替换请求体
new_body = package_to_json(encrypted_bytes)
request.setContent(new_body)
return request
def sm4_decrypt(encrypted_bytes_list):
"""SM4解密函数"""
# 将Python字节列表转换为Java有符号字节数组
java_bytes = array(to_signed_java_bytes(encrypted_bytes_list), 'b')
java_secret = array(to_signed_java_bytes(secret), 'b')
# 调用Galaxy的CryptoUtil解密
decrypted_java_bytes = CryptoUtil.sm4Decrypt(ALGORITHM, java_bytes, java_secret, {})
# 将Java字节数组转回Python字节
return to_python_bytes(decrypted_java_bytes)
def sm4_encrypt(plain_bytes):
"""SM4加密函数(与解密对称)"""
# 实现逻辑与解密类似
pass
# ... 其他辅助函数(数据提取、包装、字节转换等)
📝 注意事项:脚本需根据实际小程序的请求/响应格式(JSON 字段名、加密数据编码方式等)进行调整。核心是确保加解密算法、模式、填充方式以及密钥与小程序客户端一致。
0x05 总结
通过以上步骤,我们成功实现了:
✅ 使用 Cheat Engine 固定动态生成的 SM4 密钥
✅ 通过 BurpSuite + Galaxy 插件实现自动化加解密
✅ 建立完整的渗透测试通道
现在可以高效地对小程序后端接口进行安全测试与漏洞挖掘了。
相关资源
关键技术点回顾:
- 内存修改技术(CE)
- 国密算法(SM2/SM4)
- BurpSuite 插件开发
- Java-Python 互操作