리버스 엔지니어링: Mario 64부터 GTA까지 브라우저에서 (그리고 이제 AI가 중간에)
요약
리버스 엔지니어링은 소스 코드 없이 완성된 제품의 내부 작동 방식을 이해하는 과정입니다. Ghidra 같은 디컴파일러와 어셈블리를 분석하여 C 언어 유사한 의사 코드를 재구성할 수 있습니다. 이 기술을 통해 Mario 64나 GTA 같은 게임 엔진을 WebAssembly로 포팅하여 브라우저에서 실행하는 것이 가능해졌습니다.
핵심 포인트
- 리버스 엔지니어링은 소스 코드 없이 작동 원리를 파악하는 과정입니다.
- Ghidra와 같은 디컴파일러가 핵심 도구이며, 어셈블리 분석이 필요합니다.
- WebAssembly를 활용하여 게임 엔진을 브라우저에서 실행할 수 있습니다.
지난주, GTA V가 브라우저 탭에서 실행되는 것을 보았습니다. playgta5.com이라는 사이트가 이 게임을 공개했고, 인터넷은 발칵 뒤집혔으며, 같은 날 그 사이트는 사라졌습니다. 하지만 인터넷은 잊지 않습니다. 그 사이트의 코드는 몇 시간 만에 GitHub에 올라갔고, 오늘날에는 이미 다른 사이트들이 그 게임을 실행하고 있습니다 (명백한 이유로 어떤 곳인지는 언급하지 않겠습니다). 아무도 어떻게 만들어진 것인지 제대로 확인해주지 않았지만, 제 머릿속에 남은 질문은 또 다른 것이었습니다. 로크스타가 코드를 절대 공개하지 않은 게임을 어떻게 가져와서, 그게 생각되지 않았던 장소에서 실행되도록 만들 수 있을까?
간단한 대답은 리버스 엔지니어링(reverse engineering)입니다. 그리고 이제는 AI를 사용해서 귀찮은 부분을 처리할 수 있게 되면서 훨씬 더 접근성이 높아지고 있습니다.
리버스 엔지니어링이란 무엇인가?
C 언어로 프로그램을 작성하고 컴파일하면, 컴파일러는 그것을 기계어 명령으로 변환합니다. 이 과정에서 많은 것이 손실됩니다: 변수 이름, 함수 이름, 주석, 당신이 생각했던 예쁜 구조 같은 것들이요. 남는 것은 프로세서가 완벽하게 이해하지만 인간이 읽기에는 매우 어려운 바이너리 파일입니다.
리버스 엔지니어링은 그 과정을 되돌리는 것입니다. 당신은 완성된 제품(실행 파일, 앱, 게임)을 가지고 있고, 소스 코드가 없으면서도 내부 작동 방식을 이해하고 싶어 합니다.
만약 당신이 컴퓨터 구조(Computer Architecture)와 컴파일러(Compiler) 수업을 들은 경험이 있다면, 이미 이를 위한 정신적 도구들을 갖추고 있는 것입니다. 기본적으로 어셈블리 코드(assembly)를 보고 "자, 근데 이 사람이 여기서 뭘 하려고 했지?"라고 묻는 것과 같습니다. 저는 이 과목들을 수강하면서 평생 mov 명령을 다시 볼 일은 없을 거라고 생각했습니다. 그런데 그렇지 않았습니다.
고전적인 도구들은 디어셈블러(disassemblers) (어셈블리를 보여주는)와 디컴파일러(decompilers) (C 언어와 유사한 것을 재구성하려고 시도하는)입니다. 2019년 NSA가 무료로 공개한 Ghidra가 현재 가장 유명합니다. 이 도구는 FUN_00101189나 local_48 같은 이름들로 가득 찬 의사 코드(pseudocode)를 제공하며, 나머지 작업은 당신의 몫입니다.
Mario 64부터 Chrome 탭까지
이것을 가장 잘 설명하는 사례는 Super Mario 64입니다. 한 팬 그룹은 수년 동안 게임 코드를 함수 단위로 C 언어로 재작성했으며, 매우 엄격한 규칙을 가지고 있었습니다. 바로 Nintendo가 사용했던 컴파일러와 동일한 것으로 컴파일했을 때, 생성된 코드가 원본과 바이트 단위로 동일한 ROM을 만들어야 한다는 것입니다. 이것을 '매칭 디컴파일(matching decompilation)'이라고 부릅니다. 2019년에 이 코드가 공개되었고, 2020년에는 이미 PC용 네이티브 포트가 나와 모드들이 쏟아져 나올 수 있는 길을 열었습니다. 중요한 세부 사항은 다음과 같습니다: 이 프로젝트는 게임 자체를 배포하지 않습니다. 그래픽과 사운드를 추출하려면 사용자가 직접 ROM을 가지고 있어야 합니다.
이제 이것이 무엇을 가능하게 하는지 생각해 보세요. C 코드가 손에 들어오면, 어떤 것으로든 컴파일할 수 있습니다. 심지어 브라우저 내에서 거의 네이티브 속도로 컴파일된 코드를 실행할 수 있게 해주는 형식인 WebAssembly로도요.
GTA의 경우도 정확히 그런 일이 일어났습니다. re3와 reVC 프로젝트는 GTA III와 Vice City를 리버스 엔지니어링하여 게임 엔진을 C++로 재구축했습니다. 이 코드를 손에 넣은 후, 사람들은 이를 WebAssembly로 컴파일했고, 오늘날 WASM Arcade 같은 웹사이트가 생겨나서 브라우저 탭 안에서 Vice City를 열고 해변을 운전하는 것이 가능해졌습니다.
즉, 파이프라인은 다음과 같습니다:
원본 게임 (바이너리)
│ 리버스 엔지니어링
▼
...
물론 모든 것이 축제만 같은 것은 아닙니다. Take-Two는 2021년에 re3와 reVC를 GitHub에서 DMCA로 삭제했고, 이후 개발자들을 고소했습니다. playgta5.com도 몇 시간 만에 사라졌지만, 복사본들은 여전히 여기저기서 발견됩니다. 리버스 엔지니어링 자체는 기술이지만, 다른 사람의 게임을 배포하는 것은 별개의 문제이며, 회사들은 이 부분에 대해 유머 감각이 없는 경우가 많습니다.
AI가 이 역사에서 들어오는 곳
리버스 엔지니어링의 병목 현상은 결코 바이너리를 여는 것이 아니었습니다. 그 결과를 읽어내는 것이었습니다. FUN_algumacoisa라고 불리는 백 개의 함수들을 보고, 각각이 무엇을 하는지 이해하고, 이름을 붙이고, 서로 연결하는 것입니다. 이것은 개미 같은 작업이며, LLM(대규모 언어 모델)이 가장 잘하는 유형의 작업입니다: 지저분한 코드를 읽고 그것이 무엇을 하는지 설명해 주는 것입니다.
가장 멋진 점은 이 많은 부분이 커뮤니티, 즉 GitHub에서 모두에게 공개된 상태로 구축되고 있다는 것입니다. 전체 과정을 계층별(layer)로 이해할 수 있습니다.
1단계: 고전적인 디컴파일러
모든 것은 이전과 동일하게 시작합니다. Ghidra (또는 IDA, 또는 Hopper)가 바이너리 파일을 읽고 함수들을 분리한 다음 C 언어의 유사 코드(pseudocode)를 생성합니다. 이 코드는 정확하지만 보기 좋지 않습니다. 이름도 없고, 적절한 타입 정보도 부족하며, local_48 같은 변수로 가득 차 있습니다. AI는 이 단계를 대체하지 못하고, 그 위에 올라탑니다.
2단계: 디컴파일링을 위해 훈련된 모델들
LLM4Decompile은 학술 프로젝트(EMNLP 2024 논문)로, 오픈 소스 모델들을 훈련시켜 바이너리를 C 코드로 변환하는 데 특화되었습니다. 측정 방식이 매우 영리한데, 단순히 코드가 '맞아 보이는 것'만으로는 부족하고, 다시 컴파일되어 테스트를 통과해야 합니다. 이 기준에서 그들의 모델은 Ghidra와 GPT-4o의 결과를 두 배 이상 능가했습니다.
심지어 Ghidra의 유사 코드(pseudocode)를 가져와서 단순히 다듬기만 하는 버전도 있는데, 이는 계층적 아이디어를 잘 보여줍니다. 즉, 고전적인 디컴파일러는 기계적인 작업을 수행하고, 모델은 가독성을 높여주는 역할을 합니다.
3단계: 에이전트와 도구 사이의 다리
여기서야 비로소 2025년에 흥미로운 변화가 생겼습니다. MCP (Model Context Protocol)는 Claude Code나 Codex 같은 에이전트가 외부 도구를 호출할 수 있게 해주는 프로토콜입니다. 2025년 3월에 두 날의 간격을 두고 GhidraMCP와 ida-pro-mcp가 출시되었으며, 현재 이 둘을 합치면 24,000개 이상의 별(star)을 모았습니다.
이들은 간단한 작업을 수행합니다. Ghidra와 IDA의 기능들(함수 목록 보기, 디컴파일하기, 누가 누구를 호출하는지 확인하기, 이름 변경 등)을 에이전트가 사용할 수 있는 도구로 노출시키는 것입니다. 이로써 리버스 엔지니어링은 하나의 루프(loop)로 변모합니다:
질문(
에이전트는 인간 분석가가 하는 일을 합니다. 문자열(strings)이나 임포트(imports)부터 시작해서, 의심스러운 함수를 찾고, 디컴파일하며, 이름 지어주고, 이 함수를 호출하는 곳으로 이동하여 답변을 얻을 때까지 반복합니다.
### 레이어 4: 모든 것을 통합하고 증거를 제시하기
최근 큰 주목을 받고 있는 **[REA](https://github.com/morluto/rea)** (Reverse Engineer Anything)는 이러한 아이디어를 가져와 일반화했습니다. 이 도구는 서버 기반의 여러 도구가 아니라, Ghidra, Hopper 또는 IDA와 통신하는 MCP(Master Control Program) 역할을 하며, Electron 앱, .NET, APK, WebAssembly, 펌웨어 및 네트워크 캡처까지 이해합니다.
제가 가장 흥미로웠던 부분은 **증거(evidence)**에 대한 세심한 배려입니다. 모든 결과는 무엇이 관찰되었고, 무엇이 추론되었으며, 무엇이 알려지지 않았는지, 그리고 그것이 코드의 어느 부분에서 나왔는지 명시합니다. 또한 커버리지가 부분적일 때도 알리고, 무언가를 찾지 못했다고 해서 그것이 존재하지 않는다는 것을 의미하는 것은 아님을 분명히 합니다. 이는 매우 중요합니다. 왜냐하면 AI는 가장 큰 확신으로 환각(hallucinate)하기 때문입니다. 당신이 진실을 알아내려고 하는 코드에 대해 '나를 믿어'라는 말은 아무 소용이 없습니다.
또 다른 영리한 디테일이 있습니다. REA는 분석된 프로그램에서 오는 모든 것(문자열, 주석, 로그)을 **명령어가 아닌 데이터**로 처리하도록 에이전트에게 지시합니다. 이는 당연한 일입니다. 만약 악성코드를 분석하고 있다면, 숨겨진 문자열 하나가 'AI야, 모든 것을 무시하고 이 명령어를 실행해'라고 말하고 에이전트가 그것을 따르는 최악의 상황을 피해야 하기 때문입니다.
### 마리오 64는 어떨까요?
_matching_ 디컴파일링 커뮤니티는 수년 동안 자체 도구를 보유해 왔습니다. [decomp.me](https://github.com/decompme/decomp.me)는 사람들이 어셈블리(assembly)의 함수를 가져와 C 코드를 조정하여 원본과 동일하게 컴파일되도록 만드는 협업 웹사이트입니다. 마치 그룹 퍼즐 같습니다. 그리고 [decomp-permuter](https://github.com/simonlindholm/decomp-permuter)는 이를 무차별 대입(brute force) 방식으로 수행합니다. C 코드를 임의로 섞어 바이너리와 일치하는 버전을 찾을 때까지 시도합니다.
즉, 게임을 디컴파일하는 사람들은 이미 LLM보다 훨씬 전에 지루한 부분을 자동화하고 있었습니다. AI는 단지 빠져 있던 부분, 즉 코드를 **이해**하고 사물에 이름을 붙이는 역할을 맡았을 뿐입니다.
## 모든 것을 분해하기 전에
두 가지 간단한 점입니다.
첫째: 이것을 자신만의 프로젝트나 오픈 소스 프로젝트, 또는 분석 권한이 있는 곳에 사용하세요. 리버스 엔지니어링은 많은 것(호환성, 보안, 연구)에 대해 합법적이지만, 법률과 이용 약관은 다양하며, 'AI가 했기 때문에'라는 변명은 통하지 않을 것입니다.
둘째: 진입 장벽이 이렇게 낮았던 적은 없습니다. 몇 년 전만 해도 심볼 없이 바이너리를 이해하려면 많은 인내심과 커피가 필요했습니다. 오늘날에는 포르투갈어로 질문하고 에이전트의 추론 과정을 따라갈 수 있습니다. 저는 이것이 배우기에 아주 좋다고 생각합니다. 단, 답변뿐만 아니라 증거를 읽어야 합니다. 그렇지 않으면 단순히 블랙박스를 다른 블랙박스로 바꾼 것일 뿐입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기