IDA 9.0 Beta 插件兼容方案小记

查看 173|回复 10
作者:4qwerty7   
众所皆知,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 [i]
#include
-#include
+// #include
#include
#include
@@ -159,17 +159,19 @@ namespace yagi
    std::optional 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 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 result;
-       idatool::transform[u](
+       idatool::transform[u](
            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[I](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 的位置后即可编译。

插件, 适配器

4qwerty7
OP
  


li513216760 发表于 2024-8-26 16:09
支持分享,挺有作用,怎么判断这个库是否不兼容?

idp.hpp 的变更导致任何原来的 dll 插件都不可能在没有修改/重新编译的前提下使用。
对于依赖已经修改的api的,需要修改相关代码重新编译(当然也可以增强帖子中的src.zip实现更强的适配器)。
对于只需要重新编译但又没源码的(看dll导入函数有哪些差异),可以用帖子中的src.zip。
justwz   

跟着大佬学逆向
残风逝雪夜阑天   

感谢分享~~~~~~~~~~
Sean250mutou   

挺厉害的,感谢!
hebingcan   

学习了,。。。。
重命名   

求一份能用的IDA 9.0
crapeber   

感谢分析DLL失效原因
gys19830912   

@微笑一刀 大佬求更新。
li513216760   

论坛有你很精彩,是我需要的
您需要登录后才可以回帖 登录 | 立即注册

返回顶部