IDA 9.0 Beta 插件兼容方案小记
众所皆知,IDA 9.0 Beta 更新了插件系统,导致原来的一些插件不能用了。那么,具体是什么部分不兼容呢?
首先,对于Python插件,用来判断当前打开文件的架构信息的 `ida_idaapi.get_inf_structure()` 被删掉了,这几乎是绝大多数 Python 插件不能用的唯一原因。为此,可以做这样的替换:
```py
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`
```python
import struct
import traceback
import os
import sys
import bisect
```
之后插入
```python
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
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;
- 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),
- (const udt_member_t& arg) -> TypeStructField
+ (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 以及 微笑一刀 大佬写的 (https://www.52pojie.cn/forum.php?mod=viewthread&tid=1434932&extra=&highlight=StrongCC&page=1),即 StrongCC_x64.dll(UPX decompress 后) 放在同一目录下,调整 build.bat 里 MSVC 和 IDA SDK 的位置后即可编译。 Hmily 发表于 2024-8-26 14:45
@微笑一刀 大佬求更新。
既然有人要.那就发出来好了,加了个UPX.没功能改动.
9.0的. li513216760 发表于 2024-8-26 16:09
支持分享,挺有作用,怎么判断这个库是否不兼容?
idp.hpp 的变更导致任何原来的 dll 插件都不可能在没有修改/重新编译的前提下使用。
对于依赖已经修改的api的,需要修改相关代码重新编译(当然也可以增强帖子中的src.zip实现更强的适配器)。
对于只需要重新编译但又没源码的(看dll导入函数有哪些差异),可以用帖子中的src.zip。 跟着大佬学逆向 感谢分享~~~~~~~~~~ 挺厉害的,感谢! 学习了,。。。。 求一份能用的IDA 9.0 感谢分析DLL失效原因 @微笑一刀 大佬求更新。 论坛有你很精彩,是我需要的 本帖最后由 li513216760 于 2024-8-26 16:14 编辑
支持分享,挺有作用,怎么判断这个库是否不兼容?