安装LLVM组件
(官方文档)
因为要调试LLVM,所以需要从LLVM源码开始Debug模式编译安装。安装过程如下(如果内存较小,建议创建虚拟内存,不然编译过程可能内存耗尽,因为llvm
各个组件使用静态链接,很吃内存)
sudo apt install build-essential python3-pip cmake git
sudo pip install ninja # (可选)如果选择ninja取代make作为system generator
git clone --depth 1 https://github.com/llvm/llvm-project # 可以根据需求 -b 选择感兴趣的分支或tag
cd llvm-project
cmake -B build -DCOMPILER_RT_DEBUG=ON -DLLVM_TARGETS_TO_BUILD="X86" -DLLVM_ENABLE_PROJECTS="clang;compiler-rt;lld" -DLLVM_ABI_BREAKING_CHECKS=FORCE_OFF llvm/ -DCMAKE_INSTALL_PREFIX="/opt/llvm/"
cmake --build build -j$(nproc)
sudo cmake --install build
可以根据需求使用ninja取代make,添加"-G Ninja";-DCMAKE_BUILD_TYPE=Debug 表示Debug编译,默认就是Debug,所以可以不加。只编译X86
架构节省时间;使用gold
代替ld
作为链接器节省时间和内存开销(等装完lld
后,可使用lld
来替换ld
,就如这里提到的);安装clang
(编译器)、compiler-rt
(包含LibFuzzer
)、lldb
(代替gdb
,这个组件不装也可以)和lld
(代替ld
,比gold
更快,这个组件不装也可以)组件;安装目录指定为/opt/llvm/
(可以自由选择,装在/opt
目录要求cmake --install build
时前面加上sudo
)。-DCOMPILER_RT_DEBUG=ON
声明compiler-rt
用O0编译而非默认的O3
使用Ninja
作为Generator比Unix Makefiles
更节省时间一些。对此需要pip install ninja
以当前用户身份安装ninja。当sudo ninja install
时需要以root用户身份使用ninja,因此需要sudo pip install ninja
或sudo apt install ninja-build
。
如果需要编译之前未编译的组件,无需清空build
目录,只需要再cmake
并编译安装即可。
然后去~/.bashrc
最后加上export PATH=$PATH:/opt/llvm/bin
来添加环境变量Path
。
挑选Sample Code
这里使用libfuzzer-workshop中的Lesson 4作为Sample Code来调试。
可以先编译运行一遍first_fuzzer.cc
(会include
vulnerable_functions.h
)验证LLVM组件安装正确(当前也可以在llvm-project/build
目录ninja check-${whatever}
来验证组件),路径请自行调整。
cd /home/leone/下载/libfuzzer-workshop/lessons/04/
clang++ -g -std=c++11 -fsanitize=address,fuzzer first_fuzzer.cc -o first_fuzzer
mkdir corpus1
./first_fuzzer corpus1
很快就能发现ASAN报了堆溢出漏洞
==60092==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000003e33 at pc 0x000000551a07 bp 0x7ffd1587a4b0 sp 0x7ffd1587a4a8
调试clang++
使用gdb
(也可使用llvm
项目提供的lldb
)开始调试clang++
。
$ gdb clang++
经过漫长的加载后,在gdb
中设置一下clang++的参数(参数里的待编译文件的路径请自行调整一下),和上面直接编译运行类似。
set args -g -std=c++11 -fsanitize=address,fuzzer /home/leone/下载/libfuzzer-workshop/lessons/04/first_fuzzer.cc -o /home/leone/下载/libfuzzer-workshop/lessons/04/first_fuzzer
让gdb
在程序fork后追踪子进程(clang父进程将具体任务交给子进程完成)。
set follow-fork-mode child
在main
函数下断点。
b main
后续
ASAN源码分析内容我放在《LLVM ASAN【源码分析】(三)》