IDA Pro 在 9.0 版本带来了许多令人兴奋的新功能和改进,但随之而来的是 IDAPython API 的一些重大调整,这可能导致许多为 IDA 8.x 或更早版本编写的 Python 插件无法直接在新版本中运行。其中,最常见的不兼容性主要集中在访问数据库信息和窗口/视图类型判断上。
本篇文章将重点讲解这些关键的 API 变更,并提供具体的代码示例,帮助你顺利地将现有的 IDAPython 插件升级到兼容 IDA 9.x 的版本。
Hex-Rays 在 IDA 9.x 中重构了部分内部结构和 API 设计,目的是为了提高 API 的一致性、可维护性和未来的扩展性。这种变化虽然在短期内带来了一些兼容性问题,但从长远来看,有助于构建更稳定和健壮的插件生态系统。
在 IDA 9.0 之前,我们经常使用 ida_idaapi.get_inf_structure()
函数来获取一个 inf_structure
对象,这个对象包含了当前加载的 IDB 文件的各种全局信息,例如处理器类型、位数、文件格式等。你可能习惯于通过 inf = ida_idaapi.get_inf_structure()
然后访问 inf.is_64bit()
或 inf.procname
等属性或方法。有时也会直接使用 idaapi.cvar.inf
来访问。
旧的代码示例 (IDA < 9.0):
import idaapi
info = idaapi.get_inf_structure()
if info.is_64bit():
print("This is a 64-bit database.")
BITS = 64
elif info.is_32bit():
print("This is a 32-bit database.")
BITS = 32
else:
print("Unknown bitness.")
BITS = 16
proc_name = info.procname
print(f"Processor: {proc_name}")
# 访问类型信息
# type_info = idaapi.cvar.idati
IDA 9.0+ 的变化与修改方法:
在 IDA 9.0 及更高版本中,ida_idaapi.get_inf_structure()
函数被移除,idaapi.cvar.inf
也不再是访问 inf 结构体的推荐方式。取而代之的是一系列更细化的函数,通常位于 ida_ida
模块下。
inf.xx
访问的成员,现在通常通过 ida_ida.inf_get_xx()
函数获取。inf.is_xx()
判断的标志,现在通常通过 ida_ida.inf_is_xx()
函数判断。idaapi.get_idati()
函数。新的代码示例 (IDA >= 9.0):
import idaapi
import ida_ida # 导入 ida_ida 模块
# 获取位数信息
if ida_ida.inf_is_64bit():
print("This is a 64-bit database.")
BITS = 64
elif ida_ida.inf_is_32bit():
print("This is a 32-bit database.")
BITS = 32
else:
print("Unknown bitness.")
BITS = 16
# 获取处理器名称
proc_name = ida_ida.inf_get_procname()
print(f"Processor: {proc_name}")
# 访问类型信息
type_info = idaapi.get_idati()
总结: 将所有对 idaapi.get_inf_structure()
和 idaapi.cvar.inf
的调用替换为 ida_ida
模块中对应的 inf_get_*
或 inf_is_*
函数,并将 idaapi.cvar.idati
替换为 idaapi.get_idati()
。记得导入 ida_ida
模块。
在插件开发中,我们经常需要判断当前用户聚焦的是哪种视图(如反汇编视图、Hex 视图、结构体视图等),以便决定是否启用某个操作或在弹出菜单中添加特定项。过去,这通常通过检查 ctx.form_type
属性并与 idaapi.BWN_*
常量进行比较来实现。
旧的代码示例 (IDA < 9.0):
import idaapi
# 在 update 方法或类似的上下文中使用
# if ctx.form_type == idaapi.BWN_DISASM or ctx.form_type == idaapi.BWN_DUMP:
# # ... 执行只在反汇编或 Dump 视图下才有的操作
IDA 9.0+ 的变化与修改方法:
在 IDA 9.0+ 中,ctx.form_type
属性被弃用,推荐使用 ctx.widget_type
。更重要的是,表示不同窗口/视图类型的 BWN_*
常量不再直接位于 idaapi
模块下,而是被移到了 ida_kernwin
模块。并且,一些常量的名称可能发生了变化,例如 BWN_DUMP
在 IDA 9.1 中已改名为 BWN_HEXVIEW
。
action_handler_t
的 update
方法中,使用 ctx.widget_type
。在 UI 钩子(如 finish_populating_widget_popup
)中,如果提供了 widget 对象,可以使用 ida_kernwin.get_widget_type(widget_object)
。ida_kernwin.BWN_*
常量。需要根据实际的 IDA 版本查找正确的常量名称(例如,IDA 9.0 可能是 BWN_DUMP
,而 IDA 9.1 是 BWN_HEXVIEW
)。新的代码示例 (IDA >= 9.0):
import idaapi
import ida_kernwin # 导入 ida_kernwin 模块
# 在 action_handler_t 的 update 方法中使用
class YourActionHandler(idaapi.action_handler_t):
# ... __init__ 方法 ...
def update(self, ctx):
# 使用 ctx.widget_type 检查 widget 类型
if ctx.widget_type in (ida_kernwin.BWN_DISASM, ida_kernwin.BWN_HEXVIEW): # 注意 BWN_DUMP 改为 BWN_HEXVIEW
return idaapi.AST_ENABLE_FOR_WIDGET
else:
return idaapi.AST_DISABLE_FOR_WIDGET
# 在 UI 钩子中使用 (例如 finish_populating_widget_popup)
class YourUIHooks(ida_kernwin.UI_Hooks):
# ... __init__ 方法 ...
def finish_populating_widget_popup(self, form, popup):
# 使用 ida_kernwin.get_widget_type 获取 widget 类型
widget_type = ida_kernwin.get_widget_type(form)
# 检查 widget 类型
if widget_type == ida_kernwin.BWN_DISASM or widget_type == ida_kernwin.BWN_HEXVIEW: # 注意 BWN_DUMP 改为 BWN_HEXVIEW
# ... 附加菜单项 ...
pass
总结: 将 ctx.form_type
替换为 ctx.widget_type
。将所有 idaapi.BWN_*
常量替换为 ida_kernwin.BWN_*
中对应的新名称。如果你需要从 widget 对象获取类型,使用 ida_kernwin.get_widget_type()
。记得导入 ida_kernwin
模块。
除了上述两个主要不兼容点,IDA 9.x 的 API 可能还有其他一些变化,例如:
idaapi
中的平台常量(如 idaapi.PLFM_386
, idaapi.PLFM_ARM
)可能已经移至 ida_idp
模块。ida_enum
和 ida_struct
等模块的功能可能有所调整或合并到其他模块。修改建议: 如果你在升级过程中遇到其他 AttributeError
或弃用警告,请按照以下步骤处理:
dir(module_name)
(例如 dir(ida_kernwin)
, dir(ida_idp)
) 来探索模块内容,查找新的函数或常量名称。inf_structure
和窗口类型问题。将 IDAPython 插件从 IDA 9.0 之前的版本迁移到 9.x 需要对代码进行一些调整,主要是将访问数据库信息和判断窗口类型的旧 API 替换为新的 API。核心变化包括使用 ida_ida
模块的 inf_get_*
/inf_is_*
函数、使用 ida_kernwin
模块的 widget_type
和 BWN_*
常量(注意名称可能变化,如 BWN_DUMP
到 BWN_HEXVIEW
),以及可能需要从 ida_idp
模块导入平台常量。
虽然迁移过程可能需要一些工作量,但更新插件可以确保它们在最新的 IDA 环境中正常运行,并能够利用 IDA 9.x 带来的新功能。祝你迁移顺利!