Control Flow Flattening
简要来说,控制流平坦化是对程序控制流的变换,使得所有基本块都处于同一个层级,因此就无法简单推断出嵌套、顺序、条件分支的关系,从而干扰分析。经过控制流混淆后的代码,控制流图会变得比较“扁平”,因为原先的基本块的前驱和后继都被改成了派发器,原来的循环中的有层级关系的基本块经过处理后处于同一个层级了。下面是论文1的一张图:
基于OLLVM
的实现已经十分成熟,网上也有很多教程。
本文尝试基于soot
框架实现类似的控制流混淆。
尽管soot
有一个新的sootup
版本,而尝试起来确实比原来的soot
的API
更加友好,方便,但是其缺乏后端的支持,只能生成Jimple代码,因此本文还是选择原本的soot
进行开发。
Soot Implementation
主要的思路就是创建一个大的Switch
块,将随机生成的常量与基本块对应起来,最后写入派发的逻辑。如果是JGotoStmt
,那么把跳转的目标设置为bigswitch
,并且插入一个对x
的赋值。对于JIfStmt
,则需要获取到两个target
对应的x
值,并将跳转目标也都设置为bigswitch
。
Soot IR (Jimple)
Statements
Stmt
是Jimple
的一个基本单元。各种操作,例如JAssignStmt
是赋值操作,前面提到的bigswitch
可以用下面的代码实现:
Basic Block
Basic Block
是连续的不包含跳转的代码块。soot
中可以通过BriefBlockGraph
来得到。
绘图使用CFGToDotGraph
类。
Implementation
soot
的初始化部分较为复杂,因此笔者直接参考了下面的代码:
混淆主要是用transformer
来插入和修改Unit
。Transformer
是继承自类BodyTransformer
,或者SceneTransformer
,根据粒度的不同。
- 方法body (e.g.,
BodyTransformer
).
- 全程序 (e.g.,
SceneTransformer
).
soot
的执行是基于phases
的,和llvm
的pass
类似,是对IR代码的分析和转换,transformer
也在这里被执行。一些pack
列举如下:
jtp
(Java Transformation Pack): 对于方法执行BodyTransformer
wjtp
(Whole Java Transformation Pack): 对于整个程序执行 SceneTransformer
bb
(Basic Block Pack): Operates at the basic block level.
例如,在本文中,使用下面的代码执行BodyTransformer
Result
https://magjac.com/graphviz-visual-editor/
测试类使用了一个RC4
的加密。
test
方法原来的控制流图如下:
下图是混淆后的控制流图:
然而,目前的实现无法通过java
的bytecode verifier
检查,运行时需要手动指定-noverify
参数。推测可能是由于asm
后端无法生成正确的stackmap
信息。
尽管输出了正确的结果,但只能算得上一个实现的原型,还无法应用于实际的代码保护。
Todo
研究已有的混淆器: