控制流平坦化(Control Flow Flattening)是代码混淆中的一种技术,用来打乱代码的执行流程,让原本简单的逻辑变得复杂,增加代码被理解和逆向工程的难度。
什么是控制流?
控制流就是代码的执行顺序。通常代码按照书写顺序从上往下执行,但也会有一些跳转,比如 if 条件判断、for 循环、switch-case 等逻辑。
控制流平坦化的意思:
控制流平坦化的目的是把这些跳转和逻辑结构隐藏起来,让代码看起来像是没有分支和跳转,而实际上它通过其他手段(比如状态机或复杂的 switch 语句)来控制执行的顺序。
举个例子:
假设你有一个非常简单的代码:
if (x > 10) {
console.log("大于10");
} else {
console.log("小于等于10");
}
这段代码很容易看懂,有个 if-else 语句来判断 x 的值,然后输出相应的内容。
控制流平坦化后,这段代码可能会变成这样:
let _state = 0;
while (true) {
switch (_state) {
case 0:
if (x > 10) {
_state = 1; // 改变状态,进入下一步
break;
} else {
_state = 2;
break;
}
case 1:
console.log("大于10");
return; // 结束
case 2:
console.log("小于等于10");
return; // 结束
}
}
发生了什么?
- 原本的
if-else逻辑被“平坦化”成一个状态机和switch语句。 - 代码执行时,通过状态的改变来控制执行哪个
case,而不是直接按照原来的if-else跳转。 - 表面上看起来代码结构被打散了,变得更加复杂,但执行效果依然相同。
为什么这样做?
控制流平坦化的目的是让人难以理解代码的实际执行流程。原本简单的 if-else 变成了一系列的状态切换和跳转,使得攻击者在分析代码时必须花费更多的时间和精力去理解这些复杂的状态变化。
总结:
控制流平坦化就是通过打乱原本清晰的代码执行顺序,把控制逻辑转化成复杂的状态机或 switch 语句,从而让代码的执行流程变得不直观,增加逆向工程的难度。
延伸阅读:基于LLVM Pass实现控制流平坦化