
32비트 DOS 및 Win32 게임(1993-2010) 리버스 엔지니어링을 위한 Headless-Ghidra 툴킷: 자체 LE/LX 로더, Watcom 호출 규약, 라이브러리 시그니처, MCP 서버

헤드리스 Ghidra로 대략 1993~2010년 사이의 32비트 게임을 디컴파일하기 위한 툴킷:
출력물은 모든 함수를 담은 하나의 큰 .c 파일과 인덱스(함수, 호출 그래프, 문자열,
fixup/포인터 테이블, 임포트)를 포함하는 워크스페이스로, 이를 grep하고 사람이나 AI 에이전트
간에 분할할 수 있습니다. 분석 중 발견된 이름은 Ghidra로 다시 들어가고 내보내기가
재생성됩니다.
사전 요구사항: Ghidra 12.x
(압축 해제), JDK 21+ (JAVA_HOME), Python 3.10+.
pipx install git+https://github.com/nemo22/retrokit # or from a checkout: pip install . (or python -m retrokit)
retrokit doctor # checks Python, Ghidra, Java, loader, cspecs
retrokit install-loader # once per Ghidra install (DOS LE/LX only)
Ghidra는 --ghidra DIR, $GHIDRA_INSTALL_DIR, 또는 게임이나 키트 옆의 ghidra/ghidra_* 디렉터리를 통해 찾습니다. install-loader는 해당 Ghidra에 대해 javac로 로더를 컴파일하고( Gradle 없이), 이를 Ghidra/Extensions에 설치하고 Watcom 컴파일러 스펙을 등록합니다. Ghidra를 업데이트한 후에는 다시 실행하세요(doctor가 언제인지 알려줍니다).
retrokit info GAME.EXE # format, DOS extender, compiler, calling convention
retrokit analyze GAME.EXE # full pipeline -> GAME_analysis/ (-o DIR to choose)
retrokit show GAME_analysis FUN_00012345 main
retrokit tables GAME_analysis # function-pointer and string tables (from fixups)
retrokit names GAME_analysis # apply notes/names_*.csv, re-export
retrokit reexport GAME_analysis # re-run the fix-up passes + export without re-importing
analyze는 형식, 로더, 그리고 Watcom의 경우 호출 규약을 감지하며
(--cspec watcom|watcomreg로 재정의 가능), 이를 GAME_analysis/retrokit.json에 저장합니다;
이후 명령에는 워크스페이스만 필요합니다. 워크스페이스는:
GAME_analysis/
retrokit.json how the binary was analysed
decomp/ <exe>_decompiled.c, functions.csv (addr,name,size,callers,callees,cc,signature),
calls.txt, strings.txt, data_symbols.txt, memory_blocks.txt,
fixups.txt (source -> target of every pointer: the key to pointer tables
and to which function uses which string), imports.txt (PE)
notes/ findings, names_<topic>.csv proposals
ghidra_project/ the Ghidra project (open it in the Ghidra GUI too)
logs/
AI 에이전트: retrokit mcp GAME_analysis는 워크스페이스 위에서 동작하는 MCP 서버(stdio, 추가 패키지 불필요)로,
함수, 디컴파일된 코드, 호출 그래프, 상호 참조, 문자열, 포인터
테이블, 디스어셈블리 및 바이트, 라이브러리를 제공합니다. 이름 제안과 노트를 기록하고
이름이 적용된 상태로 다시 내보낼 수 있습니다(요청 시, 백그라운드에서). Claude Code:
claude mcp add retrokit -- retrokit mcp /path/to/GAME_analysis
다른 클라이언트를 위한 설정, 모든 도구와 에이전트가 작동해야 하는 방식: docs/MCP.md; 에이전트를 위한 짧은 버전은 AGENTS.md에 있습니다.
이름: 제안을 notes/names_<topic>.csv에 작성합니다(addr,name,confidence,comment, confidence는
V 검증됨 또는 G 추측); retrokit names WS는 함수/레이블의 이름을 바꾸고(V가 G보다 우선,
충돌 시 _<addr>가 붙음) 다시 내보냅니다.
파이프라인이 하는 일:
retrokit libs (info와 analyze의 일부이기도 하며 ->
notes/libraries.md)는 당시의 약 20개 라이브러리 - Miles/AIL, HMI SOS, DIGPAK,
Smacker, Bink, FMOD, BASS, DirectX, zlib, libjpeg, libpng, PKWARE DCL, Lua, ... - 를
문자열, 임포트, 데이터 파일에서 인식하고, 버전, 해당 형식에 대한 참고 사항, 포팅 힌트를 제공합니다.
라이브러리 코드는 시그니처로 찾습니다(제공되는 것: Watcom C/C++ 런타임, Open Watcom의
수학 및 C++ 라이브러리, zlib 1.0.4-1.2.3, libjpeg 6b; retrokit sigs build는 보유한
라이브러리에서, sigs learn은 식별한 함수에서 이를 만듭니다) - 정확히 일치하는 것을 먼저,
그다음 다른 컴파일러 버전의 유사한 코드를 - 이름을 붙이고 retrokit/knowledge/*.h에서
타입을 지정합니다.switch 점프 테이블은
해당 함수 안에 유지하고, 잘못된 "no return" 플래그는 되돌리고, 짧은 문자열은 정의하고
문자열 리터럴은 "text"로 표시하며, 매개변수 개수는 호출 지점의 ADD ESP,n 정리에서,
프로토타입은 피호출자 우선으로 복원한 뒤 내보냅니다.기타 명령: classes (RTTI에서 MSVC C++ 클래스), libs (사용 중인 라이브러리), convert (XMIDI/HMI/HMP -> MIDI, VOC -> WAV,
Smacker/Bink/FLIC -> MP4, 내용 기준), sigs match|build|learn (라이브러리 시그니처, docs/WORKFLOW.md 참조),
entries (PE: 함수가 없는 코드 주소), modules --rules FILE
(PE: assert 경로를 통해 함수 → 원본 소스 파일), strings EXE OUT (Ghidra 없이 PE 문자열 목록),
match (관련 EXE로 이름 전송: 속편, 애드온, 다른 버전),
le EXE info|dump|rec|s16|s32 (Ghidra 주소에서 LE의 테이블 읽기), rnc (RNC ProPack),
flic info|png|video (Autodesk FLI/FLC). 옵션은 retrokit COMMAND --help를 참조하세요.
자세한 절차, 예상 사항, 알려진 함정은 docs/WORKFLOW.md에 있습니다; MCP 서버는
docs/MCP.md에; AI 에이전트용 작업 템플릿은 docs/AGENT_PROMPTS.md에; 계획된
작업은 docs/ROADMAP.md에; 유지보수 및 릴리스는 docs/MAINTAINING.md에 있습니다.
retrokit/ Python package (CLI: retrokit/cli.py)
ghidra_scripts/ headless Ghidra scripts used by the pipelines
tools/ standalone Python tools behind the CLI commands
le-loader/ LE/LX loader for Ghidra (Java) + Watcom compiler specs (data/languages/)
sigs/ library signatures (Open Watcom C run-time)
knowledge/ libraries.json (library catalog), library prototypes as C headers
scripts/ build_sigs.py: rebuilds the shipped signatures
tests/ synthetic test programs, scoring against the linker map, baseline
docs/ WORKFLOW, AGENT_PROMPTS, ROADMAP
| Ghidra 스크립트 | 목적 |
|---|---|
CreateFunctionsFromFixups.java | LE: 32비트 fixup 대상 위치의 함수를 코드로 변환; 코드 내 switch 테이블 처리 |
CreateFunctionsAtEntries.java | 주어진 주소(목록 또는 @file)의 함수 생성, 선택적으로 코드 갭의 fixup 또는 프롤로그에서 생성 |
FixTruncatedCallers.java | 호출자를 잘라내는 잘못된 "no return"을 제거 |
FixAnalysis.java | 수동 수정: noreturn:ADDR, func:ADDR |
MarkStringsConstant.java | 짧은 문자열을 정의하고, 쓰기 가능한 데이터의 문자열을 constant로 표시(디컴파일 내 리터럴) |
ApplyLibraryPrototypes.java | 이름이 지정된 라이브러리 함수에 대한 문서화된 프로토타입(knowledge/*.h), 태그 LIBRARY |
ApplyStackConvention.java | 호출 지점의 ADD ESP,n에서 파라미터 개수 / __cdecl / 가변 인자, RET n에서 __stdcall |
RecoverPrototypes.java | 디컴파일러로부터 프로토타입 복원, 호출 그래프 레벨 기준 상향식 |
ApplyNames.java | names_*.csv에서 이름 적용 |
ExportDecompiled.java | .c + functions.csv, calls.txt, strings.txt, … 내보내기 |
DumpFixups.java | LE fixup / PE 베이스 재배치 → fixups.txt |
DumpImports.java | PE 임포트 및 IAT 슬롯 → imports.txt |
DumpFunctions.java | 함수 목록만 (PE 엔트리 패스 사이) |
DumpDisasm.java | 함수의 디스어셈블리를 stdout으로 출력 |
EnableDeepAnalysis.java | 느린 분석기 활성화 (권장하지 않음, WORKFLOW 참조) |
tests/는 Open Watcom으로 작은 합성 프로그램을 빌드하고(DOS/4GW, DOS/32A, PMODE/W, DOS/4G 바인드, OS/2 LX, Win32; 스택 및 레지스터 규약), 각 이미지의 독립적인 Python 모델과 로더를 대조 검증하며, 이들에 대해 retrokit analyze를 실행하고 그 결과를 링커 맵(함수 주소, 파라미터 개수, 호출 인자, 문자열 리터럴, 잘린 함수, 디컴파일러 노이즈)과 비교 채점합니다. tests/README.md를 참조하세요.
이슈와 풀 리퀘스트는 GitHub에서 환영합니다. 기본 저장소는 다른 곳에서 유지 관리되며 GitHub로 미러링되므로, 풀 리퀘스트는 그곳에서 병합되고 미러가 동기화되면 GitHub에 병합된 것으로 표시됩니다(docs/MAINTAINING.md). 게임 파일이나 디컴파일된 게임 코드를 첨부하지 마세요. 대신 바이너리를 설명하고(형식, 익스텐더, 컴파일러, 무엇이 잘못되는지), 가능하다면 tests/에 있는 것처럼 Open Watcom으로 빌드한 작은 프로그램으로 재현해 주세요.
retro-kit은 Claude Code를 통해 Claude(Anthropic)로 개발됩니다. 대부분의 코드와 문서는 유지 관리자의 지시 아래 Claude가 작성하며, 유지 관리자가 범위와 설계를 정하고 Windows와 Linux에서 테스트하며 각 릴리스에 무엇이 들어갈지 결정합니다. 커밋에는 Claude가 공동 저자로 표시됩니다. 품질은 tests/의 테스트 코퍼스로 추적됩니다. 합성 프로그램을 링커 맵과 비교 채점하며, 기준선은 Windows와 Linux의 CI에서 검사됩니다.