07-ollvm源码分析

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值