参考网站:ollvm源码分析
参考网站:Obufuscator-llvm源码分析

Pass之flattening

实现功能是:增加switch-case语句,使其扁平化。

1 命令

命令 解析
-mllvm -fla 激活控制流扁平化

2 代码分析

2.1 入口函数runOnFunction

Flattening继承了FunctionPass,因此它的入口函数即为runOnFunction。

bool Flattening::runOnFunction(Function &F) {Function *tmp = &F;// Do we obfuscateif (toObfuscate(flag, tmp, "fla")) {if (flatten(tmp)) {++Flattened;}}return false;
}

toObfuscate函数判断是否启动了fla命令,判断完毕,再调用flatten函数。

2.1 flatten函数

vector<BasicBlock *> origBB;
for (Function::iterator i = f->begin(); i != f->end(); ++i) {BasicBlock *tmp = &*i;origBB.push_back(tmp);BasicBlock *bb = &*i;if (isa<InvokeInst>(bb->getTerminator())) {return false;}}
// Nothing to flatten
if (origBB.size() <= 1) {return false;
}// Remove first BB
origBB.erase(origBB.begin());

除了first BB,将所有基本块存储到vector容器origBB中,若origBB中不止一个基本块才进行后续处理。

// Get a pointer on the first BB
Function::iterator tmp = f->begin();  //++tmp;
BasicBlock *insert = &*tmp;
// If main begin with an if
BranchInst *br = NULL;
if (isa<BranchInst>(insert->getTerminator())) {br = cast<BranchInst>(insert->getTerminator());
}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");origBB.insert(origBB.begin(), tmpBB);
}
// Remove jump
insert->getTerminator()->eraseFromParent();

若first BB未尾有条件跳转指令,获取该指令地址。通过splitBasicBlock将该块分为first BB与tmpBB,将tmpBB存储到origBB中。去除第一个基本块与下一个基本块间的跳转关系。

switchVar = new AllocaInst(Type::getInt32Ty(f->getContext()), 0,"switchVar", insert);
new StoreInst(ConstantInt::get(Type::getInt32Ty(f->getContext()),llvm::cryptoutils->scramble32(0, scrambling_key)),switchVar, insert);

创建switch变量并且初始化。

// Create main looploopEntry = BasicBlock::Create(f->getContext(), "loopEntry", f, insert);loopEnd = BasicBlock::Create(f->getContext(), "loopEnd", f, insert);load = new LoadInst(switchVar, "switchVar", loopEntry);// Move first BB on topinsert->moveBefore(loopEntry);BranchInst::Create(loopEntry, insert);// loopEnd jump to loopEntryBranchInst::Create(loopEntry, loopEnd);BasicBlock *swDefault =BasicBlock::Create(f->getContext(), "switchDefault", f, loopEnd);BranchInst::Create(loopEnd, swDefault);// Create switch instruction itself and set conditionswitchI = SwitchInst::Create(&*f->begin(), swDefault, 0, loopEntry);switchI->setCondition(load);

创建两个基本块loopEntry 、loopEnd。将first BB移至loopEntry 前面,创建loopEnd到时loopEntry 的跳转。创建swDefault 块,swDefault跳转到loopEnd,loopEntry 跳转到swDefault。

 f->begin()->getTerminator()->eraseFromParent();BranchInst::Create(loopEntry, &*f->begin());

删除first BB的跳转,将first BB跳转至loopEntry。

 // Put all BB in the switchfor (vector<BasicBlock *>::iterator b = origBB.begin(); b != origBB.end();++b) {BasicBlock *i = *b;ConstantInt *numCase = NULL;// Move the BB inside the switch (only visual, no code logic)i->moveBefore(loopEnd);// Add case to switchnumCase = cast<ConstantInt>(ConstantInt::get(switchI->getCondition()->getType(),llvm::cryptoutils->scramble32(switchI->getNumCases(), scrambling_key)));switchI->addCase(numCase, i);}

所有基本块加入switch中。

// Recalculate switchVarfor (vector<BasicBlock *>::iterator b = origBB.begin(); b != origBB.end();++b) {BasicBlock *i = *b;ConstantInt *numCase = NULL;// Ret BBif (i->getTerminator()->getNumSuccessors() == 0) {continue;}// If it's a non-conditional jumpif (i->getTerminator()->getNumSuccessors() == 1) {// Get successor and delete terminatorBasicBlock *succ = i->getTerminator()->getSuccessor(0);i->getTerminator()->eraseFromParent();// Get next casenumCase = switchI->findCaseDest(succ);// 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)));}// Update switchVar and jump to the end of loopnew StoreInst(numCase, load->getPointerOperand(), i);BranchInst::Create(loopEnd, i);continue;}// If it's a conditional jumpif (i->getTerminator()->getNumSuccessors() == 2) {// Get next casesConstantInt *numCaseTrue =switchI->findCaseDest(i->getTerminator()->getSuccessor(0));ConstantInt *numCaseFalse =switchI->findCaseDest(i->getTerminator()->getSuccessor(1));// 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)));}// Create a SelectInstBranchInst *br = cast<BranchInst>(i->getTerminator());SelectInst *sel =SelectInst::Create(br->getCondition(), numCaseTrue, numCaseFalse, "",i->getTerminator());// Erase terminatori->getTerminator()->eraseFromParent();// Update switchVar and jump to the end of loopnew StoreInst(sel, load->getPointerOperand(), i);BranchInst::Create(loopEnd, i);continue;}}

修改每个基本块之间的跳转关系,使得每个基本块执行完毕会重新设置switchVar 的值。从而回到switch并顺利跳转到下一个case,直到程序结束。
处理后的基本块间的关系图如下图所示。

ollvm源码分析之控制流扁平化(3)相关推荐

  1. 从源码分析线程池(池化技术)的实现原理

    线程池是一个非常重要的知识点,也是池化技术的一个典型应用,相信很多人都有使用线程池的经历,但是对于线程池的实现原理大家都了解吗?本篇文章我们将深入线程池源码来一探究竟. 线程池的起源 背景: 随着计算 ...

  2. 【Android 插件化】VirtualApp 源码分析 ( 目前的 API 现状 | 安装应用源码分析 | 安装按钮执行的操作 | 返回到 HomeActivity 执行的操作 )

    文章目录 一.目前的 API 现状 二.安装应用源码分析 1.安装按钮执行的操作 2.返回到 HomeActivity 执行的操作 一.目前的 API 现状 下图是 VirtualApp 官方给出的集 ...

  3. 【Android 插件化】VirtualApp 源码分析 ( 启动应用源码分析 | HomePresenterImpl 启动应用方法 | VirtualCore 启动插件应用最终方法 )

    文章目录 一.启动应用源码分析 1.HomeActivity 启动应用点击方法 2.HomePresenterImpl 启动应用方法 3.VirtualCore 启动插件应用最终方法 一.启动应用源码 ...

  4. 【Android 插件化】VirtualApp 源码分析 ( 添加应用源码分析 | LaunchpadAdapter 适配器 | 适配器添加元素 | PackageAppData 元素 )

    文章目录 一.添加应用源码分析 1.LaunchpadAdapter 适配器 2.适配器添加元素 3.PackageAppData 元素 一.添加应用源码分析 1.LaunchpadAdapter 适 ...

  5. 【Android 插件化】VirtualApp 源码分析 ( 安装应用源码分析 | HomePresenterImpl 添加应用 | AppRepository.addVirtualApp )

    文章目录 一.安装应用源码分析 1.HomePresenterImpl 添加应用 2.AppRepository.addVirtualApp 安装 SD 卡 APK 应用 一.安装应用源码分析 1.H ...

  6. PostgreSQL源码分析

    PostgreSQL源码结构 PostgreSQL的使用形态 PostgreSQL采用C/S(客户机/服务器)模式结构.应用层通过INET或者Unix Socket利用既定的协议与数据库服务器进行通信 ...

  7. 【转】ABP源码分析二十一:Feature

    Feature是什么?Feature就是对function分类的方法,其与function的关系就比如Role和User的关系一样. ABP中Feature具有以下属性: 其中最重要的属性是name, ...

  8. [源码分析] 从FlatMap用法到Flink的内部实现

    [源码分析] 从FlatMap用法到Flink的内部实现 0x00 摘要 本文将从FlatMap概念和如何使用开始入手,深入到Flink是如何实现FlatMap.希望能让大家对这个概念有更深入的理解. ...

  9. bytebuddy实现原理分析 源码分析 (三)- advice 详解

    advice详解 八.advice 8.1 AsmVisitorWrapper 8.1.1 ForDeclareFields 8.1.1.1 Entry 8.1.1.2 DispatchingVisi ...

  10. GCC源码分析(十六) — gimple转RTL(pass_expand)(下)

    版权声明:本文为CSDN博主「ashimida@」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明. 原文链接:https://blog.csdn.net/lidan1 ...

最新文章

  1. hdu1428 spfa+记忆化搜索
  2. 【.NET Core 跨平台 GUI 开发】第一篇:编写你的第一个 Gtk# 应用
  3. C#:如何将坏的代码重新编译为好的代码
  4. flume的配置和开启
  5. 2-1为什么选择Pytorch
  6. C++之继承探究(八):动态绑定
  7. DVWA-CSRF-low级别
  8. Quartus 与modelSim联合仿真常见错误以及系统任务$readmemb和$readmemh解释
  9. 怎么关闭计算机的端口服务,怎么关闭和打开电脑的端口?
  10. UniApp开发社交社区
  11. 计算机技术服务的增值税税率,咨询系统集成技术服务税率
  12. CAJ(caj)阅读器下载
  13. BigDecimal类型加减乘除运算(Java必备知识)
  14. Admob的注意事项
  15. 多线程 java实验心得_java多线程编程体会
  16. 超维空间鸿蒙大宇,高维空间的存在不仅能够统一基本力,还为时空穿越提供了可能!...
  17. Leetcode滑窗系列(java):643. 子数组最大平均数 I
  18. 朋友圈信息流广告案例(仙侠游戏)
  19. Bandwagon Host IP Change修改IP
  20. broadcom linux 博客,Broadcom SDK6.4.4驱动架构简单理解

热门文章

  1. stylesheettheme和 theme 的区别
  2. MyBatis中拦截器(Interceptor)实现原理分析
  3. Spring Cloud Alibaba @SentinelResource配置详解
  4. MyCat基于MySQL实现主从切换
  5. todo Java 并发编程
  6. 2018.09.14python学习第四天part3
  7. python数据类型二(列表和元组)
  8. Ubuntu安装与配置
  9. 设计模式学习笔记(四)之工厂模式(Factory)
  10. C++指针编程你要小心的陷阱——如何优雅的释放指针void*