ollvm 重写fla 平坦控制流

 1 添加pass 

在目录 lib\Transforms\Obfuscation 新建MyFla.cpp
 

2 什么是平坦控制流

说白了就是把原来的代码的基本块进行拆分 ,再用switch case打乱分发,把原本代码的逻辑连接起来。让逆向者不知道代码块的原本顺序。

3 编写一个测试demo

int myaddA(int a ,int b)
{
	
	int i=10;
	if(a % 2 == 0)
	{
	   i=10; 
	}
	else{
	   i=20; 
	}
	return a+b+i;
}

没有平坦流的效果

 

平坦流后的效果

 可以看到经过平坦流 该函数多了很多基本块!

pass 代码实现

上代码

bool MyFla::flatten(Function *f) 
{

  vector<BasicBlock *> origBB;
  BasicBlock *loopEntry;
  BasicBlock *loopEnd;
  LoadInst *load;
  SwitchInst *switchI;
  AllocaInst *switchVar;

  //生成随机数key case
  char scrambling_key[16];
  llvm::cryptoutils->get_bytes(scrambling_key, 16);
  for (int i = 0; i < 16; i++)
  {
      errs() <<"scrambling_key  "<< scrambling_key[i] << "\n";
  }
  


  int index = 0;
  for (Function::iterator i = f->begin(); i != f->end(); ++i) {
      BasicBlock *tmp = &*i;
      index++;
      errs() <<"baseblock "<< *tmp << "\n"; 
  }
  errs() <<"baseblock count  "<< index << "\n";
  //调用了一个外部Pass, LowerSwitch这个Pass, 主动调用了这个Pass的runOnFunction函数,
  //内部逻辑是消除了当前函数中的switch方式组织的代码,抓换成if else这种分支调用,方便后面进行代码块分割,从而进行平坦化操作
  errs() <<" ================================ " << "\n"; 
  FunctionPass *lower = createLowerSwitchPass();
  lower->runOnFunction(*f);

  // 遍历函数所有BasicBlock,并保存到origBB 数组中
  index = 0;
  for (Function::iterator i = f->begin(); i != f->end(); ++i) 
  {
    BasicBlock *tmp = &*i;
    origBB.push_back(tmp);
    index++;
    //errs() <<"origBB "<< *tmp << "\n"; 

    //末尾是一条Invoke指令 返回
    /*
      try {
        foo();
      } catch (MyError err) 
      {
      }

      IR
       %4 = alloca %struct.MyError, align 1
       invoke void @_Z3foov()
          to label %5 unwind label %6
    */
    BasicBlock *bb = &*i;
    if (isa<InvokeInst>(bb->getTerminator())) {
      return false;
    }
  }
  errs() <<"origBB count  "<< index << "\n";

  //基本款太少 不平坦化
  if (origBB.size() <= 1) {
    return false;
  }
  // 去掉第一个基本块 第一块是函数的入口块,顺序不能乱
  origBB.erase(origBB.begin());

  //1 本函数第一个基本块的处理
  Function::iterator tmp = f->begin();  //++tmp;
  BasicBlock *insert = &*tmp;

  errs() <<"firstblock   "<< *insert << "\n";
  // 如果是分支指令 br cmp
  //getTerminator 如果区块结构完整,则返回终止指令,如果区块结构不完整,则返回空。
  BranchInst *br = NULL;
  if (isa<BranchInst>(insert->getTerminator())) 
  {
    br = cast<BranchInst>(insert->getTerminator());
  }
  //isConditional 如果是有条件跳转分支指令 或者如果该跳转分支有两个后继块 则进行分割  比如 br i1 %3, label %4, label %13
  if ((br != NULL && br->isConditional()) || insert->getTerminator()->getNumSuccessors() > 1) 
  {
    BasicBlock::iterator i = insert->end();
	  --i;

    if (insert->size() > 1) 
    {
      --i;
    }
    //从倒数第二条指令 开始分割基本块
    BasicBlock *tmpBB = insert->splitBasicBlock(i, "first");
    errs() <<"firstblock tmpBB  "<< *tmpBB << "\n";
    origBB.insert(origBB.begin(), tmpBB);
  }
  // 脱离父节点的关系
  insert->getTerminator()->eraseFromParent();
  // 第一个基本块的处理 处理完毕


  // 创建一个空的switch 语句  基本骨架
 
  // 利用AllocaInst分配一个空间给switchVar
  switchVar = new AllocaInst(Type::getInt32Ty(f->getContext()), 0, "switchVar", insert);
  // 为switchVar变量赋一个伪随机值
  new StoreInst( ConstantInt::get(Type::getInt32Ty(f->getContext()), llvm::cryptoutils->scramble32(0, scrambling_key)), switchVar, insert);
 
  // 2 创建一个代码块loopEntry, 空代码块
  loopEntry = BasicBlock::Create(f->getContext(), "loopEntry", f, insert);
  loopEntry->setName("loopEntry");
  loopEnd = BasicBlock::Create(f->getContext(), "loopEnd", f, insert);   // 创建一个代码块loopEnd, 也是空代码块
  loopEnd->setName("loopEntry");
  load = new LoadInst(switchVar, "switchVar", loopEntry);

  // 将这个基本块从当前函数中脱离,并将其插入loopEntry所在的函数中,并且移动到loopEntry之前。 insert块在前,loopEntry块在后;
  insert->moveBefore(loopEntry);
  // 在第一个基本块insert块末尾添加 无条件跳转到 loopEntry
  BranchInst::Create(loopEntry, insert);
  errs() <<"insertA  "<< *insert << "\n";
  
  // 无条件跳转到 loopEntry
  BranchInst::Create(loopEntry,  loopEnd);

  //再创建一个switchDefault块 无条件跳转到 loopEnd 
  BasicBlock *swDefault =  BasicBlock::Create(f->getContext(), "switchDefault", f, loopEnd);
  BranchInst::Create(loopEnd, swDefault);
  swDefault->setName("loopEntry");
  errs() <<"swDefault  "<< *swDefault << "\n";
  errs() <<"loopEndA  "<< *loopEnd << "\n";
  // 增加一条switch指令 比如 switch(xxx)
  switchI = SwitchInst::Create(&*f->begin(), swDefault, 0, loopEntry);
  switchI->setCondition(load);
  errs() <<"loopEntryA   "<< *loopEntry << "\n";

  

  // 第一个基本块脱离父节点的关系
  f->begin()->getTerminator()->eraseFromParent();
  //在该函数第一个基本块结尾 无条件跳转到loopEntry块指令。
  BranchInst::Create(loopEntry, &*f->begin());

  Function::iterator tmpA = f->begin(); 
  BasicBlock *begin = &*tmpA;
  //errs() <<"f->begin   "<< *begin << "\n";
  // 创建一个空的switch 语句  基本骨架 end

    // 开始往switch骨架代码中填充剩余的BasicBlock
  for (vector<BasicBlock *>::iterator b = origBB.begin(); b != origBB.end();
       ++b) {
    BasicBlock *i = *b;
    ConstantInt *numCase = NULL;

    // 把当前的基本块移动到loopEnd之前 (only visual, no code logic)
    i->moveBefore(loopEnd);

    // 通过 scramble32 生成一个随机值 该值与aes的常量key有关 
    // 参数1 int 右移值 scrambling_key 异或的key
    numCase = cast<ConstantInt>(ConstantInt::get( switchI->getCondition()->getType(), llvm::cryptoutils->scramble32(switchI->getNumCases(), scrambling_key)));
    //errs() <<"numCase "<< numCase << "\n";
    // 在switch 中 添加case语句 为每个基本块设置一个case值
    switchI->addCase(numCase, i);
  }
  errs() <<"switchI"<< *switchI << "\n";
  //基本骨架 逻辑处理完毕 但是只是一个空家骨架  switchVar 也没有再继续赋值 当前switch 还是一个死循环



  // 3 处理switch case 逻辑
  for (vector<BasicBlock *>::iterator b = origBB.begin(); b != origBB.end();  ++b) 
  {
    BasicBlock *i = *b;
    ConstantInt *numCase = NULL;

    //  没有后继块直接 continue
    if (i->getTerminator()->getNumSuccessors() == 0) 
    {
      continue;
    }

    // 获取最后一条指令 如果br 该基本块只有一个后继块
    if (i->getTerminator()->getNumSuccessors() == 1) 
    {
      BasicBlock *succ = i->getTerminator()->getSuccessor(0);
      BranchInst *brA = cast<BranchInst>(i->getTerminator());
      //errs() <<"getTerminator  br    "<< *brA << "\n";
   
      i->getTerminator()->eraseFromParent();
   

      // 查找给定后继块的唯一caseVar
      numCase = switchI->findCaseDest(succ);
      //findCaseDest numCase   0xa1382f0
      errs() <<"findCaseDest numCase   "<< numCase << "\n";
       // If next case == default case (switchDefault)
      if (numCase == NULL) {
        numCase = cast<ConstantInt>(
            ConstantInt::get(switchI->getCondition()->getType(),
                             llvm::cryptoutils->scramble32(
                                 switchI->getNumCases() - 1, scrambling_key)));
      }

      // 更新 switchVar 的值 即:switch = numCase(2015464572)等再跳转到loopEntry 里面根据switchVar能直接跳转到 succ块 label %24
 
 
      new StoreInst(numCase, load->getPointerOperand(), i);
      //无条件跳转到loopEnd
      BranchInst::Create(loopEnd, i);
      continue;
    }

    //如果有两个后继块
    if (i->getTerminator()->getNumSuccessors() == 2) {
      // 获取两个后继块
    
      errs() <<"BasicBlock Parent double   "<< *i << "\n";
      ConstantInt *numCaseTrue = switchI->findCaseDest(i->getTerminator()->getSuccessor(0));
      ConstantInt *numCaseFalse = switchI->findCaseDest(i->getTerminator()->getSuccessor(1));
      errs() <<"BasicBlock  doubleA   "<< *i->getTerminator()->getSuccessor(0) << "\n";
      errs() <<"BasicBlock  doubleB   "<< *i->getTerminator()->getSuccessor(1) << "\n";
      // Check if next case == default case (switchDefault)
      if (numCaseTrue == NULL) 
      {
        numCaseTrue = cast<ConstantInt>(  ConstantInt::get(switchI->getCondition()->getType(), llvm::cryptoutils->scramble32( switchI->getNumCases() - 1, scrambling_key)));
      }

      if (numCaseFalse == NULL) 
      {
        numCaseFalse = cast<ConstantInt>( ConstantInt::get(switchI->getCondition()->getType(), llvm::cryptoutils->scramble32( switchI->getNumCases() - 1, scrambling_key)));
      }

   
      // 创建一个选择分支
      //br->getCondition()为True跳转到numCaseTrue 否则跳转到numCaseFalse
      BranchInst *br = cast<BranchInst>(i->getTerminator());
      SelectInst *sel = SelectInst::Create(br->getCondition(), numCaseTrue, numCaseFalse, "", i->getTerminator());

      // Erase terminator
      i->getTerminator()->eraseFromParent();

      new StoreInst(sel, load->getPointerOperand(), i);
      BranchInst::Create(loopEnd, i);
      continue;
    }
    //处理switch case 逻辑 完毕


  }


  fixStack(f);
  return true;
}

pass 代码我都加了注释 

下面解释一下代码具体实现流程

1 生成随机的key 

既然是switch case打乱分发 ,case 的key自然少不了 

  //生成随机数key case
  char scrambling_key[16];
  llvm::cryptoutils->get_bytes(scrambling_key, 16);

2 遍历函数所有BasicBlock,并保存到origBB 数组中 

   这里保存是为了后续操作基本块做准备 , 

for (Function::iterator i = f->begin(); i != f->end(); ++i) 
  {
    BasicBlock *tmp = &*i;
    origBB.push_back(tmp);
    index++;
    //errs() <<"origBB "<< *tmp << "\n"; 

    //末尾是一条Invoke指令 返回
    /*
      try {
        foo();
      } catch (MyError err) 
      {
      }

      IR
       %4 = alloca %struct.MyError, align 1
       invoke void @_Z3foov()
          to label %5 unwind label %6
    */
    BasicBlock *bb = &*i;
    if (isa<InvokeInst>(bb->getTerminator())) {
      return false;
    }
  }
  errs() <<"origBB count  "<< index << "\n";

  //基本款太少 不平坦化
  if (origBB.size() <= 1) {
    return false;
  }
  // 去掉第一个基本块 第一块是函数的入口块,顺序不能乱
  origBB.erase(origBB.begin());

  //1 本函数第一个基本块的处理
  Function::iterator tmp = f->begin();  //++tmp;
  BasicBlock *insert = &*tmp;

  errs() <<"firstblock   "<< *insert << "\n";
  // 如果是分支指令 br cmp
  //getTerminator 如果区块结构完整,则返回终止指令,如果区块结构不完整,则返回空。
  BranchInst *br = NULL;
  if (isa<BranchInst>(insert->getTerminator())) 
  {
    br = cast<BranchInst>(insert->getTerminator());
  }
  //isConditional 如果是有条件跳转分支指令 或者如果该跳转分支有两个后继块 则进行分割  比如 br i1 %3, label %4, label %13
  if ((br != NULL && br->isConditional()) || insert->getTerminator()->getNumSuccessors() > 1) 
  {
    BasicBlock::iterator i = insert->end();
	  --i;

    if (insert->size() > 1) 
    {
      --i;
    }
    //从倒数第二条指令 开始分割基本块
    BasicBlock *tmpBB = insert->splitBasicBlock(i, "first");
    errs() <<"firstblock tmpBB  "<< *tmpBB << "\n";
    origBB.insert(origBB.begin(), tmpBB);
  }
  // 脱离父节点的关系
  insert->getTerminator()->eraseFromParent();

3 创建一个switch case 

大致的逻辑就

1 创建一个控的switvh 语句

2 放入基本块

3 为每一个基本块都添加一个casevalue 这样就可以标记每个基本块了


; <label>:36:                                     ; preds = %11, %22
  store i32 10, i32* %6, align 4, !dbg !248
  store i32 -1325218060, i32* %9 //添加casevalue
  br label %45
 // 创建一个空的switch 语句  基本骨架
    /*
     伪代码表示
     begin第一基本块
     {
        XXXX
        XXXX
        XXXX
        loopEntry()
     }
     int switchVar
     loopEntry()
     {
      
          switch(switchVar) 
          {
            case 3:
              origBB[0]
              
            case 4:
              origBB[1]
              
             ....
             switchDefault:
                loopEnd()
                break;
          }
     }

     loopEnd()
     {
        loopEntry()
     }

  */
  // 利用AllocaInst分配一个空间给switchVar
  switchVar = new AllocaInst(Type::getInt32Ty(f->getContext()), 0, "switchVar", insert);
  // 为switchVar变量赋一个伪随机值
  new StoreInst( ConstantInt::get(Type::getInt32Ty(f->getContext()), llvm::cryptoutils->scramble32(0, scrambling_key)), switchVar, insert);
 
  // 2 创建一个代码块loopEntry, 空代码块
  loopEntry = BasicBlock::Create(f->getContext(), "loopEntry", f, insert);
  loopEntry->setName("loopEntry");
  loopEnd = BasicBlock::Create(f->getContext(), "loopEnd", f, insert);   // 创建一个代码块loopEnd, 也是空代码块
  loopEnd->setName("loopEntry");
  load = new LoadInst(switchVar, "switchVar", loopEntry);

  // 将这个基本块从当前函数中脱离,并将其插入loopEntry所在的函数中,并且移动到loopEntry之前。 insert块在前,loopEntry块在后;
  insert->moveBefore(loopEntry);
  // 在第一个基本块insert块末尾添加 无条件跳转到 loopEntry
  BranchInst::Create(loopEntry, insert);
 
  // 无条件跳转到 loopEntry
  BranchInst::Create(loopEntry,  loopEnd);

  //再创建一个switchDefault块 无条件跳转到 loopEnd 
  BasicBlock *swDefault =  BasicBlock::Create(f->getContext(), "switchDefault", f, loopEnd);
  BranchInst::Create(loopEnd, swDefault);
  swDefault->setName("loopEntry");
  errs() <<"swDefault  "<< *swDefault << "\n";
  errs() <<"loopEndA  "<< *loopEnd << "\n";
  // 增加一条switch指令 比如 switch(xxx)
  switchI = SwitchInst::Create(&*f->begin(), swDefault, 0, loopEntry);
  switchI->setCondition(load);


  // 第一个基本块脱离父节点的关系
  f->begin()->getTerminator()->eraseFromParent();
  //在该函数第一个基本块结尾 无条件跳转到loopEntry块指令。
  BranchInst::Create(loopEntry, &*f->begin());

  Function::iterator tmpA = f->begin(); 
  BasicBlock *begin = &*tmpA;
  //errs() <<"f->begin   "<< *begin << "\n";
  // 创建一个空的switch 语句  基本骨架 end

    // 开始往switch骨架代码中填充剩余的BasicBlock
  for (vector<BasicBlock *>::iterator b = origBB.begin(); b != origBB.end();
       ++b) {
    BasicBlock *i = *b;
    ConstantInt *numCase = NULL;

    // 把当前的基本块移动到loopEnd之前 (only visual, no code logic)
    i->moveBefore(loopEnd);

    // 通过 scramble32 生成一个随机值  
    // 参数1 int 右移值 scrambling_key 异或的key
    numCase = cast<ConstantInt>(ConstantInt::get( switchI->getCondition()->getType(), llvm::cryptoutils->scramble32(switchI->getNumCases(), scrambling_key)));
    //errs() <<"numCase "<< numCase << "\n";
    // 在switch 中 添加case语句 为每个基本块设置一个case值
    switchI->addCase(numCase, i);
  }
  errs() <<"switchI"<< *switchI << "\n";
  //基本骨架 逻辑处理完毕 但是只是一个空家骨架  switchVar 也没有再继续赋值 当前switch 还是一个死循环

打印switch IR 如下 

switchI  switch i32 %12, label %13 [
    i32 440379866, label %14
    i32 1930663248, label %16
    i32 471975823, label %18
    i32 1974666478, label %20
    i32 -1329156448, label %22
    i32 -664800156, label %24
    i32 1746943394, label %26
    i32 253656417, label %28
    i32 -247427635, label %30
    i32 1081079450, label %31
    i32 -2031450923, label %32
    i32 -866414378, label %36
    i32 -1610036424, label %37
    i32 -595102341, label %38
    i32 -796366667, label %44
  ]

4 处理switch 基本块br逻辑 

如果有的基本块遇到br逻辑具体要怎么处理这些逻辑呢 ?

因为如果不处理br 就跳转走了,我们的case就控制不了分发 ,就违背了我们原来的意思 对吧!

处理方式://伪代码表现形式

//伪代码表现形式
     int switchVar
     loopEntry()
     {
      
          switch(switchVar) 
          {
            case 3:
              origBB[0]
              if have 'br'
                 switchVar = 4
            case 4:
              origBB[1]
              if have 'br'
                 switchVar = 5
             ....
             switchDefault:
                loopEnd()
                break;
          }
     }

     loopEnd()
     {
        loopEntry()
     }

处理逻辑 就是 把基本块 最后的br  脱离一下不让函数自己去跳转 而是根据我们的case 去跳转

比如 有个基本块 后面跟着一个br 执行完毕之后  br会跳转到  ; <label>:24:    

  ; <label>:20:                                     ; preds = %11, %18
          store i32 10, i32* %5, align 4, !dbg !249
          br label %24, !dbg !251

 这时候我们就要处理一下 先脱离 

 i->getTerminator()->eraseFromParent();
    ; <label>:20:                                     ; preds = %11, %18
          store i32 10, i32* %5, align 4, !dbg !249

以上是脱离之后的效果 可以看到 br 已经没有了 那原本的br label %24 ,

那之后要怎么处理呢?

通过一下代码 我们在 基本块的最后添加一个 casevaluse  让switch去处理

new StoreInst(numCase, load->getPointerOperand(), i);

添加casevalue后的IR代码 

  ; <label>:20:                                     ; preds = %11, %18
          store i32 10, i32* %5, align 4, !dbg !249
          store i32 -664800156, i32* %10

 前面我们也提到在在创建的switch的时候就已经为每个基本块添加了casevalue了

记住这个值 -664800156其实他在我们创建的时候已经跟br label %24 关联上了

// 3 处理switch case 逻辑
  for (vector<BasicBlock *>::iterator b = origBB.begin(); b != origBB.end();  ++b) 
  {
    BasicBlock *i = *b;
    ConstantInt *numCase = NULL;

    //  没有后继块直接 continue
    if (i->getTerminator()->getNumSuccessors() == 0) 
    {
      continue;
    }

    // 获取最后一条指令 如果br 该基本块只有一个后继块
    if (i->getTerminator()->getNumSuccessors() == 1) 
    {
      BasicBlock *succ = i->getTerminator()->getSuccessor(0);
      BranchInst *brA = cast<BranchInst>(i->getTerminator());
   
      i->getTerminator()->eraseFromParent();
   
 
      errs() <<"succ   "<< *succ << "\n";
      // 查找给定后继块的唯一caseVar
      numCase = switchI->findCaseDest(succ);
      //findCaseDest numCase   0xa1382f0
      errs() <<"findCaseDest numCase   "<< numCase << "\n";
       // If next case == default case (switchDefault)
      if (numCase == NULL) {
        numCase = cast<ConstantInt>(
            ConstantInt::get(switchI->getCondition()->getType(),
                             llvm::cryptoutils->scramble32(
                                 switchI->getNumCases() - 1, scrambling_key)));
      }

      // 更新 switchVar 的值 即:switch = numCase(2015464572)等再跳转到loopEntry 里面根据switchVar能直接跳转到 succ块 label %24
  


      new StoreInst(numCase, load->getPointerOperand(), i);
      errs() <<"add  numCase block  "<< *i << "\n";
      //无条件跳转到loopEnd
      BranchInst::Create(loopEnd, i);
      continue;
    }

    //如果有两个后继块
    if (i->getTerminator()->getNumSuccessors() == 2) {
      // 获取两个后继块
  
      errs() <<"BasicBlock Parent double   "<< *i << "\n";
      ConstantInt *numCaseTrue = switchI->findCaseDest(i->getTerminator()->getSuccessor(0));
      ConstantInt *numCaseFalse = switchI->findCaseDest(i->getTerminator()->getSuccessor(1));
      errs() <<"BasicBlock  doubleA   "<< *i->getTerminator()->getSuccessor(0) << "\n";
      errs() <<"BasicBlock  doubleB   "<< *i->getTerminator()->getSuccessor(1) << "\n";
      // Check if next case == default case (switchDefault)
      if (numCaseTrue == NULL) 
      {
        numCaseTrue = cast<ConstantInt>(  ConstantInt::get(switchI->getCondition()->getType(), llvm::cryptoutils->scramble32( switchI->getNumCases() - 1, scrambling_key)));
      }

      if (numCaseFalse == NULL) 
      {
        numCaseFalse = cast<ConstantInt>( ConstantInt::get(switchI->getCondition()->getType(), llvm::cryptoutils->scramble32( switchI->getNumCases() - 1, scrambling_key)));
      }

   
      // 创建一个选择分支
      //br->getCondition()为True跳转到numCaseTrue 否则跳转到numCaseFalse
      BranchInst *br = cast<BranchInst>(i->getTerminator());
      SelectInst *sel = SelectInst::Create(br->getCondition(), numCaseTrue, numCaseFalse, "", i->getTerminator());

      // Erase terminator
      i->getTerminator()->eraseFromParent();

      new StoreInst(sel, load->getPointerOperand(), i);
      BranchInst::Create(loopEnd, i);
      continue;
    }
    //处理switch case 逻辑 完毕

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值