文章目录
IDApython 简介
安装
需提前安装python2.7
ida pro7.0 百度网盘链接
链接:https://pan.baidu.com/s/1XQX1w8QgFGQMef6jSaCnBQ
提取码:xe1t
可直接下载使用,无需配置
测试
- 使用IDA打开任意二进制文件
- 在输出窗口,选择python,并打印任意字符
- 观察是否能正常运行
背景
IDApython创建于04年,是将IDA中的接口提供给python,用于完成一些自动化的任务。
IDApython由三个独立模块组成,第一个是idc,它是封装IDA的IDA函数的兼容性模块,现在已经很少使用。第二个模块是idautils,这是IDA里的一个高级实用函数。第三个模块是idaapi,它允许访问更多低级的数据,这些数据能够被类使用通过IDA。
基础
获取当前地址:
ea = here()
print "0x" + hex(ea)
获取该程序中的最小地址:
Python>hex(MinEA())
0x401000L
#结尾的L是指这是一个long类型
获取改程序中的最大地址:
Python>hex(MaxEA())
0x409000L
访问某个元素的一些属性:
ea = here()
#获取一个地址,以此为索引
print idc.SegName(ea)
#获取该地址所在段名称
print idc.GetDisasm(ea)
#获取该地址的反汇编字符串
print idc.GetMnem(ea)
#获取助记符
print idc.GetOpnd(ea, 0)
#获取操作数,其中0为操作数索引
输出结果:
.text
push ebp
push
ebp
验证地址是否为有效地址:
Python>BADADDR
4294967295
Python>hex(BADADDR)
0xffffffffL
Python>idaapi.BADADDR
4294967295
ea = here()
if BADADDR != ea:
print "valid address"
输出:
valid address
遍历所有段,输出段名称,段开始和结束的地址
import idautils
for seg in idautils.Segments():
print idc.SegName(seg), hex(idc.SegStart(seg)), hex(idc.SegEnd(seg))
输出结果:
.text 0x401000L 0x402000L
.data 0x402000L 0x403000L
.rdata 0x403000L 0x404000L
.eh_frame 0x404000L 0x405000L
.bss 0x405000L 0x406000L
.idata 0x4060d0L 0x406164L
.CRT 0x407000L 0x408000L
.tls 0x408000L 0x409000L
获取下一节的起始地址:
ea = here()
print idc.SegName(ea)
eb = idc.NextSeg(ea)
输出结果:
.text
0x402000L
遍历所有已知函数:
import idautils
for func in idautils.Functions():
print hex(func), idc.GetFunctionName(func)
获取当前地址所在函数:
Python>ea = here()
Python>hex(ea)
0x4013f9L
Python>func = idaapi.get_func(ea)
Python>dir(func)
['__class__', '__del__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__getattribute__', '__gt__', '__hash__', '__init__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__swig_destroy__', '__weakref__', '_print', 'analyzed_sp', 'argsize', 'clear', 'color', 'compare', 'contains', 'does_return', 'empty', 'endEA', 'end_ea', 'extend', 'flags', 'fpd', 'frame', 'frregs', 'frsize', 'intersect', 'is_far', 'llabelqty', 'llabels', 'overlaps', 'owner', 'pntqty', 'points', 'referers', 'refqty', 'regargqty', 'regargs', 'regvarqty', 'regvars', 'size', 'startEA', 'start_ea', 'tailqty', 'tails', 'this', 'thisown']
Python>hex(func.startEA)
0x4013c9L
Python>hex(func.endEA)
0x40145eL
- dir(class)查询python中类的有效函数
- 枚举函数的一个警告是,只有当IDA将代码块标识为函数时,他才起作用。
- 在代码块被标记为一个函数之前,它将在函数枚举过程中跳过。
- 未标记为函数的代码将在图例中标记为红色(顶部的颜色栏),可以通过手动方法进行固定。
输出一个函数的反汇编:
ea = here()
start = GetFunctionAttr(ea, FUNCATTR_START)
end = GetFunctionAttr(ea, FUNCATTR_END)
cur_addr = start
while cur_addr <= end:
print hex(cur_addr),idc.GetDisasm(cur_addr)
cur_addr = idc.NextHead(cur_addr, end)
输出:
0x4013c9L push ebp
0x4013caL mov ebp, esp
0x4013ccL sub esp, 48h
0x4013cfL mov dword ptr [ebp+flag], 'l`!H'
0x4013d6L mov dword ptr [ebp+flag+4], 'i!`!'
0x4013ddL mov dword ptr [ebp+flag+8], 'djb`'
0x4013e4L mov dword ptr [ebp+flag+0Ch], 'e!-s'
0x4013ebL mov dword ptr [ebp+flag+10h], 'u&on'
0x4013f2L mov dword ptr [ebp+flag+14h], 'tnx!'
0x4013f9L mov dword ptr [ebp+flag+18h], '`br!'
0x401400L mov dword ptr [ebp+flag+1Ch], '>eds'
0x401407L mov [ebp+flag+20h], 0
0x40140bL mov [ebp+i], 0
0x401412L lea eax, [ebp+flag]
0x401415L mov [esp], eax; char *
0x401418L call _strlen
0x40141dL cmp eax, [ebp+i]
0x401420L jle short loc_401442
0x401422L lea edx, [ebp+flag]
0x401425L mov eax, [ebp+i]
0x401428L add eax, edx
0x40142aL movzx eax, byte ptr [eax]
0x40142dL xor eax, 1
0x401430L mov ecx, eax
0x401432L lea edx, [ebp+flag]
0x401435L mov eax, [ebp+i]
0x401438L add eax, edx
0x40143aL mov [eax], cl
0x40143cL add [ebp+i], 1
0x401440L jmp short loc_401412
0x401442L lea eax, [ebp+flag]
0x401445L mov [esp+4], eax; buf
0x401449L mov dword ptr [esp], offset filename; "hack"
0x401450L call __Z10Write_FilePKcS0_; Write_File(char const*,char const*)
0x401455L mov eax, 0
0x40145aL leave
0x40145bL retn 10h
- 缺点:包含在开始和结束的功能边界。如果有一个跳转地址高于函数的末尾循环也将过早的退出
根据标志位检索函数信息
- FUNC_NORET:用来标识一个函数没有执行返回指令,内部表示等于1
- FUNC_FAR:很少出现,除非逆向软件使用分段内存,内部表示2
- FUNC_LIB:用于查找库代码。标识库代码非常有用,因为是在执行分析时通常可忽略
- FUNC_STATIC:用于标示作为静态函数编译的函数,如果作者定义了一个函数为静态只能访问内部文件等功能,在有限方式下,这可以用来帮助理解源代码是如何构造的
- FUNC_FRAME:表明该函数使用栈指针ebp,使用栈指针的函数通常以设置堆栈框架的标准函数序言开始。
- FUNC_USERFAR:罕见,非常小的文件,用户已指定远性功能,内部表示32
- FUNC_HIDDEN:意味是隐藏的,需要扩展到视图
- FUNC_THUNK:thunk函数,跳转到另一个函数
- FUNC_BOTTOMBP:此标记用于跟踪栈指针
一个函数可以有多个标志;
import idautils
for func in idautils.Functions():
flags = idc.GetFunctionFlags(func)
if flags & FUNC_LIB:
print hex(func), "FUNC_LIB", GetFunctionName(func)
if flags & FUNC_FRAME:
print hex(func), "FUNC_FRAME", GetFunctionName(func)
if flags & FUNC_STATIC:
print hex(func), "FUNC_STATIC", GetFunctionName(func)
if flags & FUNC_HIDDEN:
print hex(func), "FUNC_HIDDEN", GetFunctionName(func)
if flags & FUNC_THUNK:
print hex(func), "FUNC_THUNK", GetFunctionName(func)
if flags & FUNC_BOTTOMBP:
print hex(func), "FUNC_BOTTOMBP", GetFunctionName(func)
if flags & FUNC_FAR:
print hex(func), "FUNC_FAR", GetFunctionName(func)
if flags & FUNC_USERFAR:
print hex(func), "FUNC_USERFAR", GetFunctionName(func)
获取函数中的所有地址
import idautils
addr = 0x00401350
dism_addr = list(idautils.FuncItems(addr))
print dism_addr
for line in dism_addr:
print hex(line), idc.GetDisasm(line)