delphi-mcp
Recovers symbols from Delphi binaries across Delphi 2 through 13 Florence, 32/64-bit, by routing between classic, modern, and legacy analysis engines. Provides tools for version/architecture detection, full symbol analysis, class/method/field/unit/interface queries, triage, string and import behavior intelligence, DFM form-to-event mapping, xref call graph queries, rename plan generation, and export of symbols for IDA workflows.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
delphi-mcp
Delphi 逆向符号恢复 MCP 服务:把多个 Delphi 反编译引擎统一到一个 MCP 接口后面,为 AI agent 提供静态符号知识,并与 IDA MCP(ida-mcp)协同工作。
在真实恶意样本上验证:Delphi 2 ~ 13 Florence 全版本、32/64 位,纯 Python,零编译依赖。
想了解"做了什么、为什么能做、二进制变成了什么"——见 docs/TECHNICAL.md。 想知道"能干什么、输出长什么样、怎么用"——见 docs/USAGE.md(使用手册,含真实输出样例)。 性能演进与卡死复盘——见 docs/PERFORMANCE.md。 文件职责速查——见 docs/FILES.md。
为什么
老 Delphi 样本(尤其恶意软件)在 IDA/Ghidra 里函数名全是 sub_xxxx,分析极度依赖符号恢复。现有工具要么只有 GUI(IDR)、要么绑定特定平台(DelphiReSym 依赖 Ghidra)、要么恢复能力弱。delphi-mcp 把它们的分析能力抽取为统一的、可脚本化的、给 agent 用的服务。
Related MCP server: delphi7
特性
三引擎自动路由:按 Delphi 版本选择最合适的分析引擎,输出统一的符号模型
12 个 MCP 工具:从版本判定到符号查询、行为情报、模型生命周期、IDA 协同
纯 Python 引擎:
classic/modern两个引擎无编译依赖(仅需pefile、numpy、capstone)IDR 知识库匹配:直接解析
kb*.bin(4 万+ RTL/VCL 函数字节模式),命名虚表槽与调用目标行为情报:字符串×引用、敏感 API 指纹、DFM 表单→事件、XRef 调用图
为 agent 设计:stdout=JSON、结果按需分页、大产物落盘只回传路径、磁盘缓存
架构
delphi_detect ─── 版本 / 架构判定
│
┌─────────────────┼──────────────────┐
▼ ▼ ▼
Delphi 2..2007 Delphi 2009+ (idr-cli 强制)
classic 引擎 modern 引擎 legacy 引擎
(纯 Python) (纯 Python) (C++ 子进程)
RTTI+KB 匹配 VMT/MDT/RTTI syskb 19 步流水线
│ │ │
└─────────────────┴──────────────────┘
▼
统一符号模型 SymbolModel (JSON)
▼
query / strings / imports / forms / xrefs / renames / export
▼
ida-mcp 深挖(可选)三个引擎都产出同一套 SymbolModel(类/方法/参数/字段/单元/接口/变量),后端与 agent 无需关心用的是哪个引擎。
引擎职责
引擎 | 版本范围 | 实现 | 恢复内容 |
| Delphi 2~2007(老格式,负偏移 VMT) | 纯 Python | 类/RTTI、虚表槽(KB 命名)、动态消息方法、接口、字段、调用目标发现、单元 |
| Delphi 2009~13(新格式,正偏移 VMT) | 纯 Python(DelphiReSym 衍生) | 类/VMT/MDT、方法名+参数+返回类型、RTTI 命名空间 |
| Delphi 2~2007 | C++ | IDR 完整 19 步流水线(可选深度增强/兜底) |
安装
依赖(Python ≥ 3.11):
pip install mcp pefile numpy capstonelegacy 引擎需要 idr-cli.exe(可选,缺失时 classic 引擎仍然工作):
# 见 D:\Code\IDR\idr-cli,或设 IDR_CLI_EXEIDR 知识库(可选,启用 KB 匹配):从 IDR 安装目录取得 kb2.bin … kb2014.bin,放入 IDR_KB_DIR。
运行:
PYTHONPATH=src python -m delphi_mcp.serverMCP 工具
工具 | 作用 |
| 秒级判定版本/架构/引擎路由 |
| 全量分析 → 符号模型;按 section 分页(summary/classes/methods/units/forms/vars/full,默认 summary,避免大 JSON) |
| 查符号:类名子串 / 单地址 / 地址批量查表(pull,给 IDA 的地址回名) |
| 列出当前常驻内存的模型(类比 ida-mcp |
| 卸载该样本的缓存模型(释放内存),可选删 |
| 一键初筛:版本+规模+信号串(表驱动分类 persistence/creds_path/network/exec/mutex,去重;噪声默认隐藏)+ 敏感 API + DLL 导出 |
| 字符串(带 Delphi 头分类)+ 引用函数归因 |
| 导入表 + 行为分类(process/persist/net/crypto/evasion) |
| DFM 表单控件树 + 事件处理函数→地址 |
| 调用者/跳转者/数据读者(静态调用图查询) |
| 生成 |
| 导出 idc/lst/pas/idp |
与 IDA / ida-mcp 协同
核心资产是地址 → 符号名映射。两侧地址对齐:Delphi PE image_base 由 delphi_detect 输出(32-bit 通常 0x400000),与 ida-mcp survey_binary 的 base_address 核对即可(rebased 时用 delphi_renames(base=…))。
两种模式
批量灌入(plan):
delphi_renames(file, min_confidence="medium")→ 落盘.idc→ 在 IDA 里File > Script file执行一次。按需查表(pull,推荐):让 IDA 先看,遇到关注的地址再问 delphi——不把全量改名拉进上下文,也不会误灌低可信名。
pull 闭环(推荐流程)
1. IDA 定位 (ida-mcp) survey_binary / decompile / xrefs → 关注地址集合
2. 查表 delphi_query(file, addrs=[...]) → 每个地址的名字(含 kind/confidence)
模型未命中 → 回退 PE 导出表 (export:<name>)
3. 筛选 按 confidence 取舍 (high=MDT/RTTI, medium=KB虚表, low=调用图)
4. 出计划 delphi_renames(file, addrs=[...], min_confidence="medium")
→ 只含你选的地址:小 .idc + [{addr,name,confidence}](默认不动导出)
5. 回灌 IDA 执行小 .idc / 对 [{addr,name}] 逐条 ida_mcp_rename名字来源与可信度:high=编译器元数据(MDT/RTTI)、medium=KB 字节匹配(虚表槽)、low=调用图发现。min_confidence 只回灌高可信名;改名默认跳过 PE 导出(IDA 已命名),overwrite=true 才强制覆盖。
把改名应用到 IDA(当前无原生 batch rename)
.idc 落盘后两种落地方式:
IDA GUI:
File > Script file选该.idc(一次性;小.idc即 pull 模式产物)。ida-mcp 会话内:用
execute_python解析后set_name(用SN_NOWARN,不覆盖 IDA 已在名):
import re, ida_name
txt = open(r"...\sample.renames.idc", encoding="utf-8").read()
for a, n in re.findall(r'MakeNameEx\((0x[0-9A-Fa-f]+),\s*"(.*?)"', txt):
ida_name.set_name(int(a,16), n.replace('\\\\','\\').replace('\\"','"'), ida_name.SN_NOWARN)实测(GRenam,Delphi 2007)
delphi_renames(min_confidence="medium")→ 1522 条;IDA 应用 1510。3834 函数中 1185 个由
sub_变为真实符号;反编译uMain.TfrmMain.FormCreate可见ExtCtrls.TTimer.Create(...)。病毒自写函数无 Delphi 元数据 → 仍为
sub_:delphi 给“地图”,ida 给“地形”。
详见
docs/TECHNICAL.md§5.1。
配置
环境变量 | 默认 | 说明 |
|
| legacy 引擎二进制 |
|
|
|
| 空 | 设为 |
| 空 | 设为 |
| 空 | 设为 |
|
| 内存中常驻符号模型数上限(LRU 淘汰) |
|
| 设为 |
|
| idr-cli |
|
| 设为 |
| 空 |
|
opencode.json(stdio 本地,每会话各起一份进程):
"delphi-mcp": {
"type": "local",
"command": ["python", "-m", "delphi_mcp.server"],
"environment": { "PYTHONPATH": "D:\\Code\\IDR\\delphi-mcp\\src" },
"enabled": true
}常驻远程模式(推荐,避免“每会话一份 python”)
type: local 下 opencode 会按会话/窗口各起一份进程(多窗口 = 多份 python)。改成一个常驻服务 + remote 连接,所有会话共用一份(模型 LRU 也共享):
# 启动一次并保持运行(Windows 可用 scripts/serve-delphi-mcp.bat)
python -m delphi_mcp.serve
# 默认 127.0.0.1:8910 (SSE);可用环境变量调整:
# DELPHI_MCP_TRANSPORT=sse|streamable-http DELPHI_MCP_HOST DELPHI_MCP_PORT"delphi-mcp": { "type": "remote", "url": "http://127.0.0.1:8910/sse", "enabled": true }开机自启:用任务计划程序在登录时运行 scripts/serve-delphi-mcp.bat。SSE 与 streamable-http 两种传输都支持(后者路径为 /mcp)。
性能
实测(本机,含 KB 索引一次性构建):
样本 | 版本 | 类/方法 | 耗时 |
GRenam | 2006 | 109 / 3148 | 3.0s |
Rekram | 2006 | 144 / 3761 | 3.1s |
DanaBot | 10.2 | 300 / 973 | 3.5s |
Culebra | XE2-4 | 738 / 3864 | 4.2s |
libcef.dll | 2014 | 1854 / 12190 | 9.4s |
卡死问题与修复(开发笔记)
早期版本的 classic 引擎在较大样本(如 Culebra)上会假死(CPU 100%、长时间无输出)。根因是三处缺陷叠加:
主因:
build_anchor_index只构建单字节索引_anchor,从不构建两级索引_anchor2,且无幂等守卫——match_slot每次因_anchor2 is None触发全量 4.8 万条 KB 记录索引重建。Culebra 场景 7554 次匹配 × 4.8 万解析 ≈ 3.6 亿次操作。掩码 bug:匹配掩码用
1 << (k*8)(每字节只 1 bit)而非0xFF << (k*8),导致一级预筛恒假、虚表命名静默归零。低效扫描:类名回溯对每个类名做一次全
.textfind;索引构建用重型proc_info(解码函数名/参数)。
修复(见 prepare_matching / match_slot_fast):
单遍构建两级锚点索引 + 头 8 字节掩码 + 全长掩码,用
_proc_dump(仅解析 dump 段)替代重型解析match_slot_fast用 numpy 对候选桶做向量化头字节预筛,仅对幸存者做全长比对类名回溯改为单遍 numpy u32 扫描收集引用
IntfTable 解析延后到虚表命名之后(槽名查询命中缓存)
结果:Culebra 56s → 4.2s(13×),结果不变
注意:
cProfile对千万级 Python 调用有 10~50× 放大,用它剖析此类热点会放大"卡死"观感——用DELPHI_TRACE=1的分阶段计时更合适。
MCP 调用超时与修复(开发笔记)
早期版本首次调用 delphi_triage(或任何触发冷分析的 delphi_*)会在 MCP 客户端侧报 -32001: Request timed out。
根因:
classic引擎的 KB 匹配器(engines/kb.py的prepare_matching)懒加载numpy。FastMCP 把同步工具放到 anyio 工作线程执行、且此时事件循环已在运行——在该上下文里加载 numpy 的 C 扩展_multiarray_umath会死锁,工具永不返回,客户端超时。修复:在主线程、事件循环启动之前预加载 numpy(
delphi_mcp/__init__.py包导入时 +server.pymain()里兜底)。缺 numpy 时仍优雅降级(仅失去 KB 快速匹配)。
idr-cli 兜底耗时
classic 引擎若解析出 0 个类或抛异常,router 会在确认是 Delphi 二进制(Delphi 指纹:.itext 段 / .rsrc 的 TPF0 DFM / RTL 标记串)后,才回退到 legacy(C++ idr-cli)——这是正常兜底设计,不是 Python 瓶颈。子进程超时由 DELPHI_IDRCLI_TIMEOUT(默认 900s)限定;可用 DELPHI_IDRCLI_FALLBACK=0 完全关闭兜底。回退时 model.warnings 会带 classic parser yielded 0 classes; fell back to idr-cli (C++, X.Xs)。
非 Delphi 二进制的误报与快速返回
idr-cli 的快速版本判定对非 Delphi 二进制(MSVC/MinGW/Qt 等)可能误报 version=2。此时 detect 用 Delphi 指纹预检,若无任何 Delphi 标记则返回 engine=not-delphi、triage 直接回报 delphi:false、analyze 立即报错返回——不再触发 idr-cli 兜底(例:Qt 5.1.0 的 UninstallTool.exe 由 ~12s 降至 ~0.3s)。若样本确为加壳 Delphi(元数据被抹除),会被一并判为 not-delphi——加壳样本本就在能力边界之外。
能力边界
加壳样本需先脱壳(所有引擎相同)
字段类型名:用户自定义类型可解析,导入/外部类型为
None(typesTab 语义限制)老格式 MDT 不含参数/返回类型信息(
classic通过 KB 原型补全命中的函数)64 位:
modern引擎完整支持(符号 + RIP-relative 的字符串/导入引用归因,lea/mov/call [rip+disp32]、movabs);classic/legacy仅 32 位idr-cli 弱判定:对非 Delphi(MSVC/MinGW/Qt)可能误报
version=2。detect会做 Delphi 指纹预检,无可信标记则返回engine=not-delphi(快速返回,不跑分析)非 PE / 截断文件:
detect返回engine=not-pe,analyze给出明确错误
测试
cd tests
python smoke_all.py # 工具 × 双引擎 + MCP 协议层
python classic_test.py # 老格式语料
python verify_64bit.py # 64 位路径
python download_paper_corpus.py # 从 VT 拉取论文语料tests/regression_corpus.json 记录了回归用的本地样本、论文 hash 与拒绝模式清单。
目录结构
src/delphi_mcp/
├── server.py MCP 组装(12 工具注册)
├── router.py 版本判定 + 引擎路由
├── model.py SymbolModel 统一模型
├── shared.py 缓存 / 路径 / idc 写出
├── xref.py 统一交叉引用收集
├── intel.py 情报 API 再导出
├── strings_api.py 字符串提取 + 分类 + VA 归属
├── imports_api.py IAT 指纹 + 敏感 API 分类
├── dfm.py DFM 资源提取 + TPF0 二进制解析
├── engines/
│ ├── classic.py 老格式引擎(Delphi 2~2007)
│ ├── modern.py 新格式引擎(Delphi 2009+,DelphiReSym 衍生)
│ ├── legacy.py idr-cli 子进程封装
│ ├── kb.py IDR 知识库解析 + 匹配
│ ├── units.py 单元边界/初始化表
│ ├── pe_memory.py PE 文件内存视图
│ ├── vmt_scan.py VMT 扫描
│ ├── mdt.py MDT/方法/参数遍历
│ ├── rtti.py RTTI 对象遍历
│ └── fqn.py 模板感知 FQN 解析
└── tools/ MCP 工具模块(按域拆分)致谢
crypto2011/IDR — Interactive Delphi Reconstructor (MIT)。VMT 偏移表、FieldTable/MethodTable/DynamicTable/IntfTable 解析、单元/初始化表算法均移植自其源码。
ajsb85/idr-cli — IDR 的 VCL-free CLI 移植(知识库格式与匹配器参考)。
WenzWenzWenz/DelphiReSym — 新格式(VMT/MDT/RTTI)解析与论文《Towards Ghidra Reverse Engineering Tools for Delphi Executables》(BSD-3)。
modern引擎为其衍生作品。
License
MIT(本项目代码)。衍生组件见 LICENSE:modern 引擎为 DelphiReSym (BSD-3) 衍生作品,legacy 引擎运行时依赖 idr-cli (MIT)。
This server cannot be deployed
Maintenance
Related MCP Connectors
OCR, transcription, file extraction, and image generation for AI agents via MCP.
Enrich, search, assess, and manage threat intelligence through 80+ typed MCP tools.
Hyperion — MCP tool marketplace for AI agents: web, OSINT, security, research via one key.
Code intelligence platform for AI agents. 20 tools for architecture, security & impact analysis.
Related MCP Servers
- AlicenseAqualityCmaintenanceA multi-backend MCP server that exposes binary analysis capabilities from IDA Pro and Ghidra, allowing LLMs to directly drive reverse-engineering tools via natural language.11177Apache 2.0
- FlicenseNot gradedqualityDmaintenanceMCP server that exposes the complete Delphi 7 RTL/VCL index as tools for AI agents, enabling precise lookups for symbols, class members, unit interfaces, and source contexts to generate accurate legacy Delphi 7 code.-
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to locally analyze and reverse engineer binaries through a compact 12-tool MCP interface for triage, function discovery, disassembly/decompilation, cross-references, strings/imports, call graphs, memory reads, annotations, and binary diffs.1MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to inspect and decompile software they have no source for — Android APKs, Electron bundles, .NET assemblies, and Go, Rust or WASM binaries — plus adb device interaction, through a token-guarded Streamable HTTP MCP endpoint, stdio MCP, or a CLI. Ghidra-powered native binary decompilation can be opted in at startup for ELF, PE and Mach-O targets.5Do What The F*ck You Want To Public