Skip to content

Releases

v2.0.10 - broker 缓存层:修 entity_query 崩溃,扁平参数支持 kind

Choose a tag to compare

@Sumcam-L Sumcam-L released this 08 Nov 16:06

报障

{"instance_id":"ida-25956","name_pattern":"??_7*@ModifierDefinition@*","limit":10}
Error: SQLite 缓存查询失败: dictionary update sequence element #0 has length 5; 2 is required

这里其实是两个独立的错误叠在一起。


一、dict(payload) 崩溃

cache_handlers._wrap_ok 用 dict(payload) 统一包装所有缓存工具返回值。entity_query 的每页有 5 个 key:

{"kind", "data", "next_offset", "total", "error"}

dict() 会把它当成键值对序列去迭代,5 个 key 拆不成 2 元组 → ValueError。所以 entity_query 只要命中缓存就 100% 失败。

list_funcs 之所以没炸:它的页只有 2 个 key(data, next_offset),刚好能凑成一对,于是 dict() 静默成功并产出垃圾 {"data": "next_offset"}。两处都错,只是后者没崩出来。

修复:list payload 包成 {"result": [...]},与 _mcp_tools_call 对非 dict 结果的既有约定一致。

二、扁平参数查不到 globals

entity_query 的 kind / regex / segment 原本只能写在 queries 里:

  • 扁平写法(name_pattern + limit)永远只能查 functions 表
  • 顶层传 kind 会被当成未知参数拒绝

想查 globals 下的 vtable 符号,必须自己拼 queries 对象——而报障的调用正是扁平写法。

修复:

  • _ENTITY_QUERY_ARGS 允许 kind / regex / segment / include_xrefs
  • _queries_from_args 把这些扁平字段灌进 query(嵌套 queries 优先)
  • 其他工具(list_funcs 等)仍然拒绝 kind,避免语义混淆
  • include_xrefs 只在显式传参时才写入,否则 None 会被当成 False

验证(真实 GameCore IDB):

name_pattern + kind=globals, ??_7*ModifierDefinition*   -> 4 条
queries 形式                                          -> 3 条

两种写法结果一致。

三、顺带说明:你这个 pattern 本来就查不到东西

即使修好上面两点,??_7*@ModifierDefinition@* 也是 0 结果——没有 @ModifierDefinition@ 这个符号。真实的 vtable 是:

??_7SimpleModifierDefinition@GameEffects@@6B@
??_7?$_Ref_count@VSimpleModifierDefinition@GameEffects@@@std@@6B@

而且它们在 globals 表,不在 functions 表。用 ??_7*ModifierDefinition* + kind=globals 能查到 4 条。

四、broker 层此前没有任何测试

新增 tests/test_broker_cache_handlers.py(13 个用例)。已确认它们真的能抓到这两个 bug——把修复回滚后分别红 5 个和 2 个:

_wrap_ok 回滚成 dict(payload)   -> 5 failed
删除扁平 kind 传播              -> 2 failed

测试

套件 结果
host pytest 181 passed, 1511 subtests
crackme03.elf 361 passed, 1 skipped
typed_fixture.elf 336 passed, 1 skipped

升级

WHL=$(curl -sL https://api.github.com/repos/Sumcam-L/ida-pro-mcp-enhanced/releases/latest \
      | grep -o 'https://[^"]*\.whl' | head -1)
pip install "$WHL"
ida-mcp-setup

装完重启 IDA。

v2.0.9 - 修复 xrefs_to 截断丢数据

Choose a tag to compare

@Sumcam-L Sumcam-L released this 08 Nov 13:41

报障

同一 xrefs_to 查询三次分别返回 100 / 100 / 10 条。

根因一:预览层把每个 list 砍到固定 10 条(数据丢失)

rpc.py 的输出上限补丁在响应超过 50000 字符时,把 structuredContent 换成 _truncate_value() 的结果,而它对任何 list 都只保留前 10 项:

return [_truncate_value(item) for item in value[:OUTPUT_LIMIT_PREVIEW_ITEMS]]

structuredContent 是权威数据、content 才是给人看的,于是客户端读到的是“只有 10 个 xref”。更糟的是截断标记只在 content[1],读 structuredContent 的调用方完全不知道自己看的是残缺数据。

实测(真实 IDA 实例):

传入 addrs 字符数 保留条目
200 29317 200
350 超 50000 10
700 超 50000 10

改成按字符预算截断后:

传入 addrs 保留条目 字符数
200 200 18601
350 350 32551
700 430 39991
2000 430 39991(附 download_hint)
  • 每个元素至少留 256 字符,避免长列表把单条记录切碎
  • dict 按原尺寸比例分配,绝不丢 key(total / more / error 必须保留)
  • 嵌套超过 4 层改用均分,避免深树反复整树序列化

根因二:截断时没有机器可读标记

_build_download_meta 早就生成了 download_hint,却只塞进 content[1]。现在同时写 _meta.ida_mcp(total_chars / preview_chars / download_url)。

根因三:缓存层把 list payload 转成垃圾

dict([{'data': [...], 'next_offset': 2}])  ->  {'data': 'next_offset'}
dict([{'a': 1}, {'a': 2}])                 ->  ValueError

list_funcs / list_globals / entity_query 走缓存时 structuredContent 一直是坏的。改成 {"result": [...]},与 _mcp_tools_call 对非 dict 结果的既有约定一致。

根因四:limit <= 0 被解释成上限而不是默认值

xrefs_to docstring 写 default 100 / max 1000,代码却是:

if limit <= 0 or limit > 1000:
    limit = 1000

传 0 得到 1000 条。callees / find_bytes / find 同样写法。统一改为 limit <= 0 → 文档里的默认值,再单独做上限截断。

测试基建

  • limit_response_size 从闭包里的 patched() 提出来,成为可直接测试的函数;测试改为调用生产函数而不是复制一份逻辑(旧测试复制了补丁,rpc.py 回归也照样绿)
  • 新增 6 个回归测试:保留条数、顺序、可重复性、dict 标量不被丢、深层嵌套不丢兄弟节点、limit=0 语义

测试

套件 结果
host pytest 168 passed, 1511 subtests
crackme03.elf 361 passed, 1 skipped
typed_fixture.elf 336 passed, 1 skipped

升级

WHL=$(curl -sL https://api.github.com/repos/Sumcam-L/ida-pro-mcp-enhanced/releases/latest \
      | grep -o 'https://[^"]*\.whl' | head -1)
pip install "$WHL"
ida-mcp-setup

装完重启 IDA —— 插件模块只在启动时 import。

v2.0.8 - 修复模板类型写入与 schema 退化

Choose a tag to compare

@Sumcam-L Sumcam-L released this 08 Nov 03:02

这个版本修了什么

1. 模板实例化类型写不进 IDB,还会卡死 IDA

declare_type 的模板分支用 tinfo_t.parse() 解析成员类型,而 parse() 对任何含 <...> 的名字必定失败(同一个名字 get_named_type 能拿到 size=16,parse 却返回 empty)。

更糟的是没带 PT_SIL,失败时 IDA 侧可能弹模态框阻塞消息泵,插件线程卡死 —— 现场症状是 list_funcs 正常、type_inspect 全部超时,只能重启 IDA。

修复:

  • _resolve_base_type() 对含 <...> 的名字改走 get_named_type();先剥尾部 * 再 create_ptr() 还原,所以 T * 也能用于模板名
  • 普通拼写继续走 parse(),补上 PT_SIL,永不弹框
  • _decl_needs_manual_udt() + _build_udt_by_hand():解析器失败且成员含 <...> 时,手工 create_udt + set_named_type
  • char pad[8] 的维度从名字剥出,改用 create_array() 重建

验证:GameEffects::Modifiers::DynamicModifier(47 成员 / 544 字节)一次写入成功,每个偏移对得上 ctor 反编译与 getter 反汇编:

0x000 __vftable          0x148 m_Owner        (shared_ptr, 16B)
0x048 autoArchive[144]   0x168 m_Definition   (16B)
0x0e8 m_id (int)         0x1b8 m_Effect       (16B)  <- ApplyEffect 的 [rbp+1B8h]
0x100 m_IsActivated      0x1c8 m_OwnerReqSet  (16B)  <- GetOwnerRequirementSet
0x118 m_WasActivated     0x1e0 m_StateString[32]
0x130 m_IsDisabled       0x210 Handle

2. 工具参数对模型退化成 unknown

参数写成 list[T] | T 会生成 anyOf,而客户端 schema 子集只认 type/oneOf/properties/required/additionalProperties/items/enum/const。一个 anyOf 就让整个参数对象变成 unknown,模型看不到参数名只能猜 —— 表现就是 search_structs(filter=..., limit=...)、type_inspect(name=...) 这类调用反复报 unexpected parameters。

本仓库 53 个工具是这种形状。改成 oneOf 后 87 个工具全部可渲染,unknown 从 55 降到 0。

3. 缓存工具返回形状不一致

缓存命中只给 content[0].text,原生路径给 structuredContent。现在两条路径一致。

4. type_inspect 标记空壳类型

PDB 空壳类表现为 exists: true + size: 1 + member_count: 0,和真实类型难以区分。新增 is_placeholder 字段。

5. idb_save 归入 --unsafe

idb_save / idalib_save 会直接写盘,现在需要 --unsafe。

注意:如果你的 broker 启动时没带 --unsafe,升级后 idb_save 会从工具列表消失。

6. 测试基建

  • 新增 tests/test_schema_subset_compat.py:完整实现客户端 schema 子集校验,锁死 anyOf 不得回归
  • 修 6 个因包名迁移早已无法收集的测试文件(引用已不存在的 src/ida_pro_mcp)
  • 新增 3 个模板成员/指针/数组回归测试

测试

套件 结果
host pytest 162 passed, 114 subtests
crackme03.elf 361 passed, 1 skipped
typed_fixture.elf 336 passed, 1 skipped

升级

pip install https://github.com/Sumcam-L/ida-pro-mcp-enhanced/releases/download/v2.0.8/ida_pro_mcp_enhanced-2.0.8-py3-none-any.whl
ida-mcp-setup

装完重启 IDA(或 Ctrl+Alt+M 重连)—— 插件模块只在启动时 import,热替换文件不会让已加载的模块重新执行。

v2.0.7 - 缓存层补参数校验

Choose a tag to compare

@Sumcam-L Sumcam-L released this 27 Oct 12:38

这个版本修了什么

缓存层对未知参数不再静默忽略。

现象:list_funcs 传 {"filter": "*TerrainElement*", "limit": "0:80"} 会原样返回全表前 N 条,filter 不生效、也不报错。

根因:缓存层插在 MCP dispatcher 之前,命中缓存工具就直接本地 SQLite 响应,绕过了 registry.dispatch 那套 unexpected parameters 校验。而 _queries_from_args() 只认 queries 和 name_pattern/offset/count/limit 这几个旧别名,filter 直接被丢弃 → 空查询 → 返回全表。

现在会明确报错并给出正确写法:

list_funcs: unrecognized parameter(s) ['filter'].
  Hint - filter: wrap it: "queries": {"filter": ...}  (or pass "queries": "*Pattern*")
  Accepted parameters: ['count', 'instance_id', 'limit', 'name_pattern', 'offset', 'queries']

同时拦住 limit/count/offset 收到 "0:80" 这种分页简写的情况(那属于 queries)。

正确写法:

{"instance_id": "...", "queries": {"filter": "*TerrainElement*", "count": 20}}

安装

pip install https://github.com/Sumcam-L/ida-pro-mcp-enhanced/releases/download/v2.0.7/ida_pro_mcp_enhanced-2.0.7-py3-none-any.whl
ida-mcp-setup

装完在 IDA 里按 Ctrl+Alt+M 重连。

v2.0.6 - search_text pattern 语义提示

Choose a tag to compare

@Sumcam-L Sumcam-L released this 27 Oct 12:21

这个版本改了什么

search_text 的 pattern 语义提示(只改提示,不动匹配逻辑)。

现象:AI 传 pattern="TerrainElement|AssetCooker|TerrainStyle" 却没开 regex,拿到 n: 0 就判定「这些符号不存在」。

实际是默认按字面量子串匹配,竖线也被当成普通字符——搜的是那个 8 字符的整串,0 条完全正常。这是假阴性,比慢查询危险得多。

改动:

  • pattern / regex 参数说明写清:要 | 表示 OR 必须传 regex=true
  • docstring 增加 PATTERN SEMANTICS 段落,明确「0 命中不等于符号不存在」
  • 新增 _regex_literal_hint():字面量 0 命中且 pattern 含强正则信号时,返回 note 解释

强信号只收竖线、反斜杠、锚点、.*、.+、(?:、[A-Z] 这类组合;不收裸的点号、星号、圆括号、方括号——Foo.Bar、operator() 这类正常搜索未命中时不会刷无用提示。

安装

pip install https://github.com/Sumcam-L/ida-pro-mcp-enhanced/releases/download/v2.0.6/ida_pro_mcp_enhanced-2.0.6-py3-none-any.whl
ida-mcp-setup

装完在 IDA 里按 Ctrl+Alt+M 重连。

v2.0.5 — 缓存层 filter 语义对齐原生实现

Choose a tag to compare

@Sumcam-L Sumcam-L released this 25 Oct 07:30

这个版本修了什么

缓存层的 filter 语义和原生实现不一致,同一个 filter 走不同路径结果不同。

缓存接管的 7 个工具(find_regex / entity_query / list_funcs / list_globals / imports / imports_query / refresh_cache)另写了一套 filter→SQL 翻译,有三处偏差:

pattern 原生 缓存(修复前) 原因
/create/ 3 1 原生 flags or re.IGNORECASE,无 flag 时默认忽略大小写
/CREATE/ 3 0 同上
[abc] 1 0 缓存多判了 [,把字面量当字符类
a[bc]d 1 0 同上
-1:10 filter 分页 offset=-1 正则写成 (-?\d+)

修复后 20 项 filter 对比 + 8 项分页对比全部一致。

安装

pip install https://github.com/Sumcam-L/ida-pro-mcp-enhanced/releases/download/v2.0.5/ida_pro_mcp_enhanced-2.0.5-py3-none-any.whl
ida-mcp-setup

装完在 IDA 里按 Ctrl+Alt+M 重连(会连同 broker 包一起重新加载)。

v2.0.4 — 批量接口拼错键名不再静默失败

Choose a tag to compare

@Sumcam-L Sumcam-L released this 25 Oct 07:23

这个版本修了什么

批量接口拼错键名时不再静默返回 total: 0。

rename 一直返回 total: 0 的真实原因是 batch 键名拼错(写成 functions / locals 复数),而旧实现逐个 batch.get(key) 取值——拼错不报错,只是取不到东西。

现在会在解析前校验键名,不合法直接报错并回显合法键列表:

rename: unknown batch key(s) ['functions']; supported keys: ['allow_overwrite', 'data', 'dry_run', 'func', 'global', 'globals', 'local', 'stack', 'stop_on_error']

覆盖 rename 与 type_apply_batch 两个批量接口。

安装

pip install https://github.com/Sumcam-L/ida-pro-mcp-enhanced/releases/download/v2.0.4/ida_pro_mcp_enhanced-2.0.4-py3-none-any.whl
ida-mcp-setup

装完在 IDA 里按 Ctrl+Alt+M 重连(或重启 IDA)即可生效。

v2.0.3 — 移除永远返回空的 list_instances

Choose a tag to compare

@Sumcam-L Sumcam-L released this 25 Oct 04:28

这个版本修了什么

list_instances 永远返回空数组。

它是 mrexodia 原始「每个 IDA 插件各开一个 HTTP 端口」时代的工具:内部调用 discover_instances() 扫本机端口。当前是 broker 纯路由架构,IDA 插件不再监听任何端口,只作为 SSE 客户端挂在 broker 上 → 扫不到东西 → 永远返回 []。

但它的对外语义是「列出所有 IDA 实例」,所以调用方会以为真的没有实例。

修复:从工具目录里剔除 list_instances / select_instance。实例列表请用 broker 侧的 instance_list / instance_info。

工具总数 66 → 64。

安装

pip install https://github.com/Sumcam-L/ida-pro-mcp-enhanced/releases/download/v2.0.3/ida_pro_mcp_enhanced-2.0.3-py3-none-any.whl
ida-mcp-setup

装完重启 IDA 和 DSH。

详见 PATCHES.md。

v2.0.2 — 修复 broker 被误杀导致的间歇性断连

Choose a tag to compare

@Sumcam-L Sumcam-L released this 25 Oct 04:04

这个版本修了什么

间歇性断连:IDA 开着,用着用着突然连不上,过一会儿又自己好了。

根因是 broker 生命周期判断错了对象 —— state[clients] 只记录 MCP 客户端进程,不记录 IDA 实例。任何导致 launcher 退出的情况(DSH 重载插件、工具超时重连、DSH 重启)都会让 broker 被 SIGTERM,挂在上面的 IDA 全部掉线。

日志实测:broker 启动 222 次、IDA 连接 484 次、断开 334 次。

修复后:broker 上只要还有 IDA 实例就不许关;无客户端认领时打 orphaned 标记,交给 15 分钟空闲清理。MCP 客户端断开不再影响已连接的 IDA,DSH 重连直接复用现有 broker,没有空窗期。

安装

pip install https://github.com/Sumcam-L/ida-pro-mcp-enhanced/releases/download/v2.0.2/ida_pro_mcp_enhanced-2.0.2-py3-none-any.whl
ida-mcp-setup

装完重启 IDA 和 DSH。

详见 PATCHES.md。

v2.0.1 — 可直接安装的 IDA Pro MCP

Choose a tag to compare

@Sumcam-L Sumcam-L released this 22 Oct 06:47

安装

pip install https://github.com/Sumcam-L/ida-pro-mcp-enhanced/releases/download/v2.0.1/ida_pro_mcp_enhanced-2.0.1-py3-none-any.whl
ida-mcp-setup

这个版本修了什么

问题 上游 本版
search_text 搜不存在的 token ~235 秒,broker 超时后 IDA 主线程仍在跑 ~15 秒,带预算返回 partial 游标
search_text 搜常见符号 ~70 秒 ~15 秒
survey_binary 扫十万函数大库 主线程卡几十分钟且无法取消 < 1 秒拒答,建议改用窄工具
工具超时 sys.setprofile 递归 / PyThreadState_SetAsyncExc 锁死主线程 只有调用方放弃等待,主线程安全跑完
安装 需手工处理 site-packages 与插件目录两份副本 pip install + ida-mcp-setup

包名说明

PyPI 上的 ida-pro-mcp 是上游 mrexodia 的包(1.4.0,无 broker 架构),本发行版用不到那个名字。

  • 发行包:ida-pro-mcp-enhanced
  • Python 模块:ida_pro_mcp_enhanced(与上游区分,避免覆盖)
  • DSH 插件:dsh-ida-mcp(npm)

完整改动说明见 PATCHES.md。