OLLVM控制流平坦化以及指令替换(基础工具)

一个比较专业的具体解答博客(ENGLISH)

[D810: Creating an extensible deobfuscation plugin for IDA Pro (eshard.com)

基于llvm[LLVM基本概念入门-CSDN博客](https://blog.csdn.net/SiberiaBear/article/details/103111028?ops_request_misc=%7B%22request%5Fid%22%3A%22170287063316800180624113%22%2C%22scm%22%3A%2220140713.130102334..%22%7D&request_id=170287063316800180624113&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-1-103111028-null-null.142v96pc_search_result_base6&utm_term=llvm&spm=1018.2226.3001.4187)

1.控制流平坦化概述

一种代码混淆

1.原理:

通过添加发你发起来控制流程的而执行

反混淆思路

2.动态:

通过Unicorn模拟执行的方式获得各种真实块的关系

3.静态:

通过符号执行,中间语言的分析的方式获取真实块之间的俄关系

4.简述执行思路

OLLVM会添加一个用于控制跳转的状态变量和分发器

当一个真实块执行完成后,会把状态变量的值进行更新

回到分发器进行检查,再根据状态变量的值跳转到下一个真实块执行OLLVM

1.概述

1.简述

一种程序优化的技术

将复杂的控制流程装华为简单的顺序执行流程

从而提高执行效率

2.简单例子

原始程序

if (x >0) {
y = 1;
} else {
y = -1;
}
z = y * y;

平坦化优化后


y = (x > 0) ? 1 : -1;
z = y * y;

将if 语句转化为三目运算符,执行会更快

3.专业解释

将原始的分支语句的而每一个分支提取出来,并放在一系列连续的基本块当中

然后使用一个状态变量或者标志选择执行的基本快

2.原理

1.流程

  1. 将原始的条件语句拆违独立基本块
  2. 将基本块按照一定的顺序排列在一起,形成新的流程
  3. 添加如条件语句或跳转指令,根据不同基本块的而标志来选择执行
  4. 在每个基本快的末尾甚至标志,用于确认下一个要执行的基本块

2.基本块

1.序言的地址:

函数开始的地方

2.主分发器:

序言的后继

3.真实块:

后继为预处理器

4.rent块:

无后继的块

5.其余为无用块

3.反混淆思路

1.识别FLA混淆

在这里插入图片描述

2.实操步骤,利用angr去除FLA控制流混淆

1.构建bloks,找出块之间的关系

找出真实块

2.符号执行,遍历所有blocks,找出映射关系

找出真实块的执行顺序

3.利用nop或者跳转指令(patch程序)

还原控制流混淆

4.利用angr工具实操

1.再github上面下载angr

https://github.com/cq674350529/deflat

注意:

文件夹外面要保证三个.py文件在外面

deflat.py

unli.py

an angr.py

2.将那个要去平坦化的文件拖到那个deflat的文件下

3.再搜索框下面输入cmd调出终端

4.输入

python+deflat+文件名称+函数开始的地址

5.得到那个新的recovered的文件

1.ollvm指令替换概述

1.ollvm整体框架

llvm框架

2.相关概念以及术语

1.IR(intermediate representation):

前端语言生成的中间代码表示

也是uass操作的对象

包括四部分:

  1. Module
  2. Function
  3. BasicBlock
Instruction

2.OLLVM有三个Pass以实现混淆(位于Transforms/Obfuscation/目录):

  1. Substitution
  2. BogusControlFlow
  3. flattening

3.实现指令代换的是

Pass里面的Substitution

1.替换

1.ADD
变换前变换后
a=b+ca=b-(-c)
a=b+ca= -(-b + (-c))
a=b+cr = rand (); a = b + r; a = a + c;a = a – r
a=b+cr = rand (); a = b – r; a = a + b; a = a + r
2.SUB
变换前变换后
a=b-ca=b+(-c)
a=b-cr = rand (); a = b + r; a = a – c;a = a – r
a=b-cr = rand (); a = b – r; a = a -c;a = a + r
3.AND
变换前变换后
a=b&ca=(b^~c)&b
a=a&b!(!a | !b) & (r | !r)
4.OR
变换前变换后
a=b|ca=(b&c)|(b^c)
a|b[(!a & r) | (a & !r) ^ (!b & r) |(b & !r) ] | [!(!a | !b) & (r |!r)]
5.XOR
变换前变换后
a=a^ba = (!a & b) | (a & !b)
a=a^b(a ^ r) ^ (b ^ r)或(!a & r | a & !r) ^ (!b & r | b & !r)
6.命令
命令解析
-mllvm -sub激活指令替换
-mllvm -sub_loop=3若已被激活,进行3次替换,默认为1
-mllvm -sub激活指令替换
-mllvm -sub_loop若激活了指令替换,在函数中应用指令替换的次数

4.代码实现分析

1.整体代码

namespace {

struct Substitution : public FunctionPass {
 static char ID; // Pass identification, replacement for typeid
 void (Substitution::*funcAdd[NUMBER_ADD_SUBST])(BinaryOperator *bo);
 void (Substitution::*funcSub[NUMBER_SUB_SUBST])(BinaryOperator *bo);
 void (Substitution::*funcAnd[NUMBER_AND_SUBST])(BinaryOperator *bo);
 void (Substitution::*funcOr[NUMBER_OR_SUBST])(BinaryOperator *bo);
 void (Substitution::*funcXor[NUMBER_XOR_SUBST])(BinaryOperator *bo);
 bool flag;

 Substitution() : FunctionPass(ID) {}

 Substitution(bool flag) : FunctionPass(ID) {
   this->flag = flag;
   funcAdd[0] = &Substitution::addNeg;
   funcAdd[1] = &Substitution::addDoubleNeg;
   funcAdd[2] = &Substitution::addRand;
   funcAdd[3] = &Substitution::addRand2;

   funcSub[0] = &Substitution::subNeg;
   funcSub[1] = &Substitution::subRand;
   funcSub[2] = &Substitution::subRand2;

   funcAnd[0] = &Substitution::andSubstitution;
   funcAnd[1] = &Substitution::andSubstitutionRand;

   funcOr[0] = &Substitution::orSubstitution;
   funcOr[1] = &Substitution::orSubstitutionRand;

   funcXor[0] = &Substitution::xorSubstitution;
   funcXor[1] = &Substitution::xorSubstitutionRand;
}

 bool runOnFunction(Function &F);
 bool substitute(Function *f);

 void addNeg(BinaryOperator *bo);
 void addDoubleNeg(BinaryOperator *bo);
 void addRand(BinaryOperator *bo);
 void addRand2(BinaryOperator *bo);

 void subNeg(BinaryOperator *bo);
 void subRand(BinaryOperator *bo);
 void subRand2(BinaryOperator *bo);

 void andSubstitution(BinaryOperator *bo);
 void andSubstitutionRand(BinaryOperator *bo);

 void orSubstitution(BinaryOperator *bo);
 void orSubstitutionRand(BinaryOperator *bo);

 void xorSubstitution(BinaryOperator *bo);
 void xorSubstitutionRand(BinaryOperator *bo);
};
}//5个指针数组
1.Substitution(bool flag)函数进行初始化
3.Add对应4个处理函数
3.Sub对应3个处理函数
4.and对应2个处理函数
5.or对应2个处理函数
6.xor对应2个处理函数。

1.入口函数runOnFunction

bool Substitution::runOnFunction(Function &F) {
  // Check if the percentage is correct
  if (ObfTimes <= 0) {
    errs()<<"Substitution application number -sub_loop=x must be x > 0";
return false;
  }

 Function *tmp = &F;
 // Do we obfuscate
 if (toObfuscate(flag, tmp, "sub")) {
   substitute(tmp);
return true;
}

 return false;
}?/首先验证验证了 -mllvm -sub_loop=x这个编译参数的正确性,其必须大于0。使用toObfuscate(flag, tmp, “sub”)函数判断是否进行混淆,若满足条件,则需要调用substitute(tmp)函数进行指令替换

2.substitute函数

bool Substitution::substitute(Function *f) {
 Function *tmp = f;

 // Loop for the number of time we run the pass on the function
 int times = ObfTimes;
 do {
   for (Function::iterator bb = tmp->begin(); bb != tmp->end(); ++bb) {
     for (BasicBlock::iterator inst = bb->begin(); inst != bb->end(); ++inst) {
       if (inst->isBinaryOp()) {
         switch (inst->getOpcode()) {
         case BinaryOperator::Add:
           // case BinaryOperator::FAdd:
           // Substitute with random add operation
          (this->*funcAdd[llvm::cryptoutils->get_range(NUMBER_ADD_SUBST)])(
               cast<BinaryOperator>(inst));
           ++Add;
           break;
         case BinaryOperator::Sub:
           // case BinaryOperator::FSub:
           // Substitute with random sub operation
          (this->*funcSub[llvm::cryptoutils->get_range(NUMBER_SUB_SUBST)])(
               cast<BinaryOperator>(inst));
           ++Sub;
           break;
         case BinaryOperator::Mul:
         case BinaryOperator::FMul:
           //++Mul;
           break;
         case BinaryOperator::UDiv:
         case BinaryOperator::SDiv:
         case BinaryOperator::FDiv:
           //++Div;
           break;
         case BinaryOperator::URem:
         case BinaryOperator::SRem:
         case BinaryOperator::FRem:
           //++Rem;
           break;
         case Instruction::Shl:
           //++Shi;
           break;
         case Instruction::LShr:
           //++Shi;
           break;
         case Instruction::AShr:
           //++Shi;
           break;
         case Instruction::And:
          (this->*
            funcAnd[llvm::cryptoutils->get_range(2)])(cast<BinaryOperator>(inst));
           ++And;
           break;
         case Instruction::Or:
          (this->*
            funcOr[llvm::cryptoutils->get_range(2)])(cast<BinaryOperator>(inst));
           ++Or;
           break;
         case Instruction::Xor:
          (this->*
            funcXor[llvm::cryptoutils->get_range(2)])(cast<BinaryOperator>(inst));
           ++Xor;
           break;
         default:
           break;
        }              // End switch
      }                // End isBinaryOp
    }                  // End for basickblock
  }                    // End for Function
} while (--times > 0); // for times
 return false;
}//最外层的do…while循环是根据需要循环次数进行变换,内层两个for循环从外向内分别是遍历当前函数的所有代码块、遍历每个代码块的每条指令。内层if条件用于判断当前指令是否为二进制操作(isBinaryOp)。根据Opcode来判断是否需要执行替换操作,下分为Add, Sub, And, Or, Xor 5种操作。其中llvm::cryptoutils->get_range是一个随机函数,可以从之前定义的处理函数数组中随机选择一个处理函数

3.以Sub的处理函数subNeg(BinaryOperator *bo)为例

(其他四个函数变换过程类似)

// Implementation of a = b + (-c)
void Substitution::subNeg(BinaryOperator *bo) {
 BinaryOperator *op = NULL;

 if (bo->getOpcode() == Instruction::Sub) {
   op = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo);
   op =
       BinaryOperator::Create(Instruction::Add, bo->getOperand(0), op, "", bo);

   // Check signed wrap
   //op->setHasNoSignedWrap(bo->hasNoSignedWrap());
   //op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap());
} else {
   op = BinaryOperator::CreateFNeg(bo->getOperand(1), "", bo);
   op = BinaryOperator::Create(Instruction::FAdd, bo->getOperand(0), op, "",bo);
}

 bo->replaceAllUsesWith(op);
}//该函数将a=b-c变成a=b+(-c);
BinaryOperator::CreateNeg(bo->getOperand(1), “”, bo)指将c变成-c;BinaryOperator::Create(Instruction::Add, bo->getOperand(0), op, “”, bo)指b+(-c);
bo->replaceAllUsesWith(op)指更新老的操作数。

2.OLLVM指令的替换实操

  1. 下载d810-master
  2. 将d810文件夹和D810.py文件拖入ida的plugins文件夹
  3. 在ida里面edit的里面plugins的里面D-810
  4. 进入点击start进入后重新f5反编译
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇