原文链接 :
https://wx.zsxq.com/group/51111114544514/topic/4844528181528428
样本下载链接:
aHR0cHM6Ly93d3cud2FuZG91amlhLmNvbS9hcHBzLzM2NjM1NS9oaXN0b3J5X3YyMjE=
近几个月遇到的白盒AES挺多的,再加上群里有人说这个案例没复现出来,今天终于抽出来时间来学学了
(愿大家少写点业务代码【抱头痛哭】)
原文中佬写的细得不行,每一步咋走都直接写好了,只能说,牛,就差手把手教你敲键盘了
心里莫名有点不得劲,没了探索的成就感,于是开始参照逻辑自己探索一把,所以本文主要是对原文部分内容的补充
其次是给不想依赖教程,想自己摸索的人,一个大概的逻辑自己去实现(墙裂推荐)
大概思路
1、java层就别浪费时间了,入口在com.bangcle.comapiprotect.CheckCodeUtil 的checkcode 方法
2、方法为静态注册——Java_com_bangcle_comapiprotect_CheckCodeUtil_checkcode,方法体里很明显可以看到aes和base64
3、unidbg 补环境很基础,然后直接func-trace,用base64的地址进行定位,往上的函数调用有很明显的四个方法循环调用,然后挨个看下四个方法
4、四个方法依次是 明文转state、加密计算、方法调用、方法调用
5、hook 查看第一个方法和第二个方法的传参,找出代表轮数的参数
6、DFA攻击
补充
1、抓包
群里有人说用佬的frida过ssl的脚本,还是抓不到包
我拿来就试了一下,确实依旧抓不到包,而且控制台没有打印任何东西
习惯性看一眼logcat,看看有没有报错信息、或者APP自带的日志可能会打印关键信息
SSLHandshakeException,堆栈前面是系统库,那关键部分就在okhttp3.internal.connection.RealConnection.connectTls 了
直接看代码
其实佬已经画出来了
第二条h.a和第三个hostname校验就是佬的脚本hook的地方
别想了,就这玩意儿,握手的时候证书不对,自己hook一下就完了
2、主动调用
建议在frida 中写一个循环主动调用这个加密,后面分析的时候就不用每次都手动去触发,而且主动触发日志比较多
3、加解密分析
unidbg补环境都很基础,没啥东西按照佬的走就行
佬在分析的时候看了很多汇编,说实话我看不懂一点,我比较常用的是func trace,打印方法调用流程,然后挨个跟着看大概每个方法做了啥
Debuggerdebugger = emulator.attach();
debugger.traceFunctionCall(module, newFunctionCallListener() {
publicvoidonCall(Emulator<?> emulator, long callerAddress, long functionAddress) {
}
publicvoidpostCall(Emulator<?> emulator, long callerAddress, long functionAddress, Number[] args) {
System.out.println("onCallFinish caller=" + UnidbgPointer.pointer(emulator, callerAddress) + ", function=" + UnidbgPointer.pointer(emulator, functionAddress));
// finalTraceStream.println("onCallFinish caller=" + UnidbgPointer.pointer(emulator, callerAddress) + ", function=" + UnidbgPointer.pointer(emulator, functionAddress));
}
});
这里直接拿base64方法的地址进行定位
往上看方法就会发现很有规律
这四个方法连着调用了28次,这下整个流程就比较清晰了
把这四个方法挨个看一遍
第一个方法: 0x70e4
按照佬的分析,这里是明文转state块,很明显可以看出a3就是明文
第二个方法:0x7f68
很明显的计算过程,这里就不看他的具体计算了,
第三个方法和第四个方法 就啥也没干了就方法调用
所以关键的就是 第一个方法 明文转state,第二个方法 加密计算
第二个方法加密计算的最后一个参数a4就是调用次数,传过来就是10
不会用unidbg的调试,所以我选择使用dobby hook
Dobby dobby = Dobby.getInstance(emulator);
dobby.replace(module.base+0x7f68, new ReplaceCallback() { // 使用Dobby inline hook
@Override
publicHookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
System.out.println("WBACRAES_EncryptOneBlock.onCall a4="+context.getIntArg(3));
returnHookStatus.RET(emulator, originFunction);
}
@Override
public void postCall(Emulator<?> emulator, HookContext context) {
}
}, true);
but 我在复制粘贴运行后,发现 DFA一注入,程序就会闪退
复制粘贴多了,动不了一点脑子,现在让看一下报错,突然有点不适应 全文唯一有点问题的,估计就
UnidbgPointer.pointer(emulator, 0xe4ffeb10L);
这一行代码了,问一下佬,这个方法是数字转指针,
那就好办了,总共就俩方法,要么选择加密方法那里,要么选择明文转sate的地方
之前写了第一个方法(明文转sate方法)的第三个参数是结果,查看一下第二个方法中调用第一个方法的代码
可以看到v52=0LL,然后取地址 传进了第一个方法
又因为第二个方法传进来就已经是最后一轮了,那我们DFA攻击选择的肯定就是这个地址
这个地址就是最后一轮加密之前的 state块,那我们修改这个块的内容就可以达到DFA攻击的目的了
所以所以,上面的运行后直接报错闪退,是因为他的地址跟你的可能不一样,hook一下看传入的哪个地址,然后把这个地址改成你的再进行DFA攻击即可
写个循环一百次调用,一直产生故障文
for (inti=0; i < 100; i++) {
BYDdemo=newBYD();
Stringencryptdata= demo.checkcode();
System.out.println("encryptdata:" + encryptdata);
}
使用phoenixAES 跑一下
最后结果都能对上,欧克结束
原文始发于微信公众号(逆向成长日记):DFA攻击白盒AES复现——某新能源车企
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论