LLVM 进阶一:符号混淆(LTO)

更新:编译参数添加对静态库的说明

一、目的:

实现链接时符号混淆
参考文档:
https://llvm.org/docs/LinkTimeOptimization.html
https://mayuyu.io/2017/06/01/LLVMHacking-0x1/#more

二、思路:

  • 编译阶段处理符号存在硬伤,抛弃
  • 链接器 ld 只是一个调度器,核心逻辑在库 libLTO.dylib
  • pass注册在文件 LTOBackend.cpp 里
  • 链接时的module整合成了一个总的module, 所以链接时可以修改符号

三、实现流程:

从这篇文章开始基于LLVM13.0,pass的注册与实现不同于以前的版本,反复折腾,QAQ;

1、pass代码:
不再使用runOnModule实现,我参考了 StripSymbols.cpp 的实现方式,官方在老的pass里加入了新的pass流程,官方都支持,我这里使用了新的pass调用方式,如下:

  • 头文件 SymbolObfuscation.h:
#include "llvm/IR/PassManager.h"
namespace llvm {
    struct SymbolObfuscationPass : PassInfoMixin {
      PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
    };
}
  • cpp 文件 SymbolObfuscation.cpp:

#include "llvm/IR/Module.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/SymbolObfuscation/SymbolObfuscation.h"
#include 
#include 
#include 

using namespace llvm;
using namespace std;

static string obfcharacters="-_.|/\\`+,=()*:";

int seed = 0;
string randomString(int length){
    string name;
    name.resize(length);
    srand(seed);
    seed++;
    for(int i=0;i

2、如何添加该pass:
llvm/LTO/LTOBackend.cpp文件添加,选择在这里添加是因为我们的目的是实现链接时优化。

  • 添加命令行参数:


    image.png
  • 函数 runNewPMPasses 添加:


    image.png

四、测试:

  • 上述在llvm13.0编译通过后,可以先找一个简单的cpp文件编译测试下效果,例:


    image.png
  • 为了展示更好的效果,我举例一个iOS的Xcode项目

确保原始ios项目运行没问题后,只需要添加几个参数即可使用,替换掉xcode的clang就可以了
1、xcode添加编译参数:

  • 目标二进制的编译参数:-flto
  • 如果依赖了静态库,需要在静态库的target也配置编译参数-flto,如果依赖库不需要混淆符号,则该target不需要添加-flto
    image.png

2、xcode添加链接参数:


image.png
  • -Xlinker 将 clang 参数传递给 链接器 ld
  • -lto_library 指定LLVM的链接库

3、编译,首先查看链接日志如下,说明链接时pass执行成功了:

image.png

4、自测运行该app正常,二进制包大小也没有变化:
没有做过批量测试
5、nm查看二进制符号如下:


image.png

你可能感兴趣的:(LLVM 进阶一:符号混淆(LTO))