参考网站:Obfuscator-llvm源码分析

ollvm

ollvm总体框架与llvm一致,如下图所示。

其中IR(intermediate representation)是前端语言生成的中间代码表示,也是Pass操作的对象,它包括四部分:

  • Module
  • Function
  • BasicBlock
  • Instruction

OLLVM有三个Pass以实现混淆,分别为Substitution、BogusControlFlow、flattening。它们位于Transforms/Obfuscation/目录。

Pass之Substitution

实现功能是:指令替换

1 替换

1.1 Add

变换前 变换后
a=b+c a=b-(-c)
a=b+c a= -(-b + (-c))
a=b+c r = rand (); a = b + r; a = a + c;a = a – r
a=b+c r = rand (); a = b - r; a = a + b; a = a + r

1.2 Sub

变换前 变换后
a=b-c a=b+(-c)
a=b-c r = rand (); a = b + r; a = a - c;a = a – r
a=b-c r = rand (); a = b - r; a = a -c;a = a + r

1.3 And

变换前 变换后
a=b&c a=(b^~c)&b
a=a&b !(!a | !b) & (r | !r)

1.4 Or

变换前 变换后
a=b|c a=(b&c)|(b^c)
a|b [(!a & r) | (a & !r) ^ (!b & r) |(b & !r) ] | [!(!a | !b) & (r |!r)]

1.5 Xor

变换前 变换后
a=a^b a = (!a & b) | (a & !b)
a=a^b (a ^ r) ^ (b ^ r)或(!a & r | a & !r) ^ (!b & r | b & !r)

1.6 命令

命令 解析
-mllvm -sub 激活指令替换
-mllvm -sub_loop=3 若已被激活,进行3次替换,默认为1

2 代码分析

namespace {struct Substitution : public FunctionPass {static char ID; // Pass identification, replacement for typeidvoid (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个指针数组,使用Substitution(bool flag)函数进行初始化。Add对应4个处理函数,Sub对应3个处理函数,and对应2个处理函数,or对应2个处理函数,xor对应2个处理函数。

2.1 入口函数 runOnFunction

继承FunctionPass,所以入口函数是runOnFunction。

bool Substitution::runOnFunction(Function &F) {// Check if the percentage is correctif (ObfTimes <= 0) {errs()<<"Substitution application number -sub_loop=x must be x > 0";return false;}Function *tmp = &F;// Do we obfuscateif (toObfuscate(flag, tmp, "sub")) {substitute(tmp);return true;}return false;
}

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

2.2 substitute函数

bool Substitution::substitute(Function *f) {Function *tmp = f;// Loop for the number of time we run the pass on the functionint 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 timesreturn false;
}

最外层的do…while循环是根据需要循环次数进行变换,内层两个for循环从外向内分别是遍历当前函数的所有代码块、遍历每个代码块的每条指令。内层if条件用于判断当前指令是否为二进制操作(isBinaryOp)。根据Opcode来判断是否需要执行替换操作,下分为Add, Sub, And, Or, Xor 5种操作。其中llvm::cryptoutils->get_range是一个随机函数,可以从之前定义的处理函数数组中随机选择一个处理函数。

下面我们选择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)指更新老的操作数。

ollvm源码分析之指令替换(1)相关推荐

  1. Nginx源码分析之 upstream指令

    #Nginx 源码分析 upstream指令 想要的解决问题: 1:upstream存储结构 2:动态 upstream 流程(proxy_pass跟随变量或者域名) 最简单的配置文件 http {u ...

  2. 鸿蒙内核源码分析:调度机制篇

    作者 | 深入研究鸿蒙,鸿蒙内核发烧友 出品 | CSDN(ID:CSDNnews) 头图 | CSDN 下载自东方 IC 阅读之前建议先读本系列其他文章,以便对本文任务调度机制的理解. 为什么要学这 ...

  3. Vue.js 源码分析(二十三) 指令篇 v-show指令详解

    v-show的作用是将表达式值转换为布尔值,根据该布尔值的真假来显示/隐藏切换元素,它是通过切换元素的display这个css属性值来实现的,例如: <!DOCTYPE html> < ...

  4. 【Android 安全】DEX 加密 ( Application 替换 | Android 应用启动原理 | Instrumentation 源码分析 )

    文章目录 一.Instrumentation 源码分析 二.Instrumentation 创建 Application 相关的部分源码 dex 解密时 , 需要将 代理 Application 替换 ...

  5. 【Android 安全】DEX 加密 ( Application 替换 | Android 应用启动原理 | LoadedApk 源码分析 )

    文章目录 一.LoadedApk 源码分析 二.LoadedApk 源码 makeApplication 方法分析 dex 解密时 , 需要将 代理 Application 替换为 真实 Applic ...

  6. 【Android 安全】DEX 加密 ( Application 替换 | Android 应用启动原理 | ActivityThread 源码分析 )

    文章目录 一.ActivityThread 源码分析 二.ActivityThread 部分代码示例 dex 解密时 , 需要将 代理 Application 替换为 真实 Application ; ...

  7. 【SA8295P 源码分析】44 - 如何替换 NON-HLOS.bin 中的 Wifi Firmware 固件

    [SA8295P 源码分析]44 - 如何替换 NON-HLOS.bin 中的 Wifi Firmware 固件 1.提取 NON-HLOS.bin 中的 Wifi Firmware 出来 2.把提取 ...

  8. Java并发基础:了解无锁CAS就从源码分析

    CAS的全称为Compare And Swap,直译就是比较交换.是一条CPU的原子指令,其作用是让CPU先进行比较两个值是否相等,然后原子地更新某个位置的值,其实现方式是基于硬件平台的汇编指令,在i ...

  9. Java并发基础:了解无锁CAS就从源码分析 1

    CAS的全称为Compare And Swap,直译就是比较交换.是一条CPU的原子指令,其作用是让CPU先进行比较两个值是否相等,然后原子地更新某个位置的值,其实现方式是基于硬件平台的汇编指令,在i ...

  10. MyBatis 源码分析 - SQL 的执行过程

    本文速览 本篇文章较为详细的介绍了 MyBatis 执行 SQL 的过程.该过程本身比较复杂,牵涉到的技术点比较多.包括但不限于 Mapper 接口代理类的生成.接口方法的解析.SQL 语句的解析.运 ...

最新文章

  1. rust投递箱连接箱子_灭火器箱存在的必要性
  2. C++ classics
  3. CSS样式让一个块在最上层中显示
  4. Spark 101:它是什么,它做什么以及为什么起作用
  5. Matlab画图技巧之保存超大体积图
  6. 苹果:确认开始在印度生产iPhone 13
  7. lua循环,减少不必要的循环
  8. 求出现重现次数最多的字母,如有多个反复的则都求出来
  9. 殷人昆数据结构第二版_从入门到拿offer,必须看的数据结构与算法书籍推荐,不好不推荐...
  10. honeywell Xenon TM 1900二维码扫描枪扫描不显示中文
  11. Notepad++ 安装XML Tools插件格式化XML文件
  12. C/C++描述 第十一届蓝桥杯省赛 C/C++ 大学C组 第一场(2020.7.5) 题目+题解
  13. 零 XML 多表联查
  14. 国家气象局免费天气预报接口,城市代码(JSON格式)
  15. MySQL的基本知识点,一千行命令概括
  16. Cannot run program python问题解决
  17. 云计算进入深水区, MSP才是政企用好云的生力军
  18. Linux下使用samba工具共享文件
  19. 如何给PDF文件添加自定义图章的方法
  20. 一个合格的初级前端工程师需要掌握的模块笔记

热门文章

  1. 如何安全地终止线程interrupt()、isInterrupted()、interrupted()的区别与使用
  2. String转LocalDateTime
  3. POI操作Excel详解,HSSF和XSSF两种方式
  4. JVM监控及诊断工具GUI篇之Eclipse MAT
  5. 为什么阿里巴巴禁止在foreach里进行元素的remove/add操作
  6. Spring源码之bean的属性填充populateBean方法解读
  7. Redis主从架构和哨兵架构模式
  8. DAY8-打卡第八天-2018-1-18
  9. Codeforces348B Apple Tree DFS
  10. Ubuntu各文件夹功能说明