低级中间语言(LLIL)解析
作为Binary Ninja逆向平台的核心特性之一,Low Level IL(LLIL)为开发强大的程序分析工具提供了基础。在Trail of Bits团队,我们利用LLIL自动化处理了大量CTF二进制文件,并实现了内存损坏漏洞的自动识别。
什么是低级中间语言?
编译器使用中间表示(IR)来分析和优化被编译的代码。Binary Ninja不仅能够反汇编二进制代码,还利用其自有的LLIL中间语言执行数据流分析。这种架构无关的分析使得用户能够查询任意指令处的寄存器值和栈内容。
查看LLIL
在UI界面中,LLIL仅可通过图形视图查看。IL视图使用中缀表示法,更接近高级语言的表现形式。值得注意的是,LLIL指令往往比汇编指令更多,因为汇编到LLIL的转换是一对多的过程。
LLIL结构
根据API文档,LLIL指令具有树状结构。指令树的根节点是由操作和0-4个子节点操作数组成的表达式。子节点可以是整数、字符串、整数数组或其他表达式。以下是典型表达式示例:
操作 | 操作数1 | 操作数2 | 操作数3 | 操作数4 |
---|---|---|---|---|
LLIL_NOP | ||||
LLIL_SET_REG | dest: 字符串或整数 | src: 表达式 | ||
LLIL_LOAD | src: 表达式 |
实例分析
mov eax, 2指令
该指令被转换为LLIL_SET_REG表达式,包含两个子节点:dest(eax寄存器)和src(LLIL_CONST表达式,值为2)。
lea eax, [edx+ecx*4]指令
该指令同样转换为LLIL_SET_REG表达式,但src子表达式更为复杂,包含加法(LLIL_ADD)和逻辑左移(LLIL_LSL)操作。
Python API使用
Binary Ninja提供了几个重要的LLIL相关Python类:
- LowLevelILFunction
- LowLevelILBasicBlock
- LowLevelILInstruction
指令访问
获取函数LLIL引用的第一步是通过Function对象的low_level_il属性。在GUI中,可以使用current_function.low_level_il获取当前函数的LowLevelILFunction对象。
递归遍历示例
以下函数递归遍历LLIL指令,输出表达式操作及其操作数:
|
|
提升IL与低级IL的区别
提升IL是解析可执行代码时首先生成的中间表示,而低级IL是经过优化后呈现给用户的版本。在大多数情况下,开发者应该使用低级IL进行分析工作。
开始使用LLIL
LLIL及其数据流分析已被用于解决2000个CTF挑战二进制文件。在后续文章中,我们将展示如何开发平台无关的插件来解析对象的虚方法表,使C++二进制文件的反向工程变得更加容易。
更新说明(2017年2月11日):本文已根据Binary Ninja最新API进行更新。