代码混淆技术系列
LLVM-PASS编写指南
00 分钟
2022-12-15
2024-11-11
type
status
date
slug
summary
tags
category
icon
password

LLVM PASS 基本概念

LLVM Pass 框架是整个 LLVM 提供给用户用来干预代码优化过程的框架 编译后的 LLVM Pass 一般是. So 文件 (动态链接库) 通过优化器 opt 进行加载,作用是对 LLVM IR 中间代码进行分析和修改,生成新的中间代码 如图所示:
notion image

LLVM 源代码目录结构

llvm/include/llvm 文件夹

llvm/include/llvm 文件夹存放了 LLVM 提供的一些公共头文件
notion image

llvm/lib 文件夹

llvm/lib 文件夹存放了 LLVM 大部分源代码(. cpp 文件)和一些不公开的 头文件
notion image

llvm/lib/Transforms 文件夹

llvm/lib/Transforms 文件夹存放所有 LLVM Pass 的源代码,以及 LLVM 自带的一些 PASS
notion image
其他目录官方文档有详细的说明

LVM Pass 的编写、编译以及加载

编译方式

LLVM Pass 支持三种编译方式:
  1. 与整个 LLVM 一起重新编译,Pass 代码需要存放在 llvm/lib/Transforms 文件夹中(编译太耗时间)
  1. 通过 CMake 对 Pass 进行单独编译。(本文章使用)
  1. 使用命令行对 Pass 进行单独编译。(项目越大越不好管理)

Pass 类型

Pass 有很多种类型, 如下:
  1. ModulePass(基于模块的 Pass)
  1. FuncitonPass (基于函数的 Pass)
  1. CallGraphPass (基于调用图的 Pass)
  1. LoopPass(基于循环的 Pass)
  1. 等等

编写前须知

以 FuncitonPass 为例子 编写 FuncitonPass 需要知道的
  1. FunctionPass 以函数为单位进行处理。
  1. FunctionPass 的子类必须实现 runOnFunction (Function &F) 函数。
  1. 在 FunctionPass 运行时,会对程序中的每个函数执行 runOnFunction 函数。

编写步骤

  1. 创建一个类(class),继承 FunctionPass 父类。
  1. 在创建的类中实现 runOnFunction (Function &F) 函数。
  1. 向 LLVM 注册我们的 Pass 类。

编译

如果选择基于 CMake 的编译方法,直接使用 CMake 进行编译即可。然后在 Build 文件夹内可以找到编译好的 so 文件。也就是我们编译好的 LLVM PASS

加载

使用优化器 opt 将处理中间代码(. ll 或者. bs),生成新的中间代码 (. ll 或者. bs)
命令大致如下
  • load 让 opt 优化器加载编译好的 LLVM Pass(. so 文件)进行优化中间代码

Cmake 项目创建

目录:
notion image
  • Build 文件夹:存放编译后 LLVM Pass (. so 文件)
  • Test 文件夹:存放测试程序 TestProgram. cpp
  • Test/TestProgram. cpp:示例代码(简单逆向题)
  • Transforms/include 文件夹:存放整个 LLVM Pass 项目的头文件,暂时还没有用到
  • Transforms/src 文件夹:存放整个 LLVM Pass 项目的源代码
  • Transforms/src/HelloWorld. cpp:HelloWorld Pass 的源代码,一般来说一个 Pass 使用一个 cpp 文件实现即可。
  • Transforms/CMakeLists. txt:整个 CMake 项目的配置文件
  • test.sh

模板源码

实例代码
Cmakelists文件
模板 LLVM Pass 源码
编译脚本 test. sh 文件

最后实现的结果

notion image
实现了对示例程序中的每个函数进行扫描,并且输出“Hello”加上函数名
上一篇
DES加密算法
下一篇
AES和DES加密模式