
用于 IDA Pro 和 Ghidra 的轻量级 TCP JSON 桥接服务器,通过简单的套接字协议暴露逆向工程工作流。
允许外部工具、CLI 脚本、Python 实用程序和自动化流水线查询反编译、交叉引用、符号、虚表、RTTI、结构体和补丁内存,无需手动 GUI 交互。
在处理大型逆向项目且同时打开多个二进制文件时(例如游戏客户端、启动器、DLL 代理和存根同时打开):
BASE_PORT = 5073 开始扫描,并自动探测后续端口(5073、5074、5075、5076...),直到找到可用端口。在 IDA Pro 中,Python 解释器在多次脚本执行之间保持存活:
ID_Server.py 将正在运行的服务器句柄注册到 builtins._ida_bridge_prev。stop() 并等待其线程结束(join(3.0)),在启动新服务器之前干净地释放端口。Address already in use 或孤立的线程。QUIT、STOP、EXIT 或 SHUTDOWN。服务器以 {"ok": true, "shutdown": true} 确认并立即关闭。ida_bridge_stop(),或直接关闭 IDA(守护线程会自动退出)。is_cancelled()),或发送 QUIT。.idb / .i64)。File -> Script file... / Alt+F7),执行:
import ID_Server
127.0.0.1:5073(或下一个可用端口)。ida_bridge_stop()
Window -> Script Manager)中,添加包含 Ghidra_Server.py 的文件夹,或直接在 Python 解释器中运行它。127.0.0.1:5073(或下一个空闲端口)。命令是通过 TCP(127.0.0.1:<PORT>)发送的纯换行分隔字符串。服务器回复一个 JSON 对象(或对于旧版命令回复制表符分隔的文本)。
| 命令 | 语法 | 描述 |
|---|---|---|
PING | PING | 健康检查。返回 "pong"。 |
CURRENT | CURRENT | 返回当前光标地址、函数名、大小、汇编指令和反编译代码。 |
NAME | NAME <ea> | 返回在 <ea> 处定义的符号/函数名。 |
FUNC | FUNC <addr> | 返回完整的函数元数据、入口点、大小、签名、汇编和 Hex-Rays/Ghidra 反编译。 |
DECOMP | DECOMP <addr> | FUNC 的别名。反编译目标函数。 |
DISASM | DISASM <ea> [n] | 返回从 <ea> 开始的 [n] 条指令的反汇编行(默认:40)。 |
FIND | FIND <substr> | 在所有符号和函数名中不区分大小写地搜索匹配 <substr> 的内容(最多 300 个匹配)。 |
EXPORT | EXPORT [path] | 将所有非虚拟符号、修饰名和还原名导出到文本文件(默认:C:\Contexto\ida_names.txt)。 |
HELP | HELP | 返回服务器支持的所有可用命令的 JSON 列表。 |
QUIT | QUIT | 优雅地关闭客户端连接并停止桥接服务器套接字。 |
| 命令 | 语法 | 描述 |
|---|---|---|
XREF | XREF <addr> | 列出所有指向 <addr> 的传入交叉引用(代码调用、数据读取/写入)。 |
XFROM | XFROM <addr> | 列出所有源自 <addr> 的传出交叉引用。 |
CALLERS | CALLERS <addr> | 过滤传入引用,仅返回调用点(包括已解析的间接调用)。 |
READERS | READERS <addr> | 过滤传入引用,仅返回从 <addr> 读取的指令。 |
WRITERS | WRITERS <addr> | 过滤传入引用,仅返回向 <addr> 写入的指令。 |
DECOMP_XREF | DECOMP_XREF <addr> | 在单个请求中批量反编译 <addr> 的每个调用函数。 |
IMPORTXREF | IMPORTXREF <name> | 在整个二进制文件中定位导入的 Windows/C API 的所有调用点(例如 IMPORTXREF WSASendTo)。 |
TRACE | TRACE <addr> | 跟踪 <addr> 周围的执行流和基本块。 |
| 命令 | 语法 | 描述 |
|---|---|---|
READPTR | READPTR <addr> [count] | 将内存作为指针链(32 位或 64 位)读取,并对每个目标进行分类(func、string、vtable)。 |
FINDPTR | FINDPTR <addr> | 扫描全局数据和表,查找任何引用 <addr> 的指针(查找虚表、分发表)。 |
STRUCT | STRUCT <addr> [n] | 启发式转储连续内存,将字段解释为整数、浮点数、指针和字符串。 |
DEFSTRUCT | DEFSTRUCT <name> [size] | 在数据库类型库中创建一个新的命名结构体。 |
SETFIELD | SETFIELD <struct> <off> <type> [name] | 在 <off> 处使用 <type> 和可选字段名定义或修改结构体字段。 |
MKPTRS | MKPTRS <addr> [count] | 批量将原始数据库字节转换为类型化指针。 |
NEARSTR | NEARSTR <addr> | 查找代码或数据段中范围内附近的字符串引用。 |
| 命令 | 语法 | 描述 |
|---|---|---|
VTABLE | VTABLE <funcaddr> | 识别哪些虚表包含 <funcaddr>,包括相邻的方法槽。 |
VTDUMP | VTDUMP <addr> [count] | 转储整个虚表:将每个槽解析为其方法名、偏移和索引。 |
RTTI | RTTI <addr|Name> | 遍历 MSVC C++ RTTI 结构(TypeDescriptor -> CompleteObjectLocator -> vftable)以解析类层次结构和基类。 |
| 命令 | 语法 | 描述 |
|---|---|---|
STR | STR <ascii> | 在所有已加载段中搜索 ASCII 字符串。 |
WSTR | WSTR <utf16> | 在所有已加载段中搜索 UTF-16 宽字符串。 |
BYTES | BYTES <hex> | 搜索原始操作码或数据字节序列(例如 BYTES 55 8B EC 83 EC)。 |
| 命令 | 语法 | 描述 |
|---|---|---|
RENAME_FUNC | RENAME_FUNC <addr> <name> | 将 <addr> 处的函数重命名为 <name>。 |
RENAME_SYMBOL | RENAME_SYMBOL <addr> <name> | 重命名全局数据符号或变量。 |
RENAME_LABEL | RENAME_LABEL <addr> <name> | 重命名代码标签或跳转目标。 |
RENAME_LOCAL | RENAME_LOCAL <func> <old> <new> | 在反编译视图中重命名局部变量。 |
RETYPE | RETYPE <func> <var> <type> | 修改反编译器中变量或参数的数据类型(例如 RETYPE 00401000 a1 Player*)。 |
SETCONV | SETCONV <func> <convention> | 设置调用约定(__cdecl、__stdcall、__fastcall、__thiscall)。 |
MAKEFUNC | MAKEFUNC <addr> | 强制在 <addr> 处创建函数边界。 |
PATCH | PATCH <addr> <hex> | 直接覆盖数据库中的字节(例如 PATCH 00401234 90 90)。 |
PCODE | PCODE <addr> | 转储 Hex-Rays 微码或 Ghidra P-Code 中间表示,用于深度编译器分析。 |
import socket
import json
class BridgeClient:
def __init__(self, host="127.0.0.1", port=5073):
self.host = host
self.port = port
def send(self, cmd: str) -> dict:
s = socket.socket()
s.connect((self.host, self.port))
s.sendall((cmd + "\n").encode("utf-8"))
chunks = []
while True:
chunk = s.recv(16384)
if not chunk:
break
chunks.append(chunk)
if b"\n" in chunk:
break
s.close()
raw = b"".join(chunks).decode("utf-8", errors="ignore").strip()
try:
return json.loads(raw)
except json.JSONDecodeError:
return {"raw": raw}
# Example usage:
client = BridgeClient(port=5074)
# Decompile target function
res = client.send("FUNC 007B11C0")
if res.get("ok"):
print("Function Name:", res.get("function_name"))
print(res["code"][:300])
# Trace incoming callers
callers = client.send("CALLERS 007B11C0")
print("Total callers:", callers.get("count"))
MIT