리버스 엔지니어링: 어셈블리 중심의 파이프라인을 구축하는 사람이 또 있을까?
Reverse Engineering: Is Anyone Else Building a Pipeline Like This?
핵심 요약
AI를 활용해 C언어 변환이 아닌 어셈블리를 기반으로 게임 로직을 구조화하고 이해하는 리버스 엔지니어링 방법론을 제안함.
- 어셈블리 중심 접근 — AI가 아닌 어셈블리와 런타임 증거를 진실의 원천으로 활용함
- 단계적 분석 — 정적 분석으로 범위를 좁힌 뒤 런타임 탐색을 수행하는 워크플로우 구축
- 지식 공유 모델 — 플랫폼별로 새로 시작하지 않고 어셈블리를 공통 언어로 삼아 지식을 축적함
- 도구 활용 — 에이전트 대신 MCP와 백엔드 준비를 통해 어셈블리 기반의 구조적 이해를 도모함
AI 보조 리버스 엔지니어링 파이프라인을 작업 중인데, 드디어 이 방식이 기존과 확실히 차별화되는 핵심을 찾아낸 것 같다. 바로 어셈블리를 단순히 C 언어로 가기 위한 중간 단계가 아니라, 시스템의 중심에 두는 것이다.
SNES, N64, PS2, 그리고 결국 PC 바이너리까지 다뤄보면서 똑같은 기본 원리가 계속 통한다는 걸 확인했다. 일단 기계어 수준의 구조를 복구하고, 어셈블리가 실제로 뭘 하는지 파악한 뒤, 런타임에서 특정 가설을 테스트한다. 그런 다음에야 그 동작을 고수준의 의미론적 지식으로 격상시키는 거다.
그러니까 과정을 이렇게 처리하는 대신:
바이너리 → AI한테 C 언어로 바꿔달라고 하기 → 맞길 기도하기
나는 이런 식으로 접근하고 있다:
바이너리/ROM → 어셈블리 구조 복구 → 서브시스템을 이해할 수 있을 만큼만 디컴파일 → 구체적인 질문 던지기 → 실행 중인 게임 찔러보기 → 인과관계 검증 → 결과를 구조화된 지식으로 저장 → 그 지식을 활용해 게임을 수정하고 다음 리버스 엔지니어링 속도 높이기.
여기서 중요한 건 AI가 권위자가 아니라는 점이다. 진짜 권위자는 어셈블리, 제어 흐름, 메모리 동작, 그리고 런타임에서 얻은 증거들이다.
SNES용 MK3를 리버스 엔지니어링하면서 왜 이게 중요한지 깨달았다. 초기에 런타임 실험을 했을 때 플레이어 상태 메모리의 방향 값을 찾아낸 줄 알았다. 그런데 주변 65816 코드를 디컴파일해보니, 그 바이트들은 그냥 스택 트래픽이었다. 런타임 차이만 봤을 땐 그럴싸해 보였지만, 완전히 틀린 거였다.
그 경험 이후로 작업 방식이 완전히 바뀌었다. 먼저 디컴파일하고, 정적 분석으로 범위를 좁힌 질문을 던질 때만 런타임 탐색기( fruit fly )를 투입한다.
그 이후로 우리는 MK3의 원시 컨트롤러 하드웨어부터 기술 시스템 내부까지 파고들었다. 현재 복구된 체인은 대략 이런 식이다:
SNES 조이패드 비트 → 입력 전환 → 논리적 동작 → 타임스탬프가 찍힌 히스토리 링 → 캐릭터별 디스패치 → 21바이트 명령 디스크립터 → 타이밍 윈도우 체크 → 버튼 유지 조건 → 결과 콜백.
이 정도로도 샹청(Shang Tsung)의 변신 커맨드 같은 걸 ROM에서 바로 뽑아낼 수 있었다.
예를 들어, 디스크립터 하나를 해석하면 이렇다:
앞 → 아래 → 앞 → 강펀치, 24프레임 이내 → 변신 콜백 → 대상 파이터 ID 4.
즉, 단순히 기술이 존재한다는 걸 아는 수준을 넘어서, 게임이 내부적으로 입력 히스토리를 어떻게 기록하는지, 입력 허용 시간은 얼마인지, 어떤 버튼 조건이 허용되는지, 캐릭터별 핸들러는 어떻게 선택되는지, 그리고 커맨드가 어떤 콜백이나 상태를 실행하는지까지 다 알게 되는 거다.
이 거대한 실험은 MK3보다 훨씬 더 큰 범위를 다룬다. SNES 쪽은 현재 775개의 ROM 코퍼스 전반에 걸쳐 구조 복구와 임시 디컴파일을 진행 중이고, 각 ROM에서 얻은 지식이 플랫폼 수준의 공유 지식으로 쌓이고 있다. 플랫폼마다 완전히 다른 방법론으로 새로 시작하는 게 아니라, 이 똑같은 개념을 N64, PS2, PC 리버스 엔지니어링에도 그대로 적용하고 있다.
장기적인 구상은 기본적으로 이거다:
기계어 → 어셈블리 이해 → 의미론적 모델 → 재현 가능한 수정 레이어
이 모든 과정의 밑바닥에는 어셈블리가 절대적인 진실(ground truth)로 남아있게 된다.
흥미로운 점은, 요즘 AI 디컴파일 작업들이 어셈블리를 최대한 빨리 C 언어로 매칭하는 데만 혈안이 되어 있다는 거다. 물론 그것도 유용하지만, 나는 AI가 기계어 자체에 대한 지속 가능한 이해를 구축하는 데 도움을 줄 수 있는지, 특히 원본 소스 코드를 영영 복구할 수 없는 상황에서 그게 가능한지가 더 궁금하다.
매칭 디컴파일 프로젝트, 에뮬레이터-에이전트 인터페이스, 바이너리 분석 에이전트, 결정론적 에뮬레이터 툴 같은 것들이 이 작업의 파편들과 겹치는 건 봤다. 하지만 어셈블리를 여러 게임 플랫폼을 관통하는 지속적인 공용 언어로 취급하고, 그 위에 런타임 실험과 지식 그래프를 층층이 쌓아 올리는 방식은 아직 흔치 않은 것 같다.


