This page looks best with JavaScript enabled

LLVM Opt view-cfg 优雅展示程序结构

 ·  ☕ 2 min read · 👀... views

在写混淆的时候,经常会遇到一个问题:在实现一些会改变控制流的混淆时,会理不清现在的控制流到底是怎么样的。比如在平坦化时,需要涉及很多移动基本块的操作,要抹去块跳转并自己加很多块间跳转,然后就很可能出现漏了什么跳转、或者是跳转的有问题。这可能会导致编译时直接报错(发现函数结构被破坏),也可能是导致输出的程序结构有问题(条件跳转有问题、出现死循环等)

如果这个时候去硬读IR或者汇编,是很累的,因为如果样例程序太大(比如平坦化增强就会产生大量大量的垃圾块)要找到哪里写错了是大工程,如果有工具能根据IR生成CFG图,就能一眼看出哪里出问题了(因为编译报错了是得不到bin文件用IDA去看CFG的)

然后我就发现了 LLVM 的opt,自带了生成CFG图的功能

需要装一下依赖

sudo apt-get install -y graphviz-doc libgraphviz-dev graphviz

opt生成图表,是通过解析汇编实现的,所以需要将文件先编译成汇编

1
2
3
4
5
# .c 
clang -S -emit-llvm target.c -o target.ll

# IR
llvm-dis target.bc -o target.ll

然后使用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文件渲染为图片

1
dot target.dot -Tpng -o target.png

因为可能会生成出很多dot图表,可以写一个脚本将文件夹内所有.dot文件均渲染

1
for dotfile in $(find . -name "*.dot"); do dot $dotfile -Tpng -o $dotfile.png; echo "[+]$dotfile"; done;

我用LLVM-Pass写了一个VM,然后输出图表看下效果

程序函数关系调用图
callgraph
encrypt函数cfg图
cfg
encrypt函数dom-cfg图
dom-cfg

Share on

Qfrost
WRITTEN BY
Qfrost
CTFer, Anti-Cheater, LLVM Committer