函数名称加密Pass开发

测试代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
//luoTst.c
#include <stdio.h>

void fun1() {
    printf("hello clang: fun1\r\n");
}

void fun2() {
    printf("hello clang: fun2\r\n");
}

int main(int argc, char const *argv[])
{
    if (argc > 2) {
        printf("hello world!\r\n");
    } else {
        printf("hello LuoHun!\r\n");
    }
    fun1();
    fun2();
    return 0;
}

基于源码编写Pass

  1. 在{llvm-project}/llvm/lib/Transforms目录下新建一个文件夹EncodeFunctionName
  2. 在EncodeFunctionName文件夹下新建一个CMakeLists.txt文件
1
2
3
4
5
6
add_llvm_library( LLVMEncodeFunctionName MODULE
        EncodeFunctionName.cpp

        PLUGIN_TOOL
        opt
        )
  1. 在新建文件夹的上层即lib/Transforms/CMakeLists.txt文件中填入下面内容
1
add_subdirectory(EncodeFunctionName)
  1. Reload Cmake Project

reloadCmake

  1. 在EncodeFunctionName文件夹下新建一个EncodeFunctionName.cpp文件.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

namespace {
struct EncodeFunctionName : public FunctionPass {
  static char ID;
  EncodeFunctionName() : FunctionPass(ID) {}
  bool runOnFunction(Function &F) override {
    errs() << "Encode Function Name: "<<F.getName()<<" -> ";
    if(F.getName().compare("main") != 0){
      llvm::MD5 Hasher;
      llvm::MD5::MD5Result Hash;
      Hasher.update("luohun_");
      Hasher.update(F.getName());
      Hasher.final(Hash);

      SmallString<32> HexString;
      llvm::MD5::stringifyResult(Hash, HexString);

      F.setName(HexString);
    }

    errs().write_escaped(F.getName()) << '\n';
    return false;
  }
}; // end of struct EncodeFunctionName
}

char EncodeFunctionName::ID = 0;
static RegisterPass<EncodeFunctionName> X("encode", "Encode Function Name Pass",
                                          false /* Only looks at CFG */,
                                          false /* Analysis Pass */);
  1. 在{llvm-project}/llvm/cmake-build-release目录下执行下述命令即可进行编译
1
ninja LLVMEncodeFunctionName
  1. 使用opt来测试pass
1
2
3
4
//生成.ll文件
clang -emit-llvm -S luoTst.c -o luoTst.ll
//使用opt进行测试
opt -load /home/luohun/Desktop/llvm-project-9.0.1/llvm/cmake-build-release/lib/LLVMEncodeFunctionName.so -encode luoTst.ll -o luoTst.bc

脱离源码编写Pass

项目布局如下:

1
2
3
4
5
6
7
8
<project dir>/
    |
    CMakeLists.txt
    <pass name>/
        |
        CMakeLists.txt
        Pass.cpp
        ...
  1. 新建一个项目文件夹如 passDev
  2. 在passDev文件夹下新建一个CMakeLists.txt文件,内容如下:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#前3项根据自身情况来
cmake_minimum_required(VERSION 3.24)
project(passDev)
set(LLVM_DIR /home/luohun/Desktop/llvm-project-9.0.1/build_debug/lib/cmake/llvm/)

find_package(LLVM REQUIRED CONFIG)

list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}")
include(AddLLVM)

separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS})
add_definitions(${LLVM_DEFINITIONS_LIST})
include_directories(${LLVM_INCLUDE_DIRS})

add_subdirectory(EncodeFunctionName)
  1. 在passDev文件夹下新建一个Pass文件夹如 EncodeFunctionName
  2. 在EncodeFunctionName文件夹下新建一个CMakeLists.txt文件,内容如下:
1
2
3
add_llvm_library(LLVMEncodeFunctionName2 MODULE
  EncodeFunctionName.cpp
  )
  1. 在EncodeFunctionName文件夹下新建一个EncodeFunctionName.cpp文件,内容如下:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

namespace {
struct EncodeFunctionName : public FunctionPass {
  static char ID;
  EncodeFunctionName() : FunctionPass(ID) {}
  bool runOnFunction(Function &F) override {
    errs() << "Encode Function Name: "<<F.getName()<<" -> ";
    if(F.getName().compare("main") != 0){
      llvm::MD5 Hasher;
      llvm::MD5::MD5Result Hash;
      Hasher.update("luohun_");
      Hasher.update(F.getName());
      Hasher.final(Hash);

      SmallString<32> HexString;
      llvm::MD5::stringifyResult(Hash, HexString);

      F.setName(HexString);
    }

    errs().write_escaped(F.getName()) << '\n';
    return false;
  }
}; // end of struct EncodeFunctionName
}

char EncodeFunctionName::ID = 0;
static RegisterPass<EncodeFunctionName> X("encode", "Encode Function Name Pass",
                                          false /* Only looks at CFG */,
                                          false /* Analysis Pass */);
  1. 用CLion打开该项目,点击build即可进行编译.

Clion编译

  1. 接下来就可以使用下述命令来进行混淆并生成bc文件
1
opt -load /home/luohun/Desktop/luo/passDev/cmake-build-debug/EncodeFunctionName/LLVMEncodeFunctionName2.so -encode luoTst.ll -o luoTst.bc

Pass注册到Clang中

编译llvm自定义混淆的Pass后,使用opt进行pass加载混淆bc文件这个步骤很麻烦,下面以llvm9.0.1为例将llvm pass添加到clang的命令行

  1. 创建头文件,在{llvm-project}/llvm/include/llvm/Transforms目录下,新建一个EncodeFunctionName文件夹,在里面再新建一个EncodeFunctionName.h
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#ifndef LLVM_ENCODEFUNCTIONNAME_H
#define LLVM_ENCODEFUNCTIONNAME_H
#include "llvm/Pass.h"

namespace llvm{
Pass* createEncodeFunctionName();
}


#endif // LLVM_ENCODEFUNCTIONNAME_H
  1. 在{llvm-project}/llvm/lib/Transforms/EncodeFunctionName/EncodeFunctionName.cpp文件中进行实现
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"

#include "llvm/Transforms/EncodeFunctionName/EncodeFunctionName.h"
using namespace llvm;

namespace {
struct EncodeFunctionName : public FunctionPass {
  static char ID;
  EncodeFunctionName() : FunctionPass(ID) {}
  bool runOnFunction(Function &F) override {
    errs() << "Encode Function Name: "<<F.getName()<<" -> ";
    if(F.getName().compare("main") != 0){
      llvm::MD5 Hasher;
      llvm::MD5::MD5Result Hash;
      Hasher.update("luohun_");
      Hasher.update(F.getName());
      Hasher.final(Hash);

      SmallString<32> HexString;
      llvm::MD5::stringifyResult(Hash, HexString);

      F.setName(HexString);
    }

    errs().write_escaped(F.getName()) << '\n';
    return false;
  }
}; // end of struct EncodeFunctionName
}

char EncodeFunctionName::ID = 0;
static RegisterPass<EncodeFunctionName> X("encode", "Encode Function Name Pass",
                                          false /* Only looks at CFG */,
                                          false /* Analysis Pass */);

//实现该函数
Pass* llvm::createEncodeFunctionName(){return new EncodeFunctionName();}
  1. 修改{llvm-project}/llvm/lib/Transforms/EncodeFunctionName/CMakeLists.txt内容如下:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
add_llvm_library( LLVMEncodeFunctionName
        EncodeFunctionName.cpp

        ADDITIONAL_HEADER_DIRS
        ${LLVM_MAIN_INCLUDE_DIR}/llvm/Transforms
        ${LLVM_MAIN_INCLUDE_DIR}/llvm/Transforms/EncodeFunctionName

        DEPENDS
        intrinsics_gen
        )
  1. 在{llvm-project}/llvm/lib/Transforms/EncodeFunctionName下新建一个LLVMBuild.txt
1
2
3
4
5
[component_0]
type = Library
name = EncodeFunctionName
parent = Transforms
library_name = EncodeFunctionName
  1. 在{llvm-project}/llvm/lib/Transforms/LLVMBuild.txt文件中添加EncodeFunctionName
1
2
[common]
subdirectories = AggressiveInstCombine Coroutines IPO InstCombine Instrumentation Scalar Utils Vectorize ObjCARC EncodeFunctionName
  1. 在{llvm-project}/llvm/lib/Transforms/IPO/LLVMBuild.txt文件中添加EncodeFunctionName
1
required_libraries = AggressiveInstCombine Analysis BitReader BitWriter Core InstCombine IRReader Linker Object ProfileData Scalar Support TransformUtils Vectorize Instrumentation EncodeFunctionName
  1. 修改{llvm-project}/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp文件,添加启动参数识别
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include "llvm/Transforms/EncodeFunctionName/EncodeFunctionName.h"
static cl::opt<bool>
    EnableEncodeFunctionName("encode", cl::init(false), cl::Hidden,
                       cl::ZeroOrMore, cl::desc("Encode Name Function Pass"));

void PassManagerBuilder::populateModulePassManager(
    legacy::PassManagerBase &MPM) {
    
    //---
    if (EnableEncodeFunctionName){
    	MPM.add(createEncodeFunctionName());
  	}
    //---
}
  1. 在{llvm-project}/llvm/cmake-build-release进行编译
1
2
ninja LLVMEncodeFunctionName
ninja clang
  1. 用编译出的clang去编译上面的测试文件
1
clang -mllvm -encode luoTst.ll -o luoTst.bc

clang编译测试

注意
上面的方法从llvm12.0.0开始已不再适用,因为从llvm12.0.0版本开始已经将LLVMBuild.txt文件删除了,取而代之的是一种纯粹的CMake方法.

参考链接

WritingAnLLVMPass

developing-llvm-passes-out-of-source

LLVM 12.0.0 发布


相关内容

0%