给出的文件名为rabbithole
首先使用file命令查看一下
可以看到是64位的可执行文件
接下来我们切换到win,使用IDApro,以此文件为样例,学习IDAPython的用法。
操作数在逆向分析中经常被使用,所以了解所有的操作数对逆向分析非常有帮助。我们可以使用idc.GetOpTye(ea,n)来获取操作数类型,ea是一个地址,n是一个索引,从0开始。操作数一共有八种不同的类型。
O_void:如果指令没有任何操作数,则返回0
O_reg:如果操作数是寄存器,则返回这种类型,值为1
O_mem:如果操作数是直接寻址的内存,那么返回该类型,值为2,这种类型对寻找DATA非常有帮助
O_phrase:如果操作数是利用基址寄存器和变址寄存器的寻址操作的话,返回该类型,值为3
O_displ:如果操作数利用寄存器和位移的寻址操作的话,返回该类型,值为4,位移指的是类似下图中的0x18,这在获取结构体中的某个数据是非常常见的。
O_imm:如果操作数是一个确定的数值,那么返回该类型,值为5
O_far:这种返回类型在x86,x86_64的逆向中不常见,它用来判断直接访问远端地址的操作数,值为6
O_near:这种返回类型在x86,x86_64的逆向中不常见,它用来判断直接访问近端地址的操作数,值为7
我们可以在IDA中找到对应的类型进行测试
我这里就演示一个,我们把光标定位到pop rbx
然后再输出窗口测试
可以看到返回是1,对应这条指令我们知道其操作数为寄存器,所以确实应该返回1
接下来我们结合以上所学,来看几个小dmeo
在IDA中我们会看到汇编代码的某些指令不会被识别为偏移量,如下所示
如果我们右键选中后将其更改数据类型,就会看到字符串的偏移量
比如选中20h,右键-》offset qword_20
结果如下所示
这样子做一两次也无所谓,不过既然学习了IDAPython我们可以通过脚本将其以offset偏移的形式展现
import idautils
import idaapi
min = MinEA()
max = MaxEA()
for func in idautils.Functions():
flags = idc.GetFunctionFlags(func)
if flags & FUNC_LIB or flags & FUNC_THUNK:
continue
dism_addr = list(idautils.FuncItems(func))
for curr_addr in dism_addr:
if idc.GetOpType(curr_addr,0) == 5 and (min < idc.GetOperandValue(curr_addr,0) < max):
idc.OpOff(curr_addr,0,0)
if idc.GetOpType(curr_addr,1) == 5 and (min < idc.GetOperandValue(curr_addr,1) < max):
idc.OpOff(curr_addr,1,0)
运行后如图所示
代码解释:
一开始通过MinEA()和MaxEA()获取可执行文件的最大地址和最小地址,我们遍历了所有的函数和指令。对于每条指令检查他的操作数类型是否为o_imm(5),o_imm类型的操作数就是一个确定的数值或者偏移,一旦发现是这种类型的操作数,我们就用idc.GetOperandValue(ea,n)来获取它的值,然后检测一下是否在可执行文件的最大地址和最小地址之间。最后利用idc.OpOff(ea,n,base)来讲操作数转换为一个偏移,该函数的第一个参数为地址,第二个参数为操作数的索引,第三个参数为基地址,在代码中我们将其设为0就可以了
在IDA中,交叉引用是一项非常重要的功能,交叉引用的重要性在于它能够提供某个确定的数据或者某个函数被调用的位置。比如我们要找check_value函数在哪儿被调用,我们手工的话就是定位到check_value,右键->jump to xref to operand可以看到交叉引用
既然我们现在学了IDAPython,我们就可以使用脚本来完成这项工作。
代码如下
import idautils
checkvalue = idc.LocByName(“check_value”)
for addr in idautils.CodeRefsTo(checkvalue,0):
print hex(addr),idc.GetDisasm(addr)
代码解释:首先使用idc.LocByName(str)来获取check_value的地址,str为函数名称,返回地址为该api的地址。使用idautils.CoreRefsFrom(ea,flow)函数来返回所有调用了check_value的地址,该返回的结果可以通过循环进行迭代,ea是用于查找相应交叉引用的地址,flow是一个布尔值,用于标记是否监视一个正常的代码流。对应于idautils.CoreRefsFrom(ea,flow),还有idautils.CoreRefTo(ea,flow),它可以获取一个确切地址引用了哪些地址的数据。用法都是一样的,不再演示。