OLLVM-Windows环境上编译安装-移植到llvm18-移植到android-studio使用
0x0 参考文章
编译LLVM源码
移植OLLVM到LLVM18
移植OLLVM到Android NDK Android Studio
https://juejin.cn/post/7451580780750995495
LLVM安装与编译
编译链环境下载
Android Studio中下载NDK
Tools->SDK manager
Visual Studio 安装环境
搜索x64 Native Tools Command Prompt for VS
python 安装依赖
pip install pygments pyyaml
下载LLVM
下载18.1.8版本
git clone --depth 1 --branch llvmorg-18.1.8 https://github.com/llvm/llvm-project.git
用visual studio的x64 Native Tools Command Prompt for VS 启动控制台
编译命令
cd F:\llvm\llvm-project \\你自己存放的路径
mkdir build \\新建一个文件夹存放编译后的文件
cd build
cmake -G "Ninja" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="/utf-8" -DLLVM_ENABLE_RTTI=ON -DLLVM_ENABLE_EH=ON -DLLVM_ENABLE_PROJECTS="llvm;clang;lld" ../llvm
我是117个g,注意硬盘空间
OLLVM安装
下载Obfuscation
https://github.com/DreamSoule/ollvm17/tree/main/llvm-project/llvm/lib/Passes
然后复制Obfuscation到 LLVM 工程 llvm/lib/Passes/
编辑CMakeLists.txt
复制进去
Obfuscation/Utils.cpp
Obfuscation/CryptoUtils.cpp
Obfuscation/ObfuscationOptions.cpp
Obfuscation/BogusControlFlow.cpp
Obfuscation/IPObfuscationContext.cpp
Obfuscation/Flattening.cpp
Obfuscation/StringEncryption.cpp
Obfuscation/SplitBasicBlock.cpp
Obfuscation/Substitution.cpp
Obfuscation/IndirectBranch.cpp
Obfuscation/IndirectCall.cpp
Obfuscation/IndirectGlobalVariable.cpp
编辑PassBuilder.cpp
// 导入 Obfuscation 相关头文件
#include "Obfuscation/BogusControlFlow.h" // 虚假控制流
#include "Obfuscation/Flattening.h" // 控制流平坦化
#include "Obfuscation/SplitBasicBlock.h" // 基本块分割
#include "Obfuscation/Substitution.h" // 指令替换
#include "Obfuscation/StringEncryption.h" // 字符串加密
#include "Obfuscation/IndirectGlobalVariable.h" // 间接全局变量
#include "Obfuscation/IndirectBranch.h" // 间接跳转
#include "Obfuscation/IndirectCall.h" // 间接调用
#include "Obfuscation/Utils.h" // 为了控制函数名混淆开关 (bool obf_function_name_cmd;)
// 添加命令行支持
static cl::opt<bool> s_obf_split("split", cl::init(false), cl::desc("SplitBasicBlock: split_num=3(init)"));
static cl::opt<bool> s_obf_sobf("sobf", cl::init(false), cl::desc("String Obfuscation"));
static cl::opt<bool> s_obf_fla("fla", cl::init(false), cl::desc("Flattening"));
static cl::opt<bool> s_obf_sub("sub", cl::init(false), cl::desc("Substitution: sub_loop"));
static cl::opt<bool> s_obf_bcf("bcf", cl::init(false), cl::desc("BogusControlFlow: application number -bcf_loop=x must be x > 0"));
static cl::opt<bool> s_obf_ibr("ibr", cl::init(false), cl::desc("Indirect Branch"));
static cl::opt<bool> s_obf_igv("igv", cl::init(false), cl::desc("Indirect Global Variable"));
static cl::opt<bool> s_obf_icall("icall", cl::init(false), cl::desc("Indirect Call"));
static cl::opt<bool> s_obf_fn_name_cmd("fncmd", cl::init(false), cl::desc("use function name control obfuscation(_ + command + _ | example: function_fla_bcf_)"));
PassBuilder::PassBuilder( ... ) : ... {
...
// 注册 Obfuscation 相关 Pass
this->registerPipelineStartEPCallback(
[](llvm::ModulePassManager &MPM,
llvm::OptimizationLevel Level) {
outs() << "[OLLVM] run.PipelineStartEPCallback\n";
obf_function_name_cmd = s_obf_fn_name_cmd;
if (obf_function_name_cmd) {
outs() << "[OLLVM] enable function name control obfuscation(_ + command + _ | example: function_fla_)\n";
}
MPM.addPass(StringEncryptionPass(s_obf_sobf)); // 先进行字符串加密 出现字符串加密基本块以后再进行基本块分割和其他混淆 加大解密难度
llvm::FunctionPassManager FPM;
FPM.addPass(IndirectCallPass(s_obf_icall)); // 间接调用
FPM.addPass(SplitBasicBlockPass(s_obf_split)); // 优先进行基本块分割
FPM.addPass(FlatteningPass(s_obf_fla)); // 对于控制流平坦化
FPM.addPass(SubstitutionPass(s_obf_sub)); // 指令替换
FPM.addPass(BogusControlFlowPass(s_obf_bcf)); // 虚假控制流
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
MPM.addPass(IndirectBranchPass(s_obf_ibr)); // 间接指令 理论上间接指令应该放在最后
MPM.addPass(IndirectGlobalVariablePass(s_obf_igv)); // 间接全局变量
MPM.addPass(RewriteSymbolPass()); // 根据yaml信息 重命名特定symbols
}
);
}
下面的注册代码注意括回 一直复制到 ); 即可
接下来就是解决报错 基本上原文章讲的都要做一遍,但是和文章中我的不同
error C2039: “getInt8PtrTy”: 不是 “llvm::Type” 的成员
文章中是
llvm::PointerType::get(llvm::Type::getInt8Ty(Context), 0);
我们更改的时候只需要 将Type::getInt8Ty() 替换成PointerType::get(,0)
但是我还报了一个错 StringEncryption.cpp 引用了IRB.getInt8Ty()
直接改成
Value *OutBuf = IRB.CreateBitCast(
Entry->DecGV, llvm::PointerType::get(llvm::Type::getInt8Ty(Ctx), 0));
就是文章中所说的修改方法,我是ctx 和 Context一样但是会报错显示 未标识ctx
llvm::LLVMContext Ctx; // 创建 LLVMContext 实例
创建一个即可
2 error C3861: “valueEscapes”: 找不到标识符
直接把代码复制到Utils.cpp中即可
static bool valueEscapes(const Instruction &Inst) {
if (!Inst.getType()->isSized())
return false;
const BasicBlock *BB = Inst.getParent();
for (const User *U : Inst.users()) {
const Instruction *UI = cast<Instruction>(U);
if (UI->getParent() != BB || isa<PHINode>(UI))
return true;
}
return false;
}
后续的报错看原文章即可,一摸一样操作即可 注意原文章改成参数是Inst 我们这个直接 I 即可
传参进来就是I
最后在bulid目录中 ninja编译即可,因为前面编译过llvm 所以这一次会比较快
测试
clang -mllvm -sub 是指令替换混淆
clang -mllvm -bcf 是虚假控制流
clang -mllvm -fla 是控制流平坦化
这里能编译出来即成功
移植到Android Studio中 混淆so文件
将llvm bulid目录下的bin、include、lib文件夹复制到ndk的SDK\ndk\27.1.12297006\toolchains\llvm\prebuilt\windows-x86_64目录下即可
然后就是编译apk,so
创建一个native开发项目,这里如果你只有一个sdk就不用设置
设置你的CMakeList ollvmtest 这里是我的so文件名使用你自己的 其他可以一样
最终build即可
指令替换
虚假控制流
5行代码变成了500行
程序正常运行