逆向3款App登录协议 - 论标准算法的危害
字数 2528 2025-08-06 08:34:54
逆向分析3款App登录协议 - 标准算法安全风险与防护
一、分析工具与方法
1.1 使用工具
- fridaUiTools:界面化整理脚本工具,主要用于Java层加解密分析
- GDAE:Android应用反编译工具
- HttpCanary:抓包工具
1.2 分析方法
- 通过输入固定测试账号(手机号15026818188,密码123456789)触发登录
- 抓取登录请求包
- 使用fridaUiTools附加进程,勾选Java加解密选项
- 分析日志中的加解密相关信息
- 定位关键加密代码
二、某电影网App登录协议分析
2.1 请求特征
- 请求方式:GET
- 加密参数:request
- 示例加密值:
xWonulEWGmnCtt3k0KzqxitgeBVGJxo53IW/llbwCCWoMOY3bQumRpdhOGr8X3M/
2.2 加密分析
- 定位加密:通过加密值片段在日志中搜索定位
- 加密原文:
username=15026818188&password=123456789&bcode= - 加密算法:3DES
- 密钥:通过日志获取(打码处理)
- IV:通过日志获取
- 模式填充:通过日志获取
- 验证:使用在线3DES工具加密原文,结果与hook结果一致
2.3 其他加密参数
-
Did参数:
- 原始值:
010067027161451 - 加密方式:MD5(原始值)
- 原始值:
-
Key参数:
- 组成:Did值 +
m1905_2014 - 加密方式:MD5(组合字符串)
- 组成:Did值 +
三、某设计App登录协议分析
3.1 请求特征
- 请求方式:POST
- 加密参数:key
- 示例加密值:
dTdlMmtGQjZIQk45NEN3dTIzamdVdFduWGFQM2M0WWJySm1QU3hJeUxEMStKWTV2UUdlMVhjT05K%250AZmdIeGZjOTZGSWYxU3NkUkltQQpPYTg0Z0Z0TkFqV0oyckxHOFppUGZGdnpRMzkrcjBuc0VIRVFm%250AcUk0QWtnNHdTWmR2anNyU1JpYTBpVXZ3aFVtSlZUb1FZQng4Tk5XCnFtQjB2UjZjcVE3ZXB5elRV%250AZlZhc2x1RTFsYjlENk1UREpkVG9qL3hZVGN5eENIWUtBejI1THI3Y0wzNXpVb3ZjelMybWxoUFBo%250AdVUKZzJPSStkY1Q3SkxEelNreE5VYlczTUg1b0ZwaVAvSytlUW05a1N1NFdLU0dKUWoxdWVVRHZX%250ANjI1a1lheEpRMktrdzFJbHJoOUJGQQp0MEcvQVFoQU5uWGxkU1FhUC9LK2VRbTlrU3U0V0tTR0pR%250AajF1YXFadjRiRWE5L1pxeEpWalVRSE0wUTA5WlJRaHhlRTNEVCtyS1VOClowSmRCQ2FzdHpvbnJO%250AK29wWjhmZE5tdVRRPT0KP2tleUlkPTE%253D%250A
3.2 加密分析
-
编码分析:
- 双重URL编码
- Base64编码
- 实际加密数据在Base64解码后
-
加密流程:
- 原始数据 → 加密 → Base64编码 → URL编码 → URL编码
-
特点:
- 无法直接在日志中搜索到加密值
- 需要多次解码后才能看到实际加密数据
四、某追星App登录协议分析
4.1 请求特征
- 无抓包防御
- 加密参数:pa
- 示例加密值:
MTY4OTUxNTM3Mzk0Nyw5YTI3MDE4NmU2YzA0YmU0YmM4MDgyMzRiZTdmNzU5OCwwNzMxMDk2ZDU4ZTg5OGNmNTg5YWEwYzI5YjRlOGVhOSw=
4.2 加密分析
-
Base64解码:
- 解码后格式:
时间戳,UUID,MD5值,空字符串
- 解码后格式:
-
组成分析:
- 第一部分:
String.valueOf(System.currentTimeMillis()) - 第二部分:UUID去除"-"后的字符串
- 第三部分:MD5(上下文对象 + 时间戳 + UUID)
- 第四部分:空字符串
- 第一部分:
-
MD5实现:
- 使用自定义C++实现(MD5_CTX类)
- 关键函数:
MD5_CTX::MD5_CTX- 初始化MD5_CTX::MakePassMD5- 实际MD5计算
-
标准MD5特征:
- 初始化常量:
- 0x67452301
- 0xEFCDAB89
- 0x98BADCFE
- 0x10325476
- PADDING数组首字节为0x80
- 包含64轮标准变换操作
- 初始化常量:
五、安全风险与防护建议
5.1 标准算法的风险
-
Java层加密风险:
- 标准加密库容易被hook
- 密钥、IV、模式等参数易泄露
- 加密流程透明,等同于明文传输
-
编码混淆的局限性:
- 多次编码只能增加分析难度
- 无法从根本上防止逆向
-
标准算法的识别:
- 通过算法特征常量识别
- 通过标准流程识别
5.2 防护建议
-
避免Java层加密:
- 尽量在Native层实现加密
- 避免使用标准加密接口
-
增强混淆:
- 对加密前后数据进行多重编码/变换
- 使用自定义编码方案
-
算法定制:
- 修改标准算法中的常量
- 增加冗余操作
- 拆分加密流程
-
综合防护:
- 结合设备指纹
- 动态密钥生成
- 定期更新算法
六、技术验证方法
6.1 Hook验证
// MD5函数hook示例
var funcAddr = Module.findExportByName("libencryptlib.so", "_ZN7MD5_CTX11MakePassMD5EPhjS0_");
console.log(funcAddr);
Interceptor.attach(funcAddr, {
onEnter: function(args) {
console.log("funcAddr onEnter args[1]: ", hexdump(args[1]));
console.log("funcAddr onEnter args[2]: ", args[2].toInt32());
this.args3 = args[3];
},
onLeave: function(retval) {
console.log("funcAddr onLeave args[3]: ", hexdump(this.args3));
}
});
// 字符串处理hook示例
setImmediate(function() {
Java.perform(function() {
var targetClass = decodeURIComponent('kotlin.text.StringsKt%5f%5fStringsJVMKt');
var methodName = 'replace$default';
var gclass = Java.use(targetClass);
gclass[methodName].overload('java.lang.String', 'java.lang.String', 'java.lang.String', 'boolean', 'int', 'java.lang.Object').implementation = function(arg0, arg1, arg2, arg3, arg4, arg5) {
console.log('\n[Hook replace$default(java.lang.String,java.lang.String,java.lang.String,boolean,int,java.lang.Object)]' + '\n\targ0 = ' + arg0 + '\n\targ1 = ' + arg1 + '\n\targ2 = ' + arg2 + '\n\targ3 = ' + arg3 + '\n\targ4 = ' + arg4 + '\n\targ5 = ' + arg5);
var i = this[methodName](arg0, arg1, arg2, arg3, arg4, arg5);
console.log('\treturn ' + i);
return i;
};
});
});
6.2 算法验证方法
-
在线工具验证:
- 使用在线加密工具验证标准算法
- 对比hook结果与工具结果
-
自定义实现验证:
- 根据分析实现相同算法
- 对比输出结果
-
调用栈分析:
- Hook标准加密方法
- 打印调用栈定位加密点
七、总结
通过对三款App登录协议的分析,揭示了使用标准加密算法的安全风险。分析表明:
- Java层加密容易被hook,导致密钥和算法暴露
- 单纯依赖编码混淆只能增加分析难度,不能根本解决问题
- 标准算法通过特征常量和流程可被识别
- 最有效的防护是将加密逻辑放在Native层并定制算法
安全建议优先级:
- 将核心加密逻辑移至Native层
- 定制修改标准算法
- 增加多层数据混淆
- 结合设备指纹等动态因素
- 定期更新加密方案