IDA Pro와 Ghidra용 TCP JSON 브리지 서버로, 디컴파일, 상호 참조, 심볼, 가상 함수 테이블(vtable), RTTI 및 메모리 패칭을 외부 스크립트와 자동화 파이프라인에 노출합니다.
IDA Pro와 Ghidra를 위한 경량 TCP JSON 브리지 서버로, 간단한 소켓 프로토콜을 통해 리버스 엔지니어링 워크플로우를 노출합니다.
외부 도구, CLI 스크립트, Python 유틸리티 및 자동화 파이프라인이 수동 GUI 조작 없이 디컴파일, 상호 참조, 심볼, 가상 테이블, RTTI, 구조체 및 메모리 패치를 쿼리할 수 있게 해줍니다.
여러 바이너리를 동시에 열어두고 대규모 리버싱 프로젝트를 진행할 때 (예: 게임 클라이언트, 런처, 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>을 참조하는 포인터를 찾습니다 (vtable, 디스패치 테이블 찾기). |
STRUCT | STRUCT <addr> [n] | 연속된 메모리를 휴리스틱하게 덤프하여 필드를 int, float, 포인터 및 문자열로 해석합니다. |
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> | 원시 opcode 또는 데이터 바이트 시퀀스를 검색합니다 (예: 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 Microcode 또는 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