ollvm源码分析之指令替换(1)
参考网站: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)相关推荐
- Nginx源码分析之 upstream指令
#Nginx 源码分析 upstream指令 想要的解决问题: 1:upstream存储结构 2:动态 upstream 流程(proxy_pass跟随变量或者域名) 最简单的配置文件 http {u ...
- 鸿蒙内核源码分析:调度机制篇
作者 | 深入研究鸿蒙,鸿蒙内核发烧友 出品 | CSDN(ID:CSDNnews) 头图 | CSDN 下载自东方 IC 阅读之前建议先读本系列其他文章,以便对本文任务调度机制的理解. 为什么要学这 ...
- Vue.js 源码分析(二十三) 指令篇 v-show指令详解
v-show的作用是将表达式值转换为布尔值,根据该布尔值的真假来显示/隐藏切换元素,它是通过切换元素的display这个css属性值来实现的,例如: <!DOCTYPE html> < ...
- 【Android 安全】DEX 加密 ( Application 替换 | Android 应用启动原理 | Instrumentation 源码分析 )
文章目录 一.Instrumentation 源码分析 二.Instrumentation 创建 Application 相关的部分源码 dex 解密时 , 需要将 代理 Application 替换 ...
- 【Android 安全】DEX 加密 ( Application 替换 | Android 应用启动原理 | LoadedApk 源码分析 )
文章目录 一.LoadedApk 源码分析 二.LoadedApk 源码 makeApplication 方法分析 dex 解密时 , 需要将 代理 Application 替换为 真实 Applic ...
- 【Android 安全】DEX 加密 ( Application 替换 | Android 应用启动原理 | ActivityThread 源码分析 )
文章目录 一.ActivityThread 源码分析 二.ActivityThread 部分代码示例 dex 解密时 , 需要将 代理 Application 替换为 真实 Application ; ...
- 【SA8295P 源码分析】44 - 如何替换 NON-HLOS.bin 中的 Wifi Firmware 固件
[SA8295P 源码分析]44 - 如何替换 NON-HLOS.bin 中的 Wifi Firmware 固件 1.提取 NON-HLOS.bin 中的 Wifi Firmware 出来 2.把提取 ...
- Java并发基础:了解无锁CAS就从源码分析
CAS的全称为Compare And Swap,直译就是比较交换.是一条CPU的原子指令,其作用是让CPU先进行比较两个值是否相等,然后原子地更新某个位置的值,其实现方式是基于硬件平台的汇编指令,在i ...
- Java并发基础:了解无锁CAS就从源码分析 1
CAS的全称为Compare And Swap,直译就是比较交换.是一条CPU的原子指令,其作用是让CPU先进行比较两个值是否相等,然后原子地更新某个位置的值,其实现方式是基于硬件平台的汇编指令,在i ...
- MyBatis 源码分析 - SQL 的执行过程
本文速览 本篇文章较为详细的介绍了 MyBatis 执行 SQL 的过程.该过程本身比较复杂,牵涉到的技术点比较多.包括但不限于 Mapper 接口代理类的生成.接口方法的解析.SQL 语句的解析.运 ...
最新文章
- rust投递箱连接箱子_灭火器箱存在的必要性
- C++ classics
- CSS样式让一个块在最上层中显示
- Spark 101:它是什么,它做什么以及为什么起作用
- Matlab画图技巧之保存超大体积图
- 苹果:确认开始在印度生产iPhone 13
- lua循环,减少不必要的循环
- 求出现重现次数最多的字母,如有多个反复的则都求出来
- 殷人昆数据结构第二版_从入门到拿offer,必须看的数据结构与算法书籍推荐,不好不推荐...
- honeywell Xenon TM 1900二维码扫描枪扫描不显示中文
- Notepad++ 安装XML Tools插件格式化XML文件
- C/C++描述 第十一届蓝桥杯省赛 C/C++ 大学C组 第一场(2020.7.5) 题目+题解
- 零 XML 多表联查
- 国家气象局免费天气预报接口,城市代码(JSON格式)
- MySQL的基本知识点,一千行命令概括
- Cannot run program python问题解决
- 云计算进入深水区, MSP才是政企用好云的生力军
- Linux下使用samba工具共享文件
- 如何给PDF文件添加自定义图章的方法
- 一个合格的初级前端工程师需要掌握的模块笔记
热门文章
- 如何安全地终止线程interrupt()、isInterrupted()、interrupted()的区别与使用
- String转LocalDateTime
- POI操作Excel详解,HSSF和XSSF两种方式
- JVM监控及诊断工具GUI篇之Eclipse MAT
- 为什么阿里巴巴禁止在foreach里进行元素的remove/add操作
- Spring源码之bean的属性填充populateBean方法解读
- Redis主从架构和哨兵架构模式
- DAY8-打卡第八天-2018-1-18
- Codeforces348B Apple Tree DFS
- Ubuntu各文件夹功能说明