更新:編譯參數(shù)添加對靜態(tài)庫的說明
一、目的:
實現(xiàn)鏈接時符號混淆
參考文檔:
https://llvm.org/docs/LinkTimeOptimization.html
https://mayuyu.io/2017/06/01/LLVMHacking-0x1/#more
二朱监、思路:
- 編譯階段處理符號存在硬傷岸啡,拋棄
- 鏈接器 ld 只是一個調(diào)度器,核心邏輯在庫 libLTO.dylib
- pass注冊在文件 LTOBackend.cpp 里
- 鏈接時的module整合成了一個總的module赫编, 所以鏈接時可以修改符號
三巡蘸、實現(xiàn)流程:
從這篇文章開始基于LLVM13.0,pass的注冊與實現(xiàn)不同于以前的版本擂送,反復(fù)折騰悦荒,QAQ;
1嘹吨、pass代碼:
不再使用runOnModule
實現(xiàn)搬味,我參考了 StripSymbols.cpp
的實現(xiàn)方式,官方在老的pass里加入了新的pass流程蟀拷,官方都支持碰纬,我這里使用了新的pass調(diào)用方式,如下:
- 頭文件 SymbolObfuscation.h:
#include "llvm/IR/PassManager.h"
namespace llvm {
struct SymbolObfuscationPass : PassInfoMixin<SymbolObfuscationPass> {
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 <string>
#include <iostream>
#include <cstdlib>
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<length;i++){
name[i]=obfcharacters[rand()%(obfcharacters.length())];
}
return "f_" + name;
}
PreservedAnalyses SymbolObfuscationPass::run(Module &M, ModuleAnalysisManager &AM) {
//F.setName(randomString(16));
errs()<<"Start Symbol Rewrite!\n";
for(Module::iterator Fun=M.begin();Fun!=M.end();Fun++){
Function &F=*Fun;
if (F.getName().str().compare("main")==0){
errs()<<"Skipping main\n";
}
else if(F.empty()==false){
//Rename
string newname = randomString(16);
errs()<<"Renaming Function: "<<F.getName()<<"\n";
errs()<<"New Function Name: "<<newname<<"\n";
F.setName(newname);
}
else{
errs()<<"Skipping External Function: "<<F.getName()<<"\n";
}
}
return PreservedAnalyses::all();
}
2问芬、如何添加該pass:
在 llvm/LTO/LTOBackend.cpp
文件添加悦析,選擇在這里添加是因為我們的目的是實現(xiàn)鏈接時優(yōu)化。
-
添加命令行參數(shù):
image.png -
函數(shù) runNewPMPasses 添加:
image.png
四此衅、測試:
-
上述在llvm13.0編譯通過后强戴,可以先找一個簡單的cpp文件編譯測試下效果,例:
image.png 為了展示更好的效果炕柔,我舉例一個iOS的Xcode項目
確保原始ios項目運(yùn)行沒問題后酌泰,只需要添加幾個參數(shù)即可使用,替換掉xcode的clang就可以了
1匕累、xcode添加編譯參數(shù):
- 目標(biāo)二進(jìn)制的編譯參數(shù):
-flto
- 如果依賴了靜態(tài)庫陵刹,需要在靜態(tài)庫的target也配置編譯參數(shù)
-flto
,如果依賴庫不需要混淆符號欢嘿,則該target不需要添加-flto
:
image.png
2衰琐、xcode添加鏈接參數(shù):
image.png
- -Xlinker 將 clang 參數(shù)傳遞給 鏈接器 ld
- -lto_library 指定LLVM的鏈接庫
3也糊、編譯,首先查看鏈接日志如下羡宙,說明鏈接時pass執(zhí)行成功了:
image.png
4狸剃、自測運(yùn)行該app正常,二進(jìn)制包大小也沒有變化:
沒有做過批量測試
5狗热、nm查看二進(jìn)制符號如下:
image.png