SplitBasicBlock(split 分割基本块)
toSplit = toSplit->splitBasicBlock(it, toSplit->getName() + ".split");
- 判断基本块包含的指令最多能被切分为几块
- 构建基本块被切割的位置
- 使用上面的代码切割基本块
Instructions Substitution(sub 指令替换)
- 遍历基本块中的指令,当指令操作码为加减乘除或异或之类时,进行指令替换
if (inst->isBinaryOp()) {
switch (inst->getOpcode()) {
case BinaryOperator::Add:
(this->*funcAdd[llvm::cryptoutils->get_range(NUMBER_ADD_SUBST)])(cast<BinaryOperator>(inst));
break;
case BinaryOperator::Sub:
(this->*funcSub[llvm::cryptoutils->get_range(NUMBER_SUB_SUBST)])(cast<BinaryOperator>(inst));
break;
}
。。。。。
}
- 指令替换 (图中第二个指令被替换的方式)
// Implementation of a = -(-b + (-c))
void Substitution::addDoubleNeg(BinaryOperator *bo) {
BinaryOperator *op, *op2 = NULL;
if (bo->getOpcode() == Instruction::Add) {
op = BinaryOperator::CreateNeg(bo->getOperand(0), "", bo);
op2 = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo);
op = BinaryOperator::Create(Instruction::Add, op, op2, "", bo);
op = BinaryOperator::CreateNeg(op, "", bo);
// Check signed wrap
//op->setHasNoSignedWrap(bo->hasNoSignedWrap());
//op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap());
} else {
op = BinaryOperator::CreateFNeg(bo->getOperand(0), "", bo);
op2 = BinaryOperator::CreateFNeg(bo->getOperand(1), "", bo);
op = BinaryOperator::Create(Instruction::FAdd, op, op2, "", bo);
op = BinaryOperator::CreateFNeg(op, "", bo);
}
bo->replaceAllUsesWith(op);
}
- 可指定指令替换的循环次数(在指令替换完的基础上,继续进行指令替换)
Control Flow Flattening(fla 控制流程平坦化)
该混淆包含两个Pass:
- createLowerSwitchPass
- createFlattening
测试代码如下
int switchReturn(int a,int b){
int ret = 0;
switch (a){
case 1:{
ret = a;
printf("num is %d\n",ret);
break;
}
case 2:{
ret = -a;
printf("num is %d\n",ret);
break;
}
case 3:{
ret = a-b;
printf("num is %d\n",ret);
break;
}
default:
{
ret = a+b;
printf("num is %d\n",ret);
break;
}
}
}
int main(int argc,char** argv)
{
int n = argc + 8 + switchReturn(argc,10);
if(n >= 10)
{
n = n + argc + 11;
printf("num is %d\n",n);
}else{
n = n + argc + 9;
printf("num is %d\n",n);
}
return 0;
}
控制流程平坦化会添加一个用于控制跳转的状态变量和分发器:
- 当一个真实块执行完成后,会把状态变量的值进行更新,回到分发器进行检查,再根据状态变量的值跳转到下一个真实块执行;
- 如果原本的执行流程中存在条件跳转,则会在各条件下对状态变量设置不同的值,再回到分发器进行检查和跳转。
为什么需要 createLowerSwitchPass ?
存在switch语句时,多个基本块会受原先switch语句的的控制,这些基本块无法直接嵌入到分发器中(这些基本块的执行条件无法通过状态变量控制)。需要先将switch语句以及其控制的基本块,平坦化(转成br跳转指令)
createFlattening Pass
对比左右的NodeBlock9基本块:
- 在左侧,NodeBlock9执行过后,要么跳转到LeafBlock,要么跳转到NodeBlock
- 在右侧,(左侧已经平坦化了)就多了一个控制,这个控制就是上面说的分发器和状态变量
- LeafBlock和NodeBlock用一个状态变量进行表示
- 获取状态变量的值
- 跳转到loopEnd基本块,再从loopEnd基本块跳到loopEntry基本块
- 通过获取到的状态变量的值,通过loopEntry基本块中的switch语句跳转到LeafBlock或NodeBlock
Bogus Control Flow(bcf 虚假控制流程)
解释:参考 https://blog.csdn.net/suningning/article/details/103307501
参考
http://rk700.github.io/2020/08/03/ghidra-ollvm-deobfuscation/
https://blog.csdn.net/dongjideyu/article/details/107951272