代码混淆与反混淆学习-第二弹

科技资讯 投稿 5700 0 评论

代码混淆与反混淆学习-第二弹

deflat 脚本学习【去除OLLVM混淆】

deflat 脚本测试

这里以代码混淆与反混淆学习-第一弹中的OLLVM 混淆样本为例进行去除。【LLVM-4.0】

控制流平坦前 控制流平坦后

python deflat.py --file main-bcf --addr 0x401180

去混淆后,效果还算可以,能分析程序流程了。

deflat 脚本分析【angr】

angr documentation

    序言:函数的第一个执行的基本块
  • 主(子分发器:控制程序跳转到下一个待执行的基本块
  • retn块:函数出口
  • 真实块:混淆前的基本块,程序真正执行工作的版块
  • 预处理器:跳转到主分发器

显然,去控制流平坦化就是要找到真实块间的跳转逻辑,打破Switch结构束缚。

    静态分析CFG得到序言/入口块、主分发器、子分发器/无用块、真实块、预分发器和返回块。
  1. 利用符号执行恢复真实块的前后关系,重建控制流
  2. 根据第二步重建的控制流Patch程序,输出恢复后的可执行文件

静态分析

首先明确:【以下结论针对OLLVM项目,其他大佬加料的OLLVM混淆还需要单独分析】

    函数的开始地址为序言的地址
  1. 序言的后继为主分发器
  2. 后继为主分发器的块为预处理器
  3. 后继为预处理器的块为真实块
  4. 无后继的块为retn块
  5. 剩下的为无用块

angr 获取类似Ida的 CFG

获取真实块、主分发器、预处理器、序言、retn块和无用块

获取真实块的细节

angr 恢复真实块执行逻辑,重建控制流

cmov指令,就可以分别对应得到eax、ecx,然后获得后续真实块。【局限性很大】

symbolic_execution()函数,返回后继真实块。

Patch程序恢复执行逻辑

小结

分析下来,其实就是定位到所有真实块,然后利用angr符号执行将真实块间的执行逻辑进行串联。最后进行patch程序,重建控制流。

    函数的开始地址为序言的地址
  1. 序言的后继为主分发器
  2. 后继为主分发器的块为预处理器
  3. 后继为预处理器的块为真实块
  4. 无后继的块为retn块
  5. 剩下的为无用块

但是在实际去除控制流平坦化过程中,上面的默认思路已经被加混淆的开发者做了处理。

    后继为预处理器的块不一定是真实块;
  • 预处理器不一定存在;
  • 存在分支的真实块跳转的判断逻辑,不一定是cmov指令;
  • deflat脚本默认模拟执行最多两个分支,但真实情况可能不只两个分支;
  • 可能存在一个向前更新的数组,依据程序运行进行更新,决定当前真实块的跳转【这导致angr对于该块的模拟执行得不到正确的跳转】
  • 程序在加混淆前,已经被添加了花指令或其他处理,程序CFG图已经被打破;
  • 某个块存在死循环,会使angr符号执行卡死……

这也导致了,这个deflat脚本的普适性较低,除了能够处理OLLVM官方项目做的混淆,对加了其他PASS或者处理的混淆,基本用不了。

根据程序的实际混淆效果,对deflat脚本进行修改,再进行去混淆。

失败的花指令控制流平坦化尝试

使用代码混淆与反混淆学习-第一弹中加了花指令的程序,进行OLLVM控制流平坦化混淆,看看效果。

# clang 执行内联汇编加 -fasm-blocks 或者 -fms-extensions 或者 -masm=intel

clang -mllvm -fla -mllvm -split -mllvm -split_num=3 main-call-加花.cpp -lm -fasm-blocks -o main-call-加花

# 需要对源代码作一些修改

存在较大的问题,我的OLLVM 环境是在Ubuntu上搭建的,对于上述内联汇编加的花指令无法编译通过!

Windows 上移植OLLVM,进行编译(好像挺难的)】

【最终也没解决编译问题,或许本就不可以,ollvm 不具备这样的处理能力,也可能是我代码的问题,如果博客前的你有任何想法,欢迎与我交流

TSCTF-J 2022-upx_revenge实战分析

upx_revenge题目进行分析。

python deflat.py --file upx_revenge_test --addr 0x4016D0

处理多个retn块

回到ida 查看cfg 图发现原因:存在其他的退出块。

# 其他位置的retn_node,对应改为list处理
if supergraph.out_degree(node == 0:
            retn_node.append(node
去除后CFG图

多个comv的处理

很明显看出,程序的真实块间的逻辑串联失败,也就是重建控制流失败。

显然,这里存在2个分支,因为有两个cmov【相同判断】,并且call 函数,对分支跳转是有作用的,这里var_CC是顺序执行,动态更新的。

cmov指令的情况,且hook了call函数】

【由于var_CC是顺序执行,动态更新也可以看出,deflat 脚本的模拟执行思路已经无法对真实块的后继进行确定了】

comv 处的模拟。对前文并无任何关联。

总结

angr

upx_revenge 这道题而言,

那么如何通过angr,有序的、联系上文地进行模拟执行,获取真实块的执行逻辑,显然是关键点!

unicorn

[原创]ARM64 OLLVM反混淆-Android安全-看雪论坛-安全社区|安全招聘|bbs.pediy.com (kanxue.com

使用unicorn 模拟执行框架获取真实块间的执行顺序,重建控制流。

ida

使用IDA microcode去除ollvm混淆(上 - 先知社区 (aliyun.com

利用ida 现成的CFG 图,以及idc 脚本,动态运行程序,获取真实块的执行顺序,从而恢复控制流。

编程笔记 » 代码混淆与反混淆学习-第二弹

赞同 (25) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽