没有合适的资源?快使用搜索试试~ 我知道了~
首页IDAPython文档
IDAPython文档
需积分: 26 219 浏览量
更新于2023-05-24
评论
收藏 1.54MB PDF 举报
IDAPython中文手册,有各种API使用例子,便于查阅也便于新手上路。
资源详情
资源评论
资源推荐

IDAPython 手册(翻译 by y0n)
介绍
这是一本关于 IDAPython 的手册,我最初写它是作为自己参考的,在我通常使用
IDAPython(忘记了)我想在某处能找到函数的例子。自从我开始这本书以来,我多次使用
它作为快速参考来理解语法或者查看一些例子代码。
如果你跟随我的博客,你可能会注意到一些熟悉的面孔–很多脚本,我在下面贴出了一
些在线实验的结果。
多年来,我收到许多电子邮件,问对于 IDAPython 什么是最好的学习指南?通常我会给
他们指出 Ero Carrera 介绍的 idapython 或在 idapython 的公共的 repo 示例脚本。它们是学习
的极好来源,但它们并没有涉及到我遇到的一些常见问题。我想写一本书,涵盖了这些问题。
我觉得对于学习 idapython 的人或者想快速参考学习例子和代码片段的人是有价值的。作为
电子书,它不会是静态的。我计划在未来定期更新它。
如果您遇到任何问题,错别字或有疑问,请发邮件给我。
更新
版本:1.0
免责声明
这本书不是为初学逆向工程的人设计的。它也不能作为一本介绍 IDA 的书。如果你是刚
开始接触 IDA,我建议你买 Chris Eagles 的 IDA Pro。这本书是优秀的且值得花钱的。
购买这本书有两个先决条件,你应该能很轻松的阅读汇编在一个你想工程的背景下并且
知道你所使用的 IDA。如果你碰到一个问题,问自己“如何使用 IDAPython 自动化完成一个
任务?”那么这本书可能适合你。如果你已经有一些 IDAPython 编程,在这种情况下这本书
不适合你。这本书适合初学 IDAPython 的人,它将作为一个手册方便查找例子,常用函数,
但是有经验的你已经有了自己的一些脚本参考。
应该说,我的背景是恶意代码逆向工程,本书不涉及编译器概念,如静态分析中使用的
基本块或其他学术概念。原因是,当逆向工程恶意软件时,我很少使用这些概念。偶尔我也
用它们去混淆代码基本够用,我觉得他们会对初学者来说是有价值的。读了这本书之后,读
者会感觉轻松并挖掘自己 idapython 文档。最后一个免责声明,IDA 调试器的功能不包括在
内。

规定
IDA 的输出窗口(命令行接口)用于示例和输出。为了简洁起见,有些示例不包含当前
地址对变量的赋值。通常表示为 EA = here()。所有的代码都可以剪切和粘贴到命令行或 IDA
的脚本命令的选项 shift-f2。从头到尾阅读是本书推荐的方法。有许多例子并不是一行一行
解释的,因为它假定读者理解前面例子中的代码。不同的作者调用 IDAPython 的方式不同,
有时候被调用为 idc.SegName(ea) 或者 SegName(ea)。在这本书中,我们将使用第一个风格。
我发现这个约定更容易阅读和调试。有时使用这个约定时,会抛出一个错误,如下所示:
Python>DataRefsTo(here())
<generator object refs at 0x05247828>
Python>idautils.DataRefsTo(here())
Traceback (most recent call last):
File "<string>", line 1, in <module>
NameError: name 'idautils' is not defined
Python>import idautils # manual importing of module
Python>idautils.DataRefsTo(here())
<generator object refs at 0x06A398C8>
如果这种情况发生则需要在显示前包含模块。
IDAPython 背景
IDAPython 创建于 2004 年。这是 Gergely Erdelyi 和 Ero Carrera 的共同努力。他们的目标
是结合强大的 python 与自动化分析的 IDA 的类 C 脚本语言 IDC。IDAPython 由三个独立模块
组成。第一个是 idc,它是封装 IDA 的 IDC 函数的兼容性模块。第二个模块是 idautils,这是
IDA 里的一个高级实用函数。第三个模块是 idaapi,它允许访问更多低级数据,这些数据能
够被类使用通过 IDA。
基础
在挖掘得太深之前,我们应该定义一些关键字,并检查 IDA 的反汇编输出的结构。我们
可以使用下面的代码行作为示例。
.text:00012529 mov esi, [esp+4+arg_0]
.text 是节的名称,地址是 00012529。显示的地址是 16 进制格式。mov 这个指令被称作
助记符。助记符后面的第一个操作是 esi 和第二个操作是[esp+4+arg_0],当使用 IDAPython
函数工作时,最常用的是传递变量的地址。在 IDAPython 文档中地址作为 ea 被引用。地址
可以通过几个不同的函数手动访问。最常用的功能是 idc.ScreenEA()或 here()。它们将返回一
个整型值。如果我们想要获得一个最小地址是在一个 idb 中,我们可以使用 MinEA()或者获
取最大地址我们可以使用 MaxEA()。
Python>ea = idc.ScreenEA()
Python>print "0x%x %s" % (ea, ea)

0x12529 75049
Python>ea = here()
Python>print "0x%x %s" % (ea, ea)
0x12529 75049
Python>hex(MinEA())
0x401000
Python>hex(MaxEA())
0x437000
每一个被反汇编的函数能被 IDAPython 访问。下面是一个例子,如何访问每个元素。请
重新调用我们预先存储在 ea 中的地址。
Python>idc.SegName(ea) # get text
.text
Python>idc.GetDisasm(ea) # get disassembly
mov esi, [esp+4+arg_0]
Python>idc.GetMnem(ea) # get mnemonic
mov
Python>idc.GetOpnd(ea,0) # get first operand
esi
Python>idc.GetOpnd(ea,1) # get second operand
[esp+4+arg_0]
获取表示段名的字符串我们会使用 idc.SegName(ea)与 ea 是一个段地址。打印一个反汇
编的字符串可以用 idc.GetDisasm(ea)。值得注意的是函数的拼写。获取助记符或者指令名称,
我们可以调用 idc.GetMnem(ea)。获取操作数的助记符我们可以调用 idc.GetOpnd(ea,long n)。
第一个参数是地址,第二个 long n 是操作数索引。第一个操作数是 0 和第二个是 1。
在某些情况下,验证一个地址是否存在是很重要的。idaapi.BADADDR 或 BADADDR 可以
用来检验有效地址。
Python>idaapi.BADADDR
4294967295
Python>hex(idaapi.BADADDR)
0xffffffffL
Python>if BADADDR != here(): print "valid address"
valid address
Segments(段)
打印一行作用不大。IDAPython 的强大来自于遍历所有的指令,交叉引用地址和搜索代
码或数据。后面两部分将在后面更详细地描述。遍历所有段将是一个不错的开始的位置。
Python>for seg in idautils.Segments():
print idc.SegName(seg), idc.SegStart(seg), idc.SegEnd(seg)
HEADER 65536 66208
.idata 66208 66636
.text 66636 212000

.data 212000 217088
.edata 217088 217184
INIT 217184 219872
.reloc 219872 225696
GAP 225696 229376
idautils.Segments()返回一个遍历类型对象,我们可以循环这个对象通过使用一个 for 循
环。列表 中 的每 个 项 都 是 段 的起 始 地址 。 如 果我 们 把 它 作 为 作 为一 个 参数 去 调 用
idc.SegName(ea),地址可以被用来获取名称。开始和结束的段可以通过调用 idc.SegStart(ea)
或 idc.SegEnd(ea)获得。地址或 ea 需要位于段的开始或结束的范围内。如果我们不想遍历所
有段,但想找到下一段我们可以使用 idc.NextSeg(ea)。地址可以是段范围内的任何我们希望
找到的下一段的地址。如果有机会我们想要通过名称获取一个段的开始地址,我们可以使用
idc.SegByName(segname)。
Functions(函数)
既然我们知道如何遍历所有段,我们就应该研究如何遍历所有已知函数。
Python>for func in idautils.Functions():
Print hex(func), idc.GetFunctionName(func)
Python>
0x401000 ?DefWindowProcA@CWnd@@MAEJIIJ@Z
0x401006 ?LoadFrame@CFrameWnd@@UAEHIKPAVCWnd@@PAUCCreateContext@@@Z
0x40100c ??2@YAPAXI@Z
0x401020 save_xored
0x401030 sub_401030
....
0x45c7b9 sub_45C7B9
0x45c7c3 sub_45C7C3
0x45c7cd SEH_44A590
0x45c7e0 unknown_libname_14
0x45c7ea SEH_43EE30
idautils.Functions()将返回一个已知函数列表。这个列表将包含起始地址的每一个函数。
idautils.Functions()可传递的参数范围内搜索。如果我们想要搜索可以通过开始地址和结束地
址 idautils.Funtions(start_addr, end_addr) 。 获 得 一 个 函 数 的 名 称 我 们 使 用
idc.GetFunctionName(ea)。ea 可以是函数边界的任何地址。IDAPython 含有大量的 API 集合
提供使用的函数。让我们从一个简单的功能开始。这个函数的语义不重要,但我们应该在心
里创建一个地址的记录。
.text:0045C7C3 sub_45C7C3 proc near
.text:0045C7C3 mov eax, [ebp-60h]
.text:0045C7C6 push eax ; void *
.text:0045C7C7 call w_delete
.text:0045C7CC retn
.text:0045C7CC sub_45C7C3 endp

获得边界我们可以使用 idaapi.get_func(ea)。
Python>func = idaapi.get_func(ea)
Python>type(func)
<class 'idaapi.func_t'>
Python>print "Start: 0x%x, End: 0x%x" % (func.startEA,
func.endEA)
Start: 0x45c7c3, End: 0x45c7cd
idaapi.get_func(ea)返回一个类的 idaapi.func_t。有时它并不总是显而易见的如何使用一
个类的返回通过一个函数调用。一个有用的命令去查询在 Python 中的类是 dir(class)函数。
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', 'extend', 'flags', 'fpd', 'frame', 'frregs',
'frsize', 'intersect', 'is_far', 'llabelqty', 'llabels',
'overlaps', 'owner', 'pntqty', 'points', 'referers', 'refqty',
'regargqty', 'regargs', 'regvarqty', 'regvars', 'size', 'startEA',
'tailqty', 'tails', 'this', 'thisown']
从这个输出我们能明白 startEA 和 endEA 用来访问函数的开始和结束。这些属性只适用
于 当 前 函 数 。 如 果 我 们 想 要 访 问 其 他 函 数 我 们 可 以 使 用 idc.NextFunction(ea) 和
idc.PrevFunction(ea)。ea 的值仅需要在分析的函数的边界的地址里。枚举函数的一个警告是,
只有当 IDA 将代码块标识为函数时,它才起作用。在代码块被标记为一个函数之前,它将在
函数枚举过程中跳过。未标记为函数的代码将在图例中标记为红色(顶部的颜色栏)。这些
可以手动固定或自动。IDAPython 有很多不同的方法来访问相同的数据。访问边界内的一种
常 见 的 方 法 是 使 用 一 个 函 数 idc.GetFunctionAttr(ea, FUNCATTR_START) 和
idc.GetFunctionAttr(ea, FUNCATTR_END)。
Python>ea = here()
Python>start = idc.GetFunctionAttr(ea, FUNCATTR_START)
Python>end = idc.GetFunctionAttr(ea, FUNCATTR_END)
Python>cur_addr = start
Python>while cur_addr <= end:
print hex(cur_addr), idc.GetDisasm(cur_addr)
cur_addr = idc.NextHead(cur_addr, end)
Python>
0x45c7c3 mov eax, [ebp-60h]
0x45c7c6 push eax ; void *
0x45c7c7 call w_delete
0x45c7cc retn
idc.GetFunctionAttr(ea, attr)是用来获取开始和结束的函数,然后我们打印当前地址和反
汇编通常使用 idc.GetDisasm(ea)。我们使用 idc.NextHead(eax)来获取下个指令的开始和继续
剩余36页未读,继续阅读

















安全验证
文档复制为VIP权益,开通VIP直接复制

评论0