众所皆知,IDA 9.0 Beta 更新了插件系统,导致原来的一些插件不能用了。
那么,具体是什么部分不兼容呢?
首先,对于Python插件,用来判断当前打开文件的架构信息的 ida_idaapi.get_inf_structure()
被删掉了,这几乎是绝大多数 Python 插件不能用的唯一原因。为此,可以做这样的替换:
idaapi.cvar.inf/ida_idaapi.get_inf_structure().xx -> ida_ida_inf_get_xx
ida_idaapi.get_inf_structure().is_xx -> ida_ida_inf_is_xx
idaapi.cvar.idati -> idaapi.get_idati()
而类似 D-810 的插件依赖 z3 solver,而 z3 solver 库会优先选择 IDA 目录下的 libz3.dll(用于IDA自带的gooMBA),而这玩意与 Python3.12 版本的 z3 solver 库的 Python 代码并不兼容,为此可以在 python\3\ida_idaapi.py
import struct
import traceback
import os
import sys
import bisect
之后插入
if sys.version_info > (3, 12, 0):
# In this case, we monkey patch CDLL for z3
import ctypes
cdll_func = ctypes.CDLL.__init__
def hook_func(self, name, *args, **kwargs):
if name == os.path.join(os.path.realpath('.'), 'libz3.dll'):
raise FileNotFoundError(f'Could not find module {name} as compatibility forced')
return cdll_func(self, name, *args, **kwargs)
ctypes.CDLL.__init__ = hook_func
让 python库 z3 solver 找不到位于 IDA 根目录下的 libz3.dll,转而使用它自带的 z3。
同时 IDA 把 Strucure 和 Enum 两个 view 和对应的数据库删了,转而使用统一的 Local Types。所有依赖 ida_enum 和 ida_struct 必须改成依赖 ida_typeinf。
而 dll 格式的插件里,依赖 enum.hpp struct.hpp 同样是导致不兼容的重灾区,还好绝大多数 dll 都是开源的,因此可以稍作修改(或者直接用网友的PR)后编译,例如:
IDA_ClassInformer_PlugIn64.dll -> https://github.com/EngineLessCC/ClassInformer-IDA-90/releases
HexRaysCodeXplorer64.dll -> https://github.com/REhints/HexRaysCodeXplorer/pull/121
binexport12_ida64.dll -> https://github.com/google/binexport/pull/133
我们也可以照猫画虎,修改一些没人提交PR的插件,例如对于 https://github.com/airbus-cert/Yagi 可以做如下 patch:
diff --git a/yagi/src/idasymbol.cc b/yagi/src/idasymbol.cc
index cac4fec..aac7f1a 100644
--- a/yagi/src/idasymbol.cc
+++ b/yagi/src/idasymbol.cc
@@ -5,7 +5,7 @@
#include "idatype.hh"
#include <idp.hpp>
#include <frame.hpp>
-#include <struct.hpp>
+// #include <struct.hpp>
#include <name.hpp>
#include <sstream>
@@ -159,17 +159,19 @@ namespace yagi
std::optional<std::string> IdaFunctionSymbolInfo::findStackVar(uint64_t offset, uint32_t addrSize)
{
auto idaFunc = get_func(m_symbol->getAddress());
- auto frame = get_frame(idaFunc);
- if (frame == nullptr)
- {
+ tinfo_t frame_tif;
+ if (!get_func_frame(&frame_tif, idaFunc)) {
return std::nullopt;
}
- for (uint32_t i = 0; i < frame->memqty; i++)
- {
- auto member = frame->members[i];
- auto name = std::string(get_struc_name(member.id, STRNFL_REGEX).c_str());
- auto sofset = member.get_soff() - (idaFunc->frsize + idaFunc->frregs);
+ udt_type_data_t udt_data;
+ if (!frame_tif.get_udt_details(&udt_data)) {
+ return std::nullopt;
+ }
+
+ for (const udm_t& udm : udt_data) {
+ auto name = std::string(udm.name.c_str());
+ auto sofset = (udt_data.is_union ? 0 : (udm.offset / 8)) - (idaFunc->frsize + idaFunc->frregs);
if (sofset == offset || (addrSize == 4 && ((uint32_t)sofset == (uint32_t)offset)))
{
auto pp = name.find(".");
@@ -180,6 +182,7 @@ namespace yagi
return name;
}
}
+
return std::nullopt;
}
diff --git a/yagi/src/idatype.cc b/yagi/src/idatype.cc
index 1df762f..4a08900 100644
--- a/yagi/src/idatype.cc
+++ b/yagi/src/idatype.cc
@@ -130,9 +130,9 @@ namespace yagi
m_info.m_type.get_udt_details(&attributes);
std::vector<TypeStructField> result;
- idatool::transform<udt_member_t, TypeStructField>(
+ idatool::transform<udm_t, TypeStructField>(
attributes, std::back_insert_iterator(result),
- [this](const udt_member_t& arg) -> TypeStructField
+ [this](const udm_t& arg) -> TypeStructField
{
return TypeStructField{ arg.offset / 8, arg.name.c_str(), std::make_unique<IdaTypeInfo>(arg.type) };
}
剩下还有一小部分不开源/难改的插件,排除掉不需要用的,就很少了。
这时我注意到了论坛 微笑一刀 大佬写的 StrongCC 插件,我找不到源码,同时这个插件又明显不依赖 enum.hpp struct.hpp,但为什么还是不支持?
查看 idp.hpp 发现 IDP_INTERFACE_VERSION
的值从 700 更新成了 900,对应的,struct plugmod_t
的结构被小幅度修改了。
起初,我以为这样的修改只需要二进制patch一小部分代码就可以,但是结构体开头内容增加导致继承自 plugmod_t
的插件主体代码里对 this
指针的操作都要修改,特别是虚表搞得我十分头大。
那么,为什么不考虑适配器模式呢?即写一个插件,启动时它会加载老插件,而后 IDA 调用它时,他会转而使用旧版本的接口去调用老插件;而对于老插件需要的部分导出函数,替换成适配器插件上的函数,适配器做适当处理后再调用IDA。
此外,为了避免一个插件变成需要2个DLL,可以使用内存里加载DLL的方法,我使用了 https://github.com/fancycode/MemoryModule,它同时提供了自定义 GetProcAddress
能力,可以使我们轻易修改老插件需要的部分导出函数。
原理上而言,适配器插件可以实现所有 enum.hpp struct.hpp 里导出的函数,但这工作量较大且并不为我所需,因此就不写了,只写了对 struct plugmod_t
变化的支持,从而使 StrongCC 能顺利在 IDA 9.0 Beta 上运行。
具体细节见于源码,具体源码见于附件,将这些源码和 https://github.com/fancycode/MemoryModule 上提供的 MemoryModule.h 与 MemoryModule.c 以及 微笑一刀 大佬写的 StrongCC 插件,即 StrongCC_x64.dll(UPX decompress 后) 放在同一目录下,调整 build.bat 里 MSVC 和 IDA SDK 的位置后即可编译。