news 2026/4/18 8:08:28

(9-3-02)智能编程助手(IDA Pro+VS Code+MCP):MCP-Plugin插件

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
(9-3-02)智能编程助手(IDA Pro+VS Code+MCP):MCP-Plugin插件

(9)下面代码的功能是定义一个名为sync_wrapper的函数,用于在指定的IDA安全模式下调用函数。该函数确保在IDA主线程中执行请求,以避免IDB损坏。

def idaread(f): """ 标记函数为读取IDB的操作。 在IDA主线程中调度请求以避免结果不一致。 MFF_READ常量参考:http://www.openrce.org/forums/posts/1827 """ @functools.wraps(f) def wrapper(*args, **kwargs): ff = functools.partial(f, *args, **kwargs) ff.__name__ = f.__name__ return sync_wrapper(ff, idaapi.MFF_READ) return wrapper

(10)下面代码的功能是定义一个名为is_window_active的函数,用于判断IDA窗口是否当前活跃。该函数尝试从PyQt5导入QApplication并检查是否有顶层窗口处于活动状态。

def is_window_active(): """判断IDA窗口是否当前活跃""" try: from PyQt5.QtWidgets import QApplication except ImportError: return False app = QApplication.instance() if app is None: return False for widget in app.topLevelWidgets(): if widget.isActiveWindow(): return True return False

(11)下面代码的功能是定义了多个与调试器控制相关的函数,包括运行调试器至指定地址、设置断点、删除断点、启用或禁用断点等。这些函数提供了对调试会话的控制能力。

@jsonrpc @idaread @unsafe def dbg_run_to( address: Annotated[str, "运行调试器至指定地址"], ) -> str: """运行调试器至指定地址""" ea = parse_address(address) if idaapi.run_to(ea): return f"调试器已运行至 {hex(ea)}" return f"运行至地址 {hex(ea)} 失败" @jsonrpc @idaread @unsafe def dbg_set_breakpoint( address: Annotated[str, "在指定地址设置断点"], ) -> str: """在指定地址设置断点""" ea = parse_address(address) if idaapi.add_bpt(ea, 0, idaapi.BPT_SOFT): return f"已在 {hex(ea)} 设置断点" breakpoints = list_breakpoints() for bpt in breakpoints: if bpt["ea"] == hex(ea): return f"{hex(ea)} 处已存在断点" return f"在地址 {hex(ea)} 设置断点失败" @jsonrpc @idaread @unsafe def dbg_delete_breakpoint( address: Annotated[str, "删除指定地址的断点"], ) -> str: """删除指定地址的断点""" ea = parse_address(address) if idaapi.del_bpt(ea): return f"已删除 {hex(ea)} 处的断点" return f"删除地址 {hex(ea)} 的断点失败" @jsonrpc @idaread @unsafe def dbg_enable_breakpoint( address: Annotated[str, "启用或禁用指定地址的断点"], enable: Annotated[bool, "启用或禁用断点"], ) -> str: """启用或禁用指定地址的断点""" ea = parse_address(address) if idaapi.enable_bpt(ea, enable): return f"{hex(ea)} 处的断点已{'启用' if enable else '禁用'}" return f"{'启用' if enable else '禁用'} 地址 {hex(ea)} 的断点失败" class MCP(idaapi.plugin_t): """MCP插件主类""" flags = idaapi.PLUGIN_KEEP comment = "MCP插件" help = "MCP" wanted_name = "MCP" wanted_hotkey = "Ctrl-Alt-M" # 快捷键 def init(self): """初始化插件""" self.server = Server() hotkey = MCP.wanted_hotkey.replace("-", "+") if sys.platform == "darwin": # macOS系统适配 hotkey = hotkey.replace("Alt", "Option") print(f"[MCP] 插件已加载,使用 编辑 -> 插件 -> MCP(快捷键:{hotkey})启动服务器") return idaapi.PLUGIN_KEEP def run(self, args): """运行插件(启动服务器)""" self.server.start() def term(self): """终止插件(停止服务器)""" self.server.stop() def PLUGIN_ENTRY(): """插件入口函数""" return MCP()

9.4.2 基础信息获取与类型处理

本部分的主要功能是提取程序基础信息,包括文件路径、基地址、哈希值等元数据,以及函数原型、镜像大小等关键属性。支持地址字符串解析、函数信息查询,建立函数名与地址的映射关系以加速查找。提供数据类型转换功能,可将数值转为十进制、十六进制、ASCII等多种格式,并实现数据的分页和过滤处理,方便批量信息的高效获取。

(1)下面代码的功能是定义一个名为Metadata的类型定义,用于描述程序元数据的结构。该类型包含文件路径、模块名、基地址、程序大小、MD5哈希、SHA256哈希、CRC32校验值和文件大小等字段。

class Metadata(TypedDict): """程序元数据的类型定义""" path: str # 文件路径 module: str # 模块名 base: str # 基地址 size: str # 程序大小 md5: str # MD5哈希 sha256: str # SHA256哈希 crc32: str # CRC32校验值 filesize: str # 文件大小

(2)下面代码的功能是定义一个名为get_image_size的函数,用于获取程序镜像大小。该函数尝试从IDA信息结构或PE头中提取准确的镜像大小。

def get_image_size() -> int: """获取程序镜像大小""" try: # 参考:https://www.hex-rays.com/products/ida/support/sdkdoc/structidainfo.html info = idaapi.get_inf_structure() omin_ea = info.omin_ea omax_ea = info.omax_ea except AttributeError: import ida_ida omin_ea = ida_ida.inf_get_omin_ea() omax_ea = ida_ida.inf_get_omax_ea() # 估算镜像大小(如果重定位是最后一个节则不准确) image_size = omax_ea - omin_ea # 尝试从PE头中提取准确大小 header = idautils.peutils_t().header() if header and header[:4] == b"PE\0\0": image_size = struct.unpack("<I", header[0x50:0x54])[0] return image_size

(3)下面代码的功能是定义了一个名为 get_metadata 的函数,该函数用于获取当前 IDB(IDA数据库)的元数据,包括文件路径、模块名、基地址、大小等信息。该函数还处理了可能返回 None 的哈希值,并使用 @jsonrpc 和 @idaread 装饰器来注册为 JSON-RPC 方法和指定为只读操作。

@jsonrpc @idaread def get_metadata() -> Metadata: """获取当前IDB(IDA数据库)的元数据""" # 处理可能返回None的哈希(如Fat Mach-O二进制文件) # 参考:https://github.com/mrexodia/ida-pro-mcp/issues/26 def hash(f): try: return f().hex() except: return None return Metadata( path=idaapi.get_input_file_path(), module=idaapi.get_root_filename(), base=hex(idaapi.get_imagebase()), size=hex(get_image_size()), md5=hash(ida_nalt.retrieve_input_file_md5), sha256=hash(ida_nalt.retrieve_input_file_sha256), crc32=hex(ida_nalt.retrieve_input_file_crc32()), filesize=hex(ida_nalt.retrieve_input_file_size()) )

(4)下面代码的功能是定义了一个名为 get_prototype 的函数,用于获取指定函数的原型。该函数尝试从函数对象中原型获取,如果失败则尝试使用 idc.get_type 获取类型信息,如果仍然失败则捕获异常并返回 None。

def get_prototype(fn: ida_funcs.func_t) -> Optional[str]: """获取函数原型""" try: prototype: ida_typeinf.tinfo_t = fn.get_prototype() if prototype is not None: return str(prototype) else: return None except AttributeError: try: return idc.get_type(fn.start_ea) except: tif = ida_typeinf.tinfo_t() if ida_nalt.get_tinfo(tif, fn.start_ea): return str(tif) return None except Exception as e: print(f"获取函数原型时出错:{e}") return None

(5)下面代码的功能是定义了一个名为 parse_address 的函数,用于将地址字符串(无论是十进制还是十六进制)解析为整数。该函数会检查地址字符串是否有效,并在必要时抛出 IDAError 异常。

def parse_address(address: str) -> int: """将地址字符串(十进制或十六进制)解析为整数""" try: return int(address, 0) except ValueError: for ch in address: if ch not in "0123456789abcdefABCDEF": raise IDAError(f"解析地址失败:{address}") raise IDAError(f"解析地址失败(缺少0x前缀):{address}")

(6)下面代码的功能是定义了一个名为 get_function 的函数,根据给定的地址获取函数信息。如果地址处未找到函数,则根据参数 raise_error 决定是抛出 IDAError 异常还是返回 None。

def get_function(address: int, *, raise_error=True) -> Function: """根据地址获取函数信息""" fn = idaapi.get_func(address) if fn is None: if raise_error: raise IDAError(f"地址{hex(address)}处未找到函数") return None try: name = fn.get_name() except AttributeError: name = ida_funcs.get_func_name(fn.start_ea) return Function( address=hex(address), name=name, size=hex(fn.end_ea - fn.start_ea) )

(7)下面代码的功能是定义了一个名为 create_demangled_to_ea_map 的函数,用于创建一个已解析函数名到地址的映射,以便于快速查找。该函数遍历所有函数,解析它们的名称,并建立映射关系。

DEMANGLED_TO_EA = {} # 存储已解析的函数名到地址的映射 def create_demangled_to_ea_map(): """创建已解析函数名到地址的映射(用于快速查找)""" for ea in idautils.Functions(): # 获取函数名并解析(MNG_NODEFINIT仅保留主名,默认解析会包含签名和装饰器) demangled = idaapi.demangle_name( idc.get_name(ea, 0), idaapi.MNG_NODEFINIT) if demangled: DEMANGLED_TO_EA[demangled] = ea

(8)下面代码的功能是定义了一个名为 get_type_by_name 的函数,根据类型名获取类型信息对象。该函数支持多种基本数据类型,并尝试获取命名类型,如果未找到类型则抛出 IDAError 异常。

def get_type_by_name(type_name: str) -> ida_typeinf.tinfo_t: """根据类型名获取类型信息对象""" # 8位整数类型 if type_name in ('int8', '__int8', 'int8_t', 'char', 'signed char'): return ida_typeinf.tinfo_t(ida_typeinf.BTF_INT8) elif type_name in ('uint8', '__uint8', 'uint8_t', 'unsigned char', 'byte', 'BYTE'): return ida_typeinf.tinfo_t(ida_typeinf.BTF_UINT8) # 16位整数类型 elif type_name in ('int16', '__int16', 'int16_t', 'short', 'short int', 'signed short', 'signed short int'): return ida_typeinf.tinfo_t(ida_typeinf.BTF_INT16) elif type_name in ('uint16', '__uint16', 'uint16_t', 'unsigned short', 'unsigned short int', 'word', 'WORD'): return ida_typeinf.tinfo_t(ida_typeinf.BTF_UINT16) # 32位整数类型 elif type_name in ('int32', '__int32', 'int32_t', 'int', 'signed int', 'long', 'long int', 'signed long', 'signed long int'): return ida_typeinf.tinfo_t(ida_typeinf.BTF_INT32) elif type_name in ('uint32', '__uint32', 'uint32_t', 'unsigned int', 'unsigned long', 'unsigned long int', 'dword', 'DWORD'): return ida_typeinf.tinfo_t(ida_typeinf.BTF_UINT32) # 64位整数类型 elif type_name in ('int64', '__int64', 'int64_t', 'long long', 'long long int', 'signed long long', 'signed long long int'): return ida_typeinf.tinfo_t(ida_typeinf.BTF_INT64) elif type_name in ('uint64', '__uint64', 'uint64_t', 'unsigned int64', 'unsigned long long', 'unsigned long long int', 'qword', 'QWORD'): return ida_typeinf.tinfo_t(ida_typeinf.BTF_UINT64) # 128位整数类型 elif type_name in ('int128', '__int128', 'int128_t', '__int128_t'): return ida_typeinf.tinfo_t(ida_typeinf.BTF_INT128) elif type_name in ('uint128', '__uint128', 'uint128_t', '__uint128_t', 'unsigned int128'): return ida_typeinf.tinfo_t(ida_typeinf.BTF_UINT128) # 浮点类型 elif type_name in ('float', ): return ida_typeinf.tinfo_t(ida_typeinf.BTF_FLOAT) elif type_name in ('double', ): return ida_typeinf.tinfo_t(ida_typeinf.BTF_DOUBLE) elif type_name in ('long double', 'ldouble'): return ida_typeinf.tinfo_t(ida_typeinf.BTF_LDOUBLE) # 布尔类型 elif type_name in ('bool', '_Bool', 'boolean'): return ida_typeinf.tinfo_t(ida_typeinf.BTF_BOOL) # 空类型 elif type_name in ('void', ): return ida_typeinf.tinfo_t(ida_typeinf.BTF_VOID) # 非标准类型,尝试获取命名类型 tif = ida_typeinf.tinfo_t() if tif.get_named_type(None, type_name, ida_typeinf.BTF_STRUCT): return tif if tif.get_named_type(None, type_name, ida_typeinf.BTF_TYPEDEF): return tif if tif.get_named_type(None, type_name, ida_typeinf.BTF_ENUM): return tif if tif.get_named_type(None, type_name, ida_typeinf.BTF_UNION): return tif if tif := ida_typeinf.tinfo_t(type_name): return tif raise IDAError(f"无法获取{type_name}的类型信息对象")
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 7:38:11

使用Vite#x2B; Lit 构建webcomponent 组件

ViteLit.js 构建Web Component web component作为前一个时代的方案&#xff0c;在特定场景下确有不一样的妙用 &#xff0c;在维护前后端不分离的项目&#xff0c;web component 是为数不多的选择&#xff0c;整理一下使用Lit 构建自己的web component组件库为传统项目提提速的…

作者头像 李华
网站建设 2026/4/8 20:56:58

好写作AI:从思绪到结构,一键生成清晰论文大纲

你是否曾面对空白文档&#xff0c;脑中想法万千却不知如何下笔组织&#xff1f;是否花费数小时反复调整论文结构&#xff0c;却总觉逻辑不顺&#xff1f;好写作AI全新功能——一键智能大纲生成&#xff0c;正是为破解这一核心难题而来。它帮你将飘散的思绪&#xff0c;瞬间转化…

作者头像 李华
网站建设 2026/4/18 8:00:22

从缺陷回溯到效能提升:如何构建高价值测试案例知识库

测试案例分析的常见困境与价值重估 在多数软件测试团队中&#xff0c;“测试案例分析”并非一个新名词&#xff0c;但其落地形态却常常流于形式。常见的场景是&#xff1a;在项目复盘会上&#xff0c;某个“经典的”或“严重的”Bug被匆匆回顾&#xff0c;讨论停留在“当时没想…

作者头像 李华
网站建设 2026/4/18 6:59:41

如何为多语言知识库配置翻译中间件?i18n支持扩展

如何为多语言知识库配置翻译中间件&#xff1f;i18n支持扩展 在一家跨国企业的技术支持团队中&#xff0c;一位巴西员工用葡萄牙语提问&#xff1a;“Como solicito acesso ao sistema interno?”——几乎同一时刻&#xff0c;另一位德国工程师也在系统中输入德语问题&#x…

作者头像 李华
网站建设 2026/4/18 7:41:53

如何一天内掌握Open-AutoGLM?高效学习路径图首次公开

第一章&#xff1a;Open-AutoGLM 使用教程Open-AutoGLM 是一个开源的自动化大语言模型调用框架&#xff0c;旨在简化与 GLM 系列模型的交互流程。通过该工具&#xff0c;开发者可以快速实现文本生成、指令解析、多轮对话管理等功能&#xff0c;适用于智能客服、自动化报告生成等…

作者头像 李华
网站建设 2026/4/17 13:25:21

PotPlayer播放器

Daum PotPlayer播放器是一款全能多媒体影音播放器,堪称Windows平台最强大的本地视频播放器.PotPlayer最新版拥有强劲播放引擎加速,支持DXVA,CUDA,QuickSync,多媒体播放器支持蓝光3D,其内置强大的编码器及滤镜/分离器,支持自定义添加解码器,对字幕的支持非常优秀,能兼容特效字幕…

作者头像 李华