我是去年10月左右开始研究Ollvm,现将一部分心得分享出来
## 基本概念
LLVM Pass按加载方式分类:
* `静态Pass`,即将Pass逻辑编译到`clang/opt`中,通过给`clang/opt`传递适当参数触发Pass。如果目标语言和编译环境不支持命令行方式指定Pass则可尝试此方式。目前大部分开源Ollvm项目都是此种方式,且一定程度修改了LLVM源码部分
* `动态Pass`,即将Pass逻辑编译为独立动态库,通过给`clang/opt`传递适当参数触发Pass。如果目标语言和编译环境不方便使用自定义`clang/opt`但支持命令行方式指定动态Pass则可尝试此方式,此方式在Pass开发编译调试时优势明显。
## 常见问题
* `动态Pass`和`LLVM`版本要匹配吗?是的,至少大版本要匹配否则大概率崩
* 开发`动态Pass`给`XCode`使用以实现`Ollvm`混淆的思路可行吗?可行
* 直接针对`XCode`的`Apple Clang`开发`动态Pass`可行吗?可行
## XCode使用Pass的方式(以下方式笔者均验证过可行)
* `静态Pass`方式1,编译为`XCode Toolchain`,也是目前大部分开源`Ollvm`项目所采用的方式。不过编译时间久一些且`Toolchain`占用的存储空间也大一些。
* `静态Pass`方式2,直接使用`clang`,在`Xcode`中指定`CC`变量为内嵌`Pass`的`clang`。如果`isysroot`不兼容可能需要在`Other C Flags`中覆盖
* `动态Pass`方式3,在Xcode中指定`CC`变量为开源`clang`(如`brew install llvm@15`),且指定`Other C Flags`指定`-fpass-plugin`为对应`Pass`路径
* `动态Pass`方式4,在`Xcode`中指定`CC`变量为编译脚本,脚本逻辑为"先用`clang -emit-llvm`参数生成`bitcode`,然后运行`opt`执行`Pass`,最后用`clang -c`生成原本要生成的obj文件"。此种方式可以直接使用`Xcode`自带的`Apple clang`,能比较好的兼容`arm64e`架构
* `动态Pass`方式5,直接针对Xcode自带的`Apple clang`开发`动态Pass`,在Xcode中指定`Other C Flags`指定`-fpass-plugin`为Pass路径。此种方式复杂度较高,只适合精通llvm编译的开发者。此种方式可以直接使用`Xcode`自带的`Apple clang`,能比较好的兼容`arm64e`架构
## 针对`AppleClang`开发`动态Pass`
现在来看看最难的部分,如果直接使用`AppleClang`对应版本的开源LLVM开发Pass给`AppleClang`使用是会崩溃的,因为`AppleClang`相对于开源LLVM魔改了很多地方。为了让`AppleClang`能运行起来一个最简单的`Pass`你至少需要如下hacker代码:
```c
class Ollvm : public PassInfoMixin<Ollvm> {
public:
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
M.dump();
#ifdef APPLE_CLANG
static PreservedAnalyses (*PreservedAnalyses__all)() = 0;
static PreservedAnalyses (*PreservedAnalyses__none)() = 0;
if (PreservedAnalyses__all == 0) {
const char* image = _dyld_get_image_name(0);
PreservedAnalyses__all = (__typeof(PreservedAnalyses__all)) DobbySymbolResolver(image,
"__ZN4llvm6detail9PassModelINS_6ModuleEN12_GLOBAL__N_114NoOpModulePassENS_17PreservedAnalysesENS_15AnalysisManagerIS2_JEEEJEE3runERS2_RS7_");
PreservedAnalyses__none = (__typeof(PreservedAnalyses__none))DobbySymbolResolver(image,
"__ZN4llvm6detail9PassModelINS_6ModuleENS_25InvalidateAllAnalysesPassENS_17PreservedAnalysesENS_15AnalysisManagerIS2_JEEEJEE3runERS2_RS6_");
}
return (opc > 0) ? PreservedAnalyses__all() : PreservedAnalyses__none();
#else
return (opc > 0) ? PreservedAnalyses::all() : PreservedAnalyses::none();
#endif
};
static bool isRequired() { return true; }
};
```
以上操作仅仅是让你“入门”,而下一步就是处理`AppleClang`魔改造成的冲突,包括但不限于拆分静态库/自行实现冲突代码,也是个复杂且麻烦的工程了,有兴趣的可以接着研究下去
[培训]科锐逆向工程师培训第53期2025年7月8日开班!
最后于 2025-6-10 21:25
被lichaolich编辑
,原因: