环境:IDAPro 7.6
(注意IDAPro 7.4版本后,IDA Python的API版本与7.4之前的版本发生了很多变化,具体区别请看https://hex-rays.com/products/ida/support/ida74_idapython_no_bc695_porting_guide.shtml)
常见模块
在IDA中.有三个重要的库.分别是IDC,idautils,idaapi
| 模块 | 功能 |
|---|---|
| IDC | 封装IDA与IDC函数的兼容性模块. |
| idautils | 高级实用的模块 |
| idaapi | 允许访问更加底层的数据 |
获取IDA界面地址
| 功能 | 函数 |
|---|---|
| 取当前地址 | idc.here() 或 idc.get_screen_ea() |
| 获取最小地址(可以使用的) | ida_ida.inf_get_min_ea() |
| 获取最大地址(可以使用的) | ida_ida.inf_get_max_ea() |
| 获取所选范围的起始地址 | idc.read_selection_start() |
| 获取所选范围的结束地址 | idc.read_selection_end() |
import idc |

获取地址的数值
| 功能 | 函数 |
|---|---|
| 以1字节为单位获取地址处的值 | idc.get_wide_byte(addr) |
| 以2字节(字)的单位获取 | idc.get_wide_word(addr) |
| 以4字节的单位获取 | idc.get_wide_dword(addr) |
| 以8字节的单位获取 | idc.get_qword(addr) |
| 判断是否是字节 | ida_bytes.is_byte |
import idc |

修改指令数值
| 功能 | 函数 |
|---|---|
| 修改addr地址的值为value.每次修改1个字节 | ida_bytes.patch_byte(addr,value) |
| 每次修改2个字节 | ida_bytes.patch_word(addr,value) |
| 每次修改4个字节 | ida_bytes.patch_Dword(addr,value) |
| 每次修改8个字节 | ida_bytes.patch_Qword(addr,value) |
import idc |

汇编指令操作
| 功能 | 函数 |
|---|---|
| 获取地址处的汇编语句 | idc.GetDisasm(addr) 或 idc.generate_disasm_line(addr,flags) |
| 获取指定地址位置的操作数.参数1是地址.参数2是操作数索引.如 mov ebp,esp中: 操作数1是ebp ,操作数2是esp mov则是汇编指令不是操作数 | idc.print_operand(addr,index) |
| 获取汇编操作指令(如mov、add) | idc.print_insn_mnem(addr) |
| 获取操作数的类型 | idc.get_operand_type(addr,index) |
| 获取指定索引操作数中的值: 如 calll 0x00402004 对应汇编为: FF 15 04 20 40 00 FF15=Call 而操作数的值则为04 20 40 00 (小端) 使用函数之后获取则为地址 00402004 | idc.get_operand_value(addr,index) |
| 获取下一行汇编 | idc.next_head(addr) |
| 获取上一行汇编 | idc.PrevHead(addr) |
import idc |

段操作
| 功能 | 函数 |
|---|---|
| 获取段的名字(参数为当前的地址) | idc.get_segm_name(addr) |
| 获取段的开始地址 | idc.get_segm_start(addr) |
| 获取段的结束地址 | idc.get_segm_end(addr) |
| 获取第一个段 | idc.get_first_seg(addr) |
| 获取下一个段 | idc.get_next_seg(addr) |
| 返回一个列表记录所有段的地址 | idautil.Segments() |
import idc |

函数操作
| 功能 | 函数 |
|---|---|
| 获取指定地址之间的所有函数 | idautils.Functions(startaddr,endaddr) |
| 获取指定地址的函数名 | idc.get_func_name(addr) |
| 获取函数的注释 | get_func_cmt(addr, repeatable) repeatable:0/1 0是获取常规注释 1是获取重复注释 |
| 设置函数注释 | idc.set_func_cmt(ea, cmt, repeatable) |
| 弹出框框要求用户进行选择 参数则是信息 | idc.choose_func(title) |
| 返回: addr 距离函数的偏移形式 | idc.get_func_off_str(addr) |
| 寻找函数结尾,如果函数存在则返回结尾地址,否则返回BADADDR | idc.find_func_end(addr) |
| 设置函数结尾 | ida_funcs.set_func_end(ea, newend) newend:新的结束地址 |
| 设置函数开头 | ida_funcs.set_func_start(addr, newstart) |
| 设置地址处的名字 | idc.set_name(ea, name, SN_CHECK) Ex函数也使用set_name |
| 获取首个函数 | idc.get_prev_func(ea) |
| 获取下一个函数 | idc.get_next_func(ea) |
import idc |

数据查询
在IDAPython中如果我们想查询某些 数据 代码 二进制 都可以用都搜索函数。
搜索函数可以是向上搜索 也可以是向下搜索. 搜索失败就会返回-1 也就是BADADDR。
而搜索功能也常常用于去除花指令当中。
| 功能 | 函数 |
|---|---|
| 查找二进制找到返回地址没找到返回-1(BADADDR) | idc.find_binary(ea, flag, searchstr, radix=16, from_bc695=False) |
| 从ea开始寻找下一个数据地址 | ida_search.find_data(ea, sflag) |
| 从ea开始寻找下一个代码地址 | ida_search.find_code(ea, sflag) |
| 跳转到ea位置 | ida_kernwin.jumpto(ea) |
flags取值:
SEARCH_DOWN 向下搜索 |
import idc |

数据校验函数
数据校验函数有一个参数flag,得到flag后可以直接进行校验
| 功能 | 函数 |
|---|---|
| 获取标志 | ida_bytes.get_full_flags(ea) |
| 判断是否为代码 | ida_bytes.is_code(f) f即标志 |
| 判断是否为数据 | ida_bytes.is_data(f) |
import idc |

交叉引用
在IDA的操作中 我们常常会对一个函数按X快捷键来查看谁引用了
| 功能 | 函数 |
|---|---|
| 获取地址处引用位置 A调用B 对B函数地址使用此函数则找到A调用 返回列表.遍历列表则可以找出所有引用位置. 参数1是ea也就是地址,参数2告诉IDA是否跟踪这些代码. | idautils.CodeRefsTo(ea, flow) |
| 返回ea的代码引用了何处的代码. 返回一个列表 | idautils.CodeRefsFrom(ea, flow) |
| 返回一个列表告诉ea位置的数据被谁引用了 | idautils.DataRefsTo(ea) |
| 告诉我们ea引用了谁. | idautils.DataRefsFrom(ea) |
import idc |

除了上述通过地址来查找引用的方式外,还可以通过函数名来进行查找交叉引用:
1、先通过idc.get_name_ea_simple(fun_name)找到函数的线性地址
2、再使用for i in CodeRefsTo(addr,False)得到所有引用的地址
一个例子:https://hotspurzzz.github.io/2021/11/12/IDA-Python 批量脚本分析程序/
官网API文档:
https://www.hex-rays.com/wp-content/static/products/ida/support/idapython_docs/
参考链接:
