在写混淆的时候,经常会遇到一个问题:在实现一些会改变控制流的混淆时,会理不清现在的控制流到底是怎么样的。比如在平坦化时,需要涉及很多移动基本块的操作,要抹去块跳转并自己加很多块间跳转,然后就很可能出现漏了什么跳转、或者是跳转的有问题。这可能会导致编译时直接报错(发现函数结构被破坏),也可能是导致输出的程序结构有问题(条件跳转有问题、出现死循环等)
如果这个时候去硬读IR或者汇编,是很累的,因为如果样例程序太大(比如平坦化增强就会产生大量大量的垃圾块)要找到哪里写错了是大工程,如果有工具能根据IR生成CFG图,就能一眼看出哪里出问题了(因为编译报错了是得不到bin文件用IDA去看CFG的)
然后我就发现了 LLVM 的opt,自带了生成CFG图的功能
需要装一下依赖
sudo apt-get install -y graphviz-doc libgraphviz-dev graphviz
opt生成图表,是通过解析汇编实现的,所以需要将文件先编译成汇编
|
|
然后使用opt转化成dot格式的图表
opt -dot-callgraph target.ll # 生成程序函数调用关系图
opt -dot-cfg target.ll # 生成函数cfg图(对每个函数生成一个.dot文件)
opt -dot-dom target.ll # 生成函数dom-cfg图(对每个函数生成一个.dot文件)
# LLVM16及以上版本需加 -enable-new-pm=0 将其转换为NewPass
最后用dot将.dot文件渲染为图片
|
|
因为可能会生成出很多dot图表,可以写一个脚本将文件夹内所有.dot文件均渲染
|
|
我用LLVM-Pass写了一个VM,然后输出图表看下效果
程序函数关系调用图
encrypt函数cfg图
encrypt函数dom-cfg图