## 概述 现代编译器普遍采用前后端分离的设计,中间表示(Intermediate Representation, IR)与源语言和目标语言无关 ![Clang pipeline](https://hackmd.io/_uploads/SyEM5rAi2.png) ![Rustc pipeline](https://blog.rust-lang.org/images/2016-04-MIR/flow.svg) LLVM IR仅有一种,其三种表示形式: * Human-readable IR, LLVM Assembly(\*.ll) * On-disk bitcode IR, LLVM Bitcode(\*.bc) * In-memory compiler IR LLVM pass 是 LLVM 中负责对 LLVM IR 进行 transformation 的组件,Pass 就是“遍历一遍IR,同时对它做一些操作”的意思。翻译成中文应该叫“趟”,编译器的转换和优化部分可以视为若干 Pass 的流水线 作为编译器后端, LLVM 允许编译器开发者向 optimizer 中注入或重写 LLVM pass,在实现上,LLVM的核心库中包含若干 Pass 类可供继承 LLVM Pass的用处是插桩,机器无关的代码优化,静态分析,代码混淆等 参见 [LLVM Pass 入门导引][LLVM Pass Tutorial] ### LLVM 工具 * llvm-as:"汇编器" LLVM Assembly -> LLVM Bitcode * llvm-dis:"反汇编器" LLVM Bitcode -> LLVM Assembly * opt:优化器 LLVM IR optimizer * llc:"编译器" LLVM IR -> ASM * lli:"解释器" LLVM IR Interpreter ## LLVM Pass PWN LLVM Pass PWN 在近年的 CTF 中已经较为常见,其通常提供题目使用的 opt 和存在漏洞的 pass 模块,选手需要编写一段程序, 以 LLVM IR 形式交予加载了该漏洞 pass 编译器编译来获取编译机器上存放的 flag 大多数Pass类题目是这样实现的:重写 runOnFunction,处理 IR 中具有特定名称的函数,这些函数会事先预留一些漏洞,比如后门、任意地址读写、数组越界读写、整数溢出等等。 最常规的模式:任意地址读写 写got表或free_hook * 红帽杯-2021 simpleVM(任意地址读写读got改free) * CISCN-2021 staool(堆上脏数据泄露+任意地址执行) * 强网杯-2022 yakagame(负数索引导致的数组越界写+后门) 栈溢出: Pass只运行一次,要求利用 leakfree * CISCN-2022 satool(JIT Spray) ---- [LLVM Pass Tutorial]:https://zhuanlan.zhihu.com/p/122522485 [LLVM Pass PWN]:https://zhuanlan.zhihu.com/p/535985826