ollvm反混淆

一、前言

此篇文章只讲思路,具体代码实现见https://github.com/gal2xy/AngrDeobfuscator。

二、去混淆

2.1 去指令替换混淆

指令替换一般可以使用llvmpass进行优化,使用llvm-dis反汇编再使用opt-o3等级优化。或者使用Miasm框架进行匹配,然后优化处理即可。

2.2 去字符串混淆

没怎么了解字符串混淆这一块,就贴一下随风而行aa大佬的文章内容。

字符串加密的的常规解决方式:

(1)特征搜索

一般在so中可以直接搜索datadiv_decode,一般很多编写解密函数进行操作是这个函数,针对这种情况,一般可以通过frida hook就可以拿到解密后的值,然后进行patch

(2)init_array中解密

字符串解密操作在init_arrray中进行,一般可以通过模拟执行init_array,然后将解密后的字符串全部保存下来。

(3)jni_onload解密

jni_onload函数中进行解密操作,这时候就要进行inlinehook拿到解密后寄存器的值,也可以进行hook,也可以使用unicorn进行操作。

2.3 去虚假控制流混淆

虚假控制流主要是通过不透明谓词控制代码流,ollvm中的不透明谓词与输入无关,因此可以通过符号执行来去除虚假块。具体思路为,使用angr执行整个程序,记录下可到达的基本块,其余基本块则是不可达基本块,可以认为使虚假块。接下来就需要对后继块中存在虚假块的基本块进行patch,将最后一条指令(jcc指令)修改成jmp指令。

2.4 去控制流平坦化混淆

ollvm中控制流平坦化混淆的效果如下图所示:

其代码的真实逻辑在:序言块、真实块(相关块)、retn块中。

整个去混淆思路如下:

  1. 区分基本块

    这些基本块在CFG中具有很明显的特征,例如前继基本块为0的是序言块,后继基本块为0的是retn块,后继基本块为预处理器(预分发器)的为真实块,而预处理器的后继基本块为主分发器,而主分发器的前继基本块为序言块。因此,通过这些特征很容区分出这些基本块。

    (不过如果是魔改混淆,则可能需要另找特征进行区分)

  2. 恢复相关块(包括序言块)之间的跳转关系

    这个可以通过angr的符号执行来恢复。即从每个相关块(包括序言块)进行符号执行,当执行到其他相关块中时,则认为找到了当前相关块的后继相关块。当然,后继块数量可能 > 2,则就需要下断点,更改条件表达式变量的值,使其强制执行我们所需要的分支,,这样才能恢复得全面。

    关于后继块的数量,可以通过块中有无cmov指令指令来判断。

  3. 修补程序

    把无用块都nop掉。根据得到的跳转关系,如果当前块只有一个后继块,则将当前块中的最后一条指令修改成jmp指令跳转到该后继块,如果当前块存在两个后继块,则将当前块中的cmovxxx指令修改成对应的jcc指令,然后再将后面的指令修改成jmp指令跳转到另一条分支。


参考:

相关博客参考:

利用符号执行去除控制流平坦化 - 博客 - 腾讯安全应急响应中心 (tencent.com)

[原创]Android APP漏洞之战(14)——Ollvm混淆与反混淆-Android安全-看雪-安全社区|安全招聘|kanxue.com

https://github.com/WindXaa/Android-Vulnerability-Mining/blob/main/Ollvm%E5%8F%8D%E6%B7%B7%E6%B7%86%E8%84%9A%E6%9C%AC

angr API参考:

https://docs.angr.io/en/latest/analyses/cfg.html

https://docs.angr.io/en/latest/api.html#angr.knowledge_plugins.cfg.CFGModel.nodes

https://docs.angr.io/en/latest/api.html#angr.knowledge_plugins.cfg.cfg_node.CFGNode

https://docs.angr.io/en/latest/api.html#angr.block.CapstoneInsn

am_graph库:

https://github.com/angr/angr-management/blob/master/angrmanagement/utils/graph.py


ollvm反混淆
http://example.com/2024/06/25/LLVM and OLLVM/ollvm反混淆/
作者
gla2xy
发布于
2024年6月25日
许可协议