ollvm 新增字符串加密功能
好久没弄ollvm了,可以继续了,今天给ollvm新增了一个pass,用来加密字符串,这个pass是从别的库里面扒出来的。
本文是基于在Windows 上使用VS2017编译出来的ollvm,在这个基础上来添加。
第一步:
寻找两个pass的代码
头文件
#ifndef _STRING_OBFUSCATION_H_
#define _STRING_OBFUSCATION_H_ // LLVM include
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/CryptoUtils.h" // Namespace
using namespace llvm;
using namespace std; namespace llvm {
Pass *createStringObfuscation(bool flag);
} #endif
源文件
#define DEBUG_TYPE "objdiv"
#include <string>
#include <sstream> #include "llvm/ADT/Statistic.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Value.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/CryptoUtils.h"
#include "llvm/Transforms/Obfuscation/StringObfuscation.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Transforms/Utils/ModuleUtils.h" using namespace llvm; STATISTIC(GlobalsEncoded, "Counts number of global variables encoded"); #define ZooPrint(_F, ...) fprintf(stdout, "File : [%s](%d) " _F, __FILE__, __LINE__, __VA_ARGS__) namespace llvm { struct encVar {
public:
GlobalVariable *var;
uint8_t key;
}; class StringObfuscationPass : public llvm::ModulePass {
public:
static char ID; // pass identification
bool is_flag = false;
StringObfuscationPass() : ModulePass(ID) {}
StringObfuscationPass(bool flag) : ModulePass(ID)
{
is_flag = flag;
} virtual bool runOnModule(Module &M) {
ZooPrint(" Run On Module : %d \n", is_flag);
if (!is_flag)
return false;
std::vector<GlobalVariable*> toDelConstGlob;
//std::vector<GlobalVariable*> encGlob;
std::vector<encVar*> encGlob;
ZooPrint(" M.Size : %d \n", M.size());
int i = ;
for (Module::global_iterator gi = M.global_begin(), ge = M.global_end(); gi != ge; ++gi)
{ #if 0
// 老式代码,原来的样子
@.str = private unnamed_addr constant[ x i8] c"\E4\BD\A0\E5\A5\BD\E4\B8\96\E7\95\8C\00", align
@__CFConstantStringClassReference = external global[ x i32]
@.str. = private unnamed_addr constant[ x i16][i16 , i16 , i16 ], section "__TEXT,__ustring", align
// 新式字符串的样子
@"\01??_C@_07CHPFNFHA@123456?6?$AA@" = linkonce_odr unnamed_addr constant [ x i8] c"123456\0A\00", comdat, align
@"\01??_C@_03PMGGPEJJ@?$CFd?6?$AA@" = linkonce_odr unnamed_addr constant [ x i8] c"%d\0A\00", comdat, align
@__local_stdio_printf_options._OptionsStorage = internal global i64 , align
#endif
// Loop over all global variables
GlobalVariable* gv = &(*gi);
//errs() << "Global var " << gv->getName();
//std::string::size_type str_idx = gv->getName().str().find(".str.");
std::string section(gv->getSection()); ZooPrint(" %d : String : \"%s\" , section : \"%s\" , isConstant : %d , hasInitializer : %d , isa : %d , r : %d \n", i++, gv->getName().str().c_str(), section.c_str(), gv->isConstant(), gv->hasInitializer(), isa<ConstantDataSequential>(gv->getInitializer()), gv->getName().str().substr(, ) == "\"\x01??_C@_");
// ZooPrint(" 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X \n", gv->getName()[0] & 0xFF, gv->getName()[1] & 0xFF, gv->getName()[2] & 0xFF, gv->getName()[3] & 0xFF, gv->getName()[4] & 0xFF, gv->getName()[5] & 0xFF, gv->getName()[6] & 0xFF, gv->getName()[7] & 0xFF); // Let's encode the static ones
//if (gv->getName().str().substr(0, 4) == ".str"&&
if (gv->getName().str().substr(, ) == "\x01??_C@_" &&
gv->isConstant() &&
gv->hasInitializer() &&
isa<ConstantDataSequential>(gv->getInitializer()) &&
section != "llvm.metadata" &&
section.find("__objc_methname") == std::string::npos
/*&&gv->getType()->getArrayElementType()->getArrayElementType()->isIntegerTy()*/)
{
ZooPrint(" In Global Encode \n");
++GlobalsEncoded;
//errs() << " is constant"; // Duplicate global variable
GlobalVariable *dynGV = new GlobalVariable(M,
gv->getType()->getElementType(),
!(gv->isConstant()), gv->getLinkage(),
(Constant*), gv->getName(),
(GlobalVariable*),
gv->getThreadLocalMode(),
gv->getType()->getAddressSpace());
// dynGV->copyAttributesFrom(gv);
dynGV->setInitializer(gv->getInitializer()); std::string tmp = gv->getName().str();
// errs()<<"GV: "<<*gv<<"\n"; Constant *initializer = gv->getInitializer();
ConstantDataSequential *cdata = dyn_cast<ConstantDataSequential>(initializer);
if (cdata) {
const char *orig = cdata->getRawDataValues().data();
unsigned len = cdata->getNumElements()*cdata->getElementByteSize(); encVar *cur = new encVar();
cur->var = dynGV;
cur->key = llvm::cryptoutils->get_uint8_t();
// casting away const is undef. behavior in C++
// TODO a clean implementation would retrieve the data, generate a new constant
// set the correct type, and copy the data over.
//char *encr = new char[len];
//Constant *initnew = ConstantDataArray::getString(M.getContext(), encr, true);
char *encr = const_cast<char *>(orig);
// Simple xor encoding
for (unsigned i = ; i != len; ++i) {
encr[i] = orig[i] ^ cur->key;
} // FIXME Second part of the unclean hack.
dynGV->setInitializer(initializer); // Prepare to add decode function for this variable
encGlob.push_back(cur);
}
else {
// just copying default initializer for now
dynGV->setInitializer(initializer);
} // redirect references to new GV and remove old one
gv->replaceAllUsesWith(dynGV);
toDelConstGlob.push_back(gv); }
} // actuallte delete marked globals
for (unsigned i = , e = toDelConstGlob.size(); i != e; ++i)
toDelConstGlob[i]->eraseFromParent(); addDecodeFunction(&M, &encGlob); return true;
} private:
void addDecodeFunction(Module *mod, std::vector<encVar*> *gvars) {
ZooPrint(" Add Decode Function \n");
// Declare and add the function definition
//errs()<<"Successful enter decode function"<<"\n";
std::vector<Type*>FuncTy_args;
FunctionType* FuncTy = FunctionType::get(
/*Result=*/Type::getVoidTy(mod->getContext()), // returning void
/*Params=*/FuncTy_args, // taking no args
/*isVarArg=*/false);
uint64_t StringObfDecodeRandomName = cryptoutils->get_uint64_t();
std::string random_str;
std::stringstream random_stream;
random_stream << StringObfDecodeRandomName;
random_stream >> random_str;
StringObfDecodeRandomName++;
Constant* c = mod->getOrInsertFunction(".datadiv_decode" + random_str, FuncTy);
Function* fdecode = cast<Function>(c);
fdecode->setCallingConv(CallingConv::C); BasicBlock* entry = BasicBlock::Create(mod->getContext(), "entry", fdecode); IRBuilder<> builder(mod->getContext());
builder.SetInsertPoint(entry); for (unsigned i = , e = gvars->size(); i != e; ++i) {
GlobalVariable *gvar = (*gvars)[i]->var;
uint8_t key = (*gvars)[i]->key; Constant *init = gvar->getInitializer();
ConstantDataSequential *cdata = dyn_cast<ConstantDataSequential>(init); unsigned len = cdata->getNumElements()*cdata->getElementByteSize();
--len; BasicBlock *preHeaderBB = builder.GetInsertBlock();
BasicBlock* for_body = BasicBlock::Create(mod->getContext(), "for-body", fdecode);
BasicBlock* for_end = BasicBlock::Create(mod->getContext(), "for-end", fdecode);
builder.CreateBr(for_body);
builder.SetInsertPoint(for_body);
PHINode *variable = builder.CreatePHI(Type::getInt32Ty(mod->getContext()), , "i");
Value *startValue = builder.getInt32();
Value *endValue = builder.getInt32(len);
variable->addIncoming(startValue, preHeaderBB);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //LoadInst *Load=builder.CreateLoad(gvar);
//errs()<<"Load: "<<*(Load->getPointerOperand())<<"\n";
Value* indexList[] = { ConstantInt::get(variable->getType(), ), variable };
Value *const_key = builder.getInt8(key);
Value *GEP = builder.CreateGEP(gvar, ArrayRef<Value*>(indexList, ), "arrayIdx");
LoadInst *loadElement = builder.CreateLoad(GEP, false);
loadElement->setAlignment();
//errs()<<"Type: "<<*loadElement<<"\n";
//CastInst* extended = new ZExtInst(const_key, loadElement->getType(), "extended", for_body);
//Value* extended = builder.CreateZExtOrBitCast(const_key, loadElement->getType(),"extended");
Value *Xor = builder.CreateXor(loadElement, const_key, "xor");
StoreInst *Store = builder.CreateStore(Xor, GEP, false);
Store->setAlignment(); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Value *stepValue = builder.getInt32();
Value *nextValue = builder.CreateAdd(variable, stepValue, "next-value");
Value *endCondition = builder.CreateICmpULT(variable, endValue, "end-condition");
endCondition = builder.CreateICmpNE(endCondition, builder.getInt1(), "loop-condition");
BasicBlock *loopEndBB = builder.GetInsertBlock();
builder.CreateCondBr(endCondition, loopEndBB, for_end);
builder.SetInsertPoint(for_end);
variable->addIncoming(nextValue, loopEndBB); }
builder.CreateRetVoid();
appendToGlobalCtors(*mod, fdecode, ); } }; Pass *createStringObfuscation(bool flag);
} #if 0
RegisterPass(const char *PassArg, const char *Name, bool CFGOnly = false, bool is_analysis = false) 上面这个是RegisterPass的构造函数。
参数说明: template<typename passName> :YourPassName;
PassArg :opt调用时所用的命行参数;
Name :此pass的简要说明;
CFGOnly :如果一个遍历CFG而不修改它,那么这个参数被设置为true;
is_analysis :如果一个Pass是一个分析Pass,例如dominator tree pass,那么这个参数被设置为true。
例子: static RegisterPass<Hello> X("hello", "Hello World Pass", false, false);
#endif char StringObfuscationPass::ID = ;
static RegisterPass<StringObfuscationPass> X("GVDiv", "Global variable (i.e., const char*) diversification pass", false, true); Pass * llvm::createStringObfuscation(bool flag) {
ZooPrint("new my pass \n");
return new StringObfuscationPass(flag);
}
第二步:
将头文件放在如下位置:ollvm\obfuscator-llvm-4.0\include\llvm\Transforms\Obfuscation\StringObfuscation.h
将源文件放在如下位置:ollvm\obfuscator-llvm-4.0\lib\Transforms\Obfuscation\StringEncode.cpp
第三步:
将源文件放到如下工程中
第四步:
在此文件中新增代码:ollvm\obfuscator-llvm-4.0\lib\Transforms\IPO\PassManagerBuilder.cpp
新增导入头文件
#include "llvm/Transforms/Obfuscation/StringObfuscation.h"
新增全局变量代码如下
static cl::opt<std::string> Seed("seed", cl::init(""),
cl::desc("seed for the random")); // 全局开关,根据参数判断是否设置
static cl::opt<bool> StringObf("sobf", cl::init(false),
cl::desc("Enable the string obfuscation"));
在:PassManagerBuilder::populateModulePassManager 函数中,新增挂载新的pass代码,如下
MPM.add(createStringObfuscation(StringObf));
意义为根据全局开关来判断是否启用当前pass
经过以上四步,问题全部解决了,直接重新编译ollvm即可。
后续可以修改pass代码,可以修改解密函数。
新增其他pass新增步骤也如上。
使用方式如下
G:\ollvm\Test>G:\ollvm\build\RelWithDebInfo\bin\clang.exe -mllvm -sobf -mllvm -fla main.c
含义是,开启字符串加密,并且启动代码扁平化
效果:
源代码如下
编译后如下
已经开启了代码扁平化,原始字符串也已经不一样了,具体情况,
看data段就好了:
已经完全没个人样了
重点在最后,忘了,补充一句,由于字符串在ollvm里面是以UTF8的格式保存的,所以中文字符串天然就是乱码,
有时间想办法来解决一下中文字符串的乱码问题。
这个pass挺简单的,我也没怎么改就拿来用了,后续有时间再改一下吧。
ollvm 新增字符串加密功能的更多相关文章
- Dotfuscator可以实现混淆代码、变量名修改、字符串加密
C#编写的代码如果不进行一定程度的混淆和加密,那么是非常容易被反编译进行破解的,特别是对于一些商业用途的C#软件来说,因为盯着的人多,更是极易被攻破.使用VS自带的Dotfuscator可以实现混淆代 ...
- Jmeter_beanshell实现字符串加密
Jmeter内置的没有MD5加密方法,所以需要写一些java代码实现加密功能,以下是具体操作: 1:用eclipse建个工程(包名.类名.方法名自己起) package com.wjika.test; ...
- Jmeter(十六)_beanshell实现字符串加密
Jmeter内置的没有MD5加密方法,所以需要写一些java代码实现加密功能,以下是具体操作: 1:用eclipse建个工程(包名.类名.方法名自己起) package com.wjika.test; ...
- Jmeter实现对字符串加密
最近测试移动端接口,但是请求内容是用MD5加密的,所以要先对请求内容进行加密,Jmeter内置的没有MD5加密方法,所以自己从网上copy了一份,实现了加密功能,以下是具体操作: 1.从网上copy了 ...
- 给 Qt sqlite 增加加密功能
整合sqlite代码 开源的sqlite中没有实现加密的功能,所以如果需要加密功能,需要自己实现 sqlite3_keysqlite3_rekey 等相关函数 不过开源的 wxsqlite3中已经实现 ...
- ES6学习----let、const、解构赋值、新增字符串、模板字符串、Symbol类型、Proxy、Set
这篇es6的学习笔记来自于表哥 表严肃,是我遇到过的讲课最通透,英文发音最好听的老师,想一起听课就去这里吧 https://biaoyansu.com/i/hzhj1206 ES6就是JS6,JS的第 ...
- anyRTC SDK 5月迭代:优化自定义加密功能,让通信更安全
anyRTC SDK 5月上新,新增多种加密类型,让实时音视频通信更安全:新增移动端推流支持1080P分辨率的支持:此外还对事件上报.日志详情.数据统计.网络传输等多项功能进行了优化改进. 以下为更新 ...
- 使用.NET 6开发TodoList应用(29)——实现静态字符串本地化功能
系列导航及源代码 使用.NET 6开发TodoList应用文章索引 需求 在开发一些需要支持多种语言的应用程序时,我们需要根据切换的语言来对应展示一些静态的字符串字段,在本文中我们暂时不去讨论如何结合 ...
- 利用javascript对字符串加密
没事利用js写个对字符串加密的方法,基本原理就是先把字符串转化成对应的unicode(用到的方法是charCodeAt()),再把unicode统一减去100(这里加减随便你取多少),把得到的unic ...
随机推荐
- docker-compose启动报错:Creating network "soft_default" with the default driver ERROR: cannot create network e5b60fc347db868e471b61ea185fd24e3ea7e2730149d91ad70baf29732aaff0 (br-e5b60fc347db): conflicts wi
docker-compose启动容器时出现报错 Creating network "soft_default" with the default driver ERROR: can ...
- windows10安装nodejs 10和express 4
最进做一个个人博客系统,前端用到了semanticUI,但是要使用npm工具包,所以需要安装nodejs,nodejs自带npm 下载 去官网下载自己系统对应的版本,我的是windows:下载 可以在 ...
- update all line start with -- to space
update all line start with -- to space ^--.*$
- ubuntu在线搭建ftp服务器
转载:https://www.linuxidc.com/Linux/2016-12/138563.htm 在Linux中ftp服务器的全名叫 vsftpd,我们需要利用相关命令来开启安装ftp服务器, ...
- PyQt5界面上调用subprocess.Popen会闪命令窗口的问题
最近再做一个界面开发,主要实现的点击一个按钮,会执行adb安装应用程序的功能,在调试阶段一切都正常,但打包成一个exe安装程序,安装之后运行,点击按钮会闪一下adb的命令窗口 先列出subproces ...
- Ubuntu18.04 安装 Idea 2018.2
https://blog.csdn.net/weixx3/article/details/81136822 Ubuntu18.04 安装 Idea 2018.2环境信息:OS:Ubuntu18.04J ...
- hive的数据定义之创建数据库和表
1.对数据库的操作 create database hive_db //创建数据库hive_db create table hive_db.test(字段内容及其格式省略) //在数据库hive_db ...
- nyoj 83:迷宫寻宝(二)(计算几何)
题目链接 枚举所有墙的2n个端点与宝物的位置作为一条线段(墙的端点必定与边界重合), 求出与之相交的最少线段数(判断线段相交时用跨立实验的方法),+1即为结果. #include<bits/st ...
- PHP curl_close函数
说明 void curl_close ( resource $ch ) 关闭一个cURL会话并且释放所有资源.cURL句柄ch 也会被释放. 参数 ch 由 curl_init() 返回的 cURL ...
- HDU - 6601 Keen On Everything But Triangle 主席树
Keen On Everything But Triangle 感觉最近多校好多主席树的亚子,但是本人菜得很,还没学过主席树,看着队友写题就只能划水,\(WA\)了还不能帮忙\(debug\),所以深 ...