IDAPython基础教程2

给出的文件名为rabbithole
在这里插入图片描述
首先使用file命令查看一下
在这里插入图片描述
可以看到是64位的可执行文件
接下来我们切换到win,使用IDApro载入,以此文件为样例,学习IDAPython的用法。
IDAPython有非常多获取数据的方式,最常用的是通过idc.GetFunctionAttr(ea,FUNCATTR_START)和idc.GetFunctionAttr(ea,FUNCATTR_END)两个调用来获取一个函数的边界地址。
在这里插入图片描述
结果如下
在这里插入图片描述来解释下代码:idc.GetFunctionAttr(ea,attr)可以用来获取某个函数的首尾地址,idc.GetDisasm(ea)获取当前地址的反汇编代码。然后利用idc.NextHead()不停地获取下一个指令的地址,直到函数的结束地址才停止。
GetFuntionFlags(ea)是一个类似于idc.GetFunctionAttr(ea,attr)的信息搜集函数。它可以用于检索有关函数的信息,例如它是否是库中代码、是否有返回值等。对于一个函数来说有九个可能的标志,我们使用下面的代码来枚举:
import idautils
ea = idc.ScreenEA()
print ea
for func in idautils.Functions():
flags = idc.GetFunctionFlags(func)
if flags & FUNC_NORET:
print hex(func),“FUNC_NORET”
if flags & FUNC_FAR:
print hex(func),“FUNC_FAR”
if flags & FUNC_LIB:
print hex(func),“FUNC_LIB”
if flags & FUNC_STATIC:
print hex(func),“FUNC_STATIC”
if flags & FUNC_FRAME:
print hex(func),“FUNC_FRAME”
if flags & FUNC_USERFAR:
print hex(func),“FUNC_USERFAR”
if flags & FUNC_HIDDEN:
print hex(func),“FUNC_HIDDEN”
if flags & FUNC_THUNK:
print hex(func),“FUNC_THUNK”
if flags & FUNC_BOTTOMBP:
print hex(func),“FUNC_BOTTOMBP”
在这里插入图片描述代码解释:利用idautils.Funciton()来获取所有已知的函数首地址,然后使用Idc.GetFunctionFlags(ea)获取标志。我们在代码中利用&来检查每个函数是否拥有某个标志。
下面分别介绍下这九个标志。
FUNC_NORET:这个标志表示某个函数是否有返回值,本身的值是1,没有返回值的函数,类似下面这样
在这里插入图片描述FUN_FAR:这个标志不常出现,用于标志程序是否使用分段内存,值为2
FUN_USERFAR:也不常见,官方文档描述为”user has specified far-ness of the function”,它的值是32
FUN_LIB:表示用于寻找库函数的代码,它的值是4
FUNC_STATIC:作用于是被该函数在编译的是否是一个静态函数。在C语言中静态函数被默认是认为是全局的,如果作者把这个函数定义为静态函数,那么这个函数只能被本文件中的函数访问。利用静态函数的判定我们可以更好地理解源代码的结构。
FUNC_FRAME:表示函数是否使用了ebp寄存器(帧指针),使用ebp寄存器的函数通常有如下的语法设定,目的是为了保存栈帧。
在这里插入图片描述FUNC_BOTTOMBP:和FUNC_FRAME一样,用于跟着帧指针(ebp),它的作用是识别函数中帧指针是否等于堆栈指针(esp)
FUNC_HIDDEN:带有FUNC_HIDDEN标志的函数意味着它们是隐藏的,这个函数需要展开才能查看。
FUNC_THUNK:表示这个函数是否是一个thunk函数,thunk函数表示的是一个简单的跳转函数。
在这里插入图片描述需要注意的是,一个函数可能拥有多个标志的组合。
在这里插入图片描述这一块非常重要,我们再来实现一个功能–列举所有不会return的函数,我们由上面的知识可以知道,即FUNC_NORET
代码如下:
import idautils
ea = idc.ScreenEA()
print ea
for func in idautils.Functions():
flags = idc.GetFunctionFlags(func)
if flags & FUNC_NORET:
print hex(func),“FUNC_NORET”,GetFunctionName(func)
在这里插入图片描述上一节我们已经知道如何操作函数来获取他们的指令,如果我们拥有一个函数中的指令地址,则可以使用idautils.FuncItems(ea)来获取该函数中所有指令地址的集合
import idautils
ea = idc.ScreenEA()
print ea
dism_addr = list(idautils.FuncItems(ea))
print type(dism_addr)
print dism_addr
for line in dism_addr:
print hex(line),idc.GetDisasm(line)
在这里插入图片描述来解释下代码:idautis.FunItems(ea)实际上返回的是一个迭代器,但是我们将它强制转换为list类型。这个list以一种连续的方式存储着所有指令的起始地址。我们之前学习过如何循环遍历程序中的段、函数、指令,我们在这个脚本中就用到了。

有时候我们会逆向一个加壳的代码,这时候知道代码中哪里进行了动态调用对分析是非常有帮助的。一个动态的调用可能是由call或者jump加上一个操作数来实现的,比如call eax,或者jmp edi。我们可以通过下面的脚本将存在相应特征的指令打印出来。
import idautils
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 line in dism_addr:
m = idc.GetMnem(line)
if m == ‘call’ or m == ‘jmp’:
op = idc.GetOpType(line,0)
if op == o_reg:
print “0x%x %s” % (line,idc.GetDisasm(line))
在这里插入图片描述代码解释:
脚本中通过调用idautils.Functions获取已知的函数地址列表,对于每一个函数通过idc.GetFunctionFlags()来获取其对应的flags,其中过滤掉为FUNC_LIB和FUNC_THUNK的函数类型。然后通过idautils.FuncItems(ea)获取选中函数的所有指令地址,循环遍历该地址,通过idc.GetMenm(ea)获取所有操作码为call和jmp的指令地址。判断通过之后使用idc.GetOpType(ea,n)取该地址上指令的第一个操作数。判断该操作数的类型,函数会返回一个整型变量,分别表示该地址是一个寄存器、内存还是引用,代码中是判断类型是否为寄存器,如果是则将其打印出来。

这里可能会有个疑问,为什么要将idautils.FuncItems(ea)的返回类型强制转换成list呢?因为迭代器是没有len()函数的,通过强制转换将其放入list中可以实现获取指令的操作,如下所示是获取长度
import idautils
ea = idc.ScreenEA()
print len(list(idautils.FuncItems(ea)))

在这里插入图片描述我们已经学习了通过遍历list中的每个实体来获取下一条指令,那么如果我们拥有一个确定的地址,该怎么获取这个地址的下一条指令呢?使用idc.NextHead(ea)或者idc.PrevHead(ea)获取的是对应指令而不是地址,获取地址的话得使用idc.NextAddr(ea),idc.PrevAddr(ea)
import idautils
ea = idc.ScreenEA()
print hex(ea),idc.GetDisasm(ea)
next_instr = idc.NextHead(ea)
print hex(next_instr),idc.GetDisasm(next_instr)
pre_instr = idc.PrevHead(ea)
print hex(pre_instr),idc.GetDisasm(pre_instr)
print hex(idc.NextAddr(ea))
print hex(idc.PrevAddr(ea))
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值