移动安全 ollvm基础 llvm
字数 1639 2025-08-22 12:23:30
LLVM与OLLVM基础教学文档
一、环境准备与LLVM编译
1.1 基础环境配置
使用Ubuntu 18.04系统,需要安装以下基础工具:
su root
apt update
apt install net-tools openssh-server vim build-essential cmake ninja-build
1.2 编译工具说明
- CMake:跨平台构建工具,管理源文件编译顺序,处理不同OS和编译器的差异
- Ninja:专注于快速构建的构建系统,比传统构建工具更快
- build-essential:包含C++编译器等一系列基本构建工具
1.3 LLVM编译步骤
-
下载LLVM 10.0.1源码:
mkdir LLVM cd LLVM tar -Jxvf llvm-project-10.0.1.tar.xz -
配置和编译:
cd llvm-project-10.0.1 mkdir build cd build cmake -G Ninja -DCMAKE_BUILD_TYPE="Release" \ -DLLVM_ENABLE_PROJECTS="clang" \ -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" ../llvm ninja && ninja install -j4
参数说明:
-G Ninja:生成Ninja构建文件-DCMAKE_BUILD_TYPE="Release":生产环境构建-DLLVM_ENABLE_PROJECTS="clang":同时构建clang-DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi":启用运行时库
二、LLVM基本概念
2.1 编译器架构
LLVM采用三段式设计:
-
前端(Frontend):
- 词法分析
- 语法分析
- 语义分析
- 构建抽象语法树(AST)
-
优化器(Optimizer):
- 代码优化
- 消除冗余
-
后端(Backend):
- 生成目标机器指令
- 指令选择
- 寄存器分配
- 指令调度
2.2 中间表示(IR)
LLVM IR有两种表示形式:
| 格式 | 类型 | 特点 |
|---|---|---|
.ll |
文本格式 | 人类可读,类似汇编 |
.bc |
二进制格式 | 紧凑高效,用于工具链内部 |
转换命令:
llvm-as file.ll -o file.bc # 汇编到二进制
llvm-dis file.bc -o file.ll # 二进制到汇编
2.3 LLVM工具集
| 工具 | 功能 |
|---|---|
| bugpoint | 调试优化遍数或代码生成后端 |
| llvm-ar | 生成包含LLVM位码的归档文件 |
| llvm-as | 将LLVM汇编转换为位码 |
| llvm-dis | 将位码转换为LLVM汇编 |
| llvm-link | 链接多个LLVM模块 |
| lli | LLVM解释器/JIT编译器 |
| llc | LLVM后端编译器,生成本地代码 |
| opt | 应用LLVM到LLVM的转换 |
三、LLVM Pass开发
3.1 LLVM Pass概念
LLVM Pass是对IR进行特定操作的组件,可用于:
- 代码优化(提高性能、减小体积)
- 代码分析(检查问题、验证规则)
工作方式:IR代码流经Pass时被处理
3.2 项目内Pass开发
-
在
llvm/lib/Transforms下创建Pass目录 -
创建
CMakeLists.txt:add_llvm_library(LLVMPrintName MODULE PrintName.cpp PLUGIN_TOOL opt) -
编写Pass代码示例:
#include "llvm/IR/Function.h" #include "llvm/IR/Module.h" #include "llvm/Pass.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; namespace { struct PrintFunctionNamePass : public ModulePass { static char ID; PrintFunctionNamePass() : ModulePass(ID) {} bool runOnModule(Module &M) override { for (auto &F : M) { errs() << "函数名: " << F.getName() << "\n"; } return false; } }; char PrintFunctionNamePass::ID = 0; static RegisterPass<PrintFunctionNamePass> X( "printname", // 命令行标识符 "打印函数名LLVM Pass", // 简短描述 false, // 不修改IR false // 不是分析Pass ); } -
编译和使用:
ninja LLVMPrintName opt -load /path/to/LLVMPrintName.so -printname hello.ll -o hello.bc
3.3 项目外Pass开发
目录结构:
项目根目录/
├── CMakeLists.txt
└── llvmpass/
├── CMakeLists.txt
└── PrintName.cpp
根目录CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
SET(CMAKE_CXX_FLAGS "-Wall -fno-rtti")
find_package(LLVM REQUIRED CONFIG)
add_definitions(${LLVM_DEFINITIONS})
include_directories(${LLVM_INCLUDE_DIRS})
link_directories(${LLVM_LIBRARY_DIRS})
add_subdirectory(llvmpass)
子目录CMakeLists.txt:
add_library(LLVMPrintName MODULE PrintName.cpp)
target_link_libraries(LLVMPrintName PRIVATE ${LLVM_LIBRARY_DIRS})
四、OLLVM基础
OLLVM是基于LLVM的混淆工具,通过对代码结构进行转换增加逆向难度。理解OLLVM需要先掌握LLVM基础知识,特别是:
- LLVM IR结构
- Pass开发技术
- 编译器优化流程
OLLVM主要通过以下Pass实现混淆:
- 控制流扁平化
- 指令替换
- 虚假控制流
- 字符串加密等
五、常见问题解决
-
apt锁冲突:
ps aux | grep apt sudo kill -9 <PID> -
网卡丢失:
service NetworkManager restart -
编译中断:
- 重新运行命令会继续之前进度
- 建议增加内存和CPU核心数
六、参考资料
- LLVM官方文档:https://llvm.org/docs/GettingStarted.html
- Writing an LLVM Pass:https://releases.llvm.org/9.0.1/docs/WritingAnLLVMPass.html
- CMake构建参考:https://stackoverflow.com/questions/17225956/developing-an-llvm-pass-with-cmake-out-of-llvm-source-directory