文章目录[隐藏]
密码学学习记录 3 / 15
- 密码学学习记录|hash md5 算法
- 密码学学习记录|hash md5 算法练习样本一
- 密码学学习记录|hash md5 算法练习样本二
- 密码学学习记录|hash sha1 算法
- 密码学学习记录|hash sha1 算法练习样本一
- 密码学学习记录|hash sha256 算法
- 密码学学习记录|hash sha256 算法练习样本一
- 密码学学习记录|hash sha512 算法
- 密码学学习记录|hash hmac 算法
- 密码学学习记录|des 加解密算法
- 密码学学习记录|des - 3des 算法
- 密码学学习记录|aes 加解密算法
- 密码学学习记录|aes dfa 练习样本一
- 密码学学习记录|aes dfa 练习样本二
- 密码学学习记录|aes dfa 练习样本三
前言
样本 app https://www.wandoujia.com/apps/280945 版本 15.25.1
分析总结:这个样本是标准的 md5 算法,但是因为对 md5 不太了解,导致还原了 so 算法之后才发现,如果大家时间充足的话,还是推荐还原一下 so md5 算法
charles 抓包
就是这个 nsign
参数
java 层的逻辑就不在分析了,后面直接分析 so
frida hook
function getMapData(mapSet) {
try {
var result = {};
var key_set = mapSet.keySet();
var it = key_set.iterator();
while (it.hasNext()) {
var key_str = it.next().toString();
result[key_str] = mapSet.get(key_str).toString();
}
return result
} catch (error) {
return mapSet
}
}
function getProcessId() {
var androidProcess = Java.use('android.os.Process');
return 'processId: ' + androidProcess.myTid() + ' - ';
}
function printLog() {
var result = '';
for (var i = 0; i < arguments.length; i++) {
result += arguments[i] + ' ';
}
console.log(getProcessId(), result)
}
Java.perform(function () {
var SignUtil = Java.use('com.anjuke.mobile.sign.SignUtil');
SignUtil.getSign0.implementation = function (a, b, c, d, e) {
printLog('SignUtil.getSign0.a: ', a);
printLog('SignUtil.getSign0.b: ', b);
printLog('SignUtil.getSign0.c: ', c);
printLog('SignUtil.getSign0.c: ', JSON.stringify(getMapData(c)));
printLog('SignUtil.getSign0.d: ', d);
printLog('SignUtil.getSign0.e: ', e);
var res = this.getSign0(a, b, c, d, e);
printLog('SignUtil.getSign0.res: ', res);
return res;
}
})
先使用 frida hook
一下,看看函数的输入输出时候
这个 c
参数是个 map
,byte[]
的数据没打印出来,不过都在 url params
里,可以根据 key
查找
so 分析
打开 libsignutil.so 文件
搜索 java
关键词,分析 getSign0
函数
点进 j_get_sign
函数
这里的 qsort
看起来是排序函数,下面又拼接上了一个盐值,最后调用了 j_SIGNMD5
函数
这个函数就比较清晰了,前面定义了四个 md5 的常量,接着调用了 update
函数
这是调用 transform
函数逻辑
transform
函数里的一些常量看起来不是标准的(实际上是标准的,博主也很疑惑,有清楚的小伙伴还望指点一下)
unidbg
接着使用 unidbg 辅助分析 so,大家自行先跑起来
final Pointer[] md5updater0 = {null};
emulator.getBackend().hook_add_new(new CodeHook() {
@Override
public void hook(Backend backend, long address, int size, Object user) {
if (address == (module.base + 0x11D4)) {
Arm32RegisterContext ctx = emulator.getContext();
md5updater0[0] = ctx.getR0Pointer();
Inspector.inspect(md5updater0[0].getByteArray(0, ctx.getR2Int() + 10), " md5 update params r0 ");
Inspector.inspect(ctx.getR1Pointer().getByteArray(0, ctx.getR2Int() + 10), " md5 update params r1 ");
System.out.println("md5 update params r2 " + ctx.getR2Int());
}
}
@Override
public void onAttach(UnHook unHook) {
}
@Override
public void detach() {
}
}, module.base + 0x11D4, module.base + 0x11D4, null);
跑起来之后,先 hook md5 update
函数的参数(获取到输入之后,就可以开始还原算法了)
so md5 还原
md5 算法的还原步骤
-
1、定义四个常量
-
2、定义 T数组(正弦函数表)
-
3、定义循环左移数(当然这个样本是循环右移)
-
4、确定 a, b, c, d 顺序(这个样本是标准的,唯一的区别是 + - 符号,可以参照 so 算法看一下)
feng504x
2022-04-27同感, 之前b站 安全第四题也是 标准md5, 然而后边才发现~~~
会爬山的小脑虎
2022-04-27@feng504x 确实 懵逼