上一篇讲解了如何加载一个Luac文件到IDA Pro当中,加载进入idb数据库的内容犹如切好洗净的食材,并不能粗暴的直接展示给用户,还需要IDA Pro中的处理器模块对内容进行下一步的反汇编渲染与指令功能注释,才能最终装盘食用。
处理器模块的工作就是:解析不同段的内容,确定代码段后,通过指定的指令格式解析与构造指令;确定指令使用的数据类型、寄存器与助记符;执行代码段的线性式代码反汇编;为指令标记注释与交叉引用等。
处理器模块架构
IDA Pro没有详细的文档描述如何开发处理器模块,最有效的学习途径是阅读IDA Pro程序中自带的开源的处理器模块代码。IDA Pro的处理器模块比文件加载器在架构上要更加晦涩难懂,实现起来也要复杂得多。
本篇写作时,对应的IDA Pro版本为国内众所周知的IDA Pro版本7.0,实验环境为macOS 10.12平台,处理器模块的开发选择使用Python。在IDA Pro软件的加载器目录(macOS平台):/Applications/IDAPro7.0/ida.app/Contents/MacOS/procs中,有着3个Python编写的处理器模块代码,分别是spu.py、ebc.py、msp430.py,如果安装了IDA Pro的开发SDK,在其中的module/script目录下也会找到这些模块,另外,还会包含一个proctemplate.py模板。
理论上,本节编写的Luac处理器模块,放到Windows等其他平台上,不需要进行任何的修改,也可以很好的工作。 本次参考使用到的代码是ebc.py模块,因为它的实现代码量不算最少,但在指令的解码处理上,代码更加直观。
处理器模块要求py中有一个定义为PROCESSOR_ENTRY()的方法,它的返回值是一个processor_t类型的类结构,IDA Pro通过检查这个类的字段,与回调它的方法,来完成指令的处理。一个精简的代码架构如下:
class ebc_processor_t(processor_t):
...
# ----------------------------------------------------------------------
def __init__(self):
processor_t.__init__(self)
self.PTRSZ = 4 # Assume PTRSZ = 4 by default
self.init_instructions()
self.init_registers()
...
...
def PROCESSOR_ENTRY():
return ebc_processor_t()
ebc_processor_t类中有很多的回调函数,它们都会在特定的场景下触发执行,所有的回调方法,可以在当前版本的IDA Pro的ida_idp.py文件中,查看processor_t的类型声明得知,不过可以发现,processor_t的声明是由swig自动生成的桥接到C的代码,看不出任何有价值的地方,在实际编写代码时,可能需要查看Python编写的处理器模块的回调函数注释,来理解回调的参数与使用场景,也可以直接查看processor_t类型在C语言中的声明,它的定义可以在SDK的include目录下的idp.hpp头文件中找到,在实现上,SDK中也包含了很多C语言编写的处理器模块,代码也很有参考价值。
这里的ebc_processor_t的__init__()方法中,会调用init_instructions()初始化处理器模块用到的指令,以及调用init_registers()初始化处理器模块用到的寄存器信息,这是一种通用的设置流程,我们在下面的代码中也采用这种方式完成Luac的相关初始化。
Luac处理器模块的实现
下面来动手实现Luac的处理器模块,同样的,它只支持基于Lua 5.2生成的Luac文件。 将ebc.py模块复制一份改名为loacproc.py。并修改ebc_processor_t为lua_processor_t,它的`_init()`代码不需要进行修改,代码如下:
def __init__(self):
processor_t.__init__(self)
self.PTRSZ = 4 # Assume PTRSZ = 4 by default
self.init_instructions()
self.init_registers()
self.PTRSZ描述了使用到的指针类型所占的字节大小,对于32位的Luac来说,它的值为4,通常只有在编写64位的程序处理器模块时,它的值才是8。init_instructions()与init_registers()分别用来初始化指令与寄存器列表,我们需要修改它的方法的实现部分。
在开始讲解指令与寄存器的修改前,我们先看看processor_t中需要修改的一些字段,它们的片断如下:
PLFM_LUAC = 99
class lua_processor_t(processor_t):
# IDP id ( Numbers above 0x8000 are reserved for the third-party modules)
id = PLFM_LUAC
# Processor features
flag = PR_DEFSEG32 | PR_USE64 | PRN_HEX | PR_RNAMESOK | PR_NO_SEGMOVE | PR_TYPEINFO
# Number of bits in a byte for code segments (usually 8)
# IDA supports values up to 32 bits
cnbits = 8
# Number of bits in a byte for non-code segments (usually