TECH 으로 돌아가기
TECH HACKER NEWS 7분 읽기 26 READS

11년에 걸친 리버스 엔지니어링, DOS 윙 커맨더에 협동 멀티플레이를 심다

11년에 걸친 리버스 엔지니어링, DOS 윙 커맨더에 협동 멀티플레이를 심다
SOURCE IMAGE · HACKER NEWS

1990년대 PC 게임을 상징하던 우주 전투 시뮬레이션 '윙 커맨더(Wing Commander)'를 두 사람이 각자의 전투기를 몰고 함께 날 수 있게 만든 개발 기록이 공개됐다. 작성자는 형제인 자신과 패트릭이 어린 시절 한 대의 기체를 둘이 나눠 조종하던 추억에서 출발해, 11년에 걸쳐 원본 게임을 분석하고 네트워크 멀티플레이를 이식한 과정을 상세히 정리했다. 단순한 모드가 아니라 1990년대 DOS 바이너리의 내부 동작을 하나하나 역추적해 두 에뮬레이터 인스턴스를 동기화한, 전형적인 장기 리버스 엔지니어링 프로젝트다.

640K 메모리를 뒤져 좌표를 찾다

시작은 2015년 10월, DOSBox에서 고전 윙 커맨더를 돌리다 '게임 전체가 640K 안에 들어간다면 메모리를 덤프해 플레이어와 윙맨의 좌표 위치를 찾아낼 수 있지 않을까'라는 착상이었다. 문제는 100만 바이트도 안 되는 공간에서 특정 좌표가 저장된 번지를 어떻게 특정하느냐였다. 작성자는 변수를 통제하는 실험 설계로 접근했다. 적 기체가 모두 사라진 빈 우주 공간까지 날아가 정지 상태에서 메모리를 두 번 스냅샷해 '배경 잡음'을 걸러내고, 직진만 한 뒤 다시 측정해 바뀐 바이트를 비교하는 방식이다. 마우스를 꺼 회전을 막으면 한 축만 변하도록 조건을 좁힐 수 있었다.

이 차분 비교로 데이터 세그먼트에서 35개의 변화 클러스터가 나왔고, 부동소수점이나 작은 정수 변화를 눈으로 확인해 13개 후보로 줄인 끝에 13D3:A9C2 번지를 찾아냈다. DOSBox 디버거의 SM 명령으로 그 주소에 값을 더하자 기체가 실제로 앞으로 튀어나갔다. 회전 벡터는 더 까다로웠는데, 256을 1.0으로 쓰는 4바이트 스칼라 구조 덕분에 작은 회전은 대개 한 바이트만 바꿨다. 여기에 개발자들이 64개 엔티티 슬롯(0x00~0x3F) 중 카메라를 0x3D에 둔 '농담 같은' 배치가 겹치면서, 관련 바이트들이 한곳에 모여 추적이 수월해졌다.

메모리 쓰기만으로는 부족했다

2016년 말, 작성자는 전역 메모리에 값을 쓰는 것만으로 게임을 조종하려던 계획이 한계에 부딪혔음을 인정한다. 레이저 발사나 유도 미사일 같은 동작은 메모리 조작으로 흉내 내기엔 너무 복잡했고, 결국 원본 게임의 함수를 그대로 '빌려 쓰는' 방식이 필요했다. 문제는 Borland 컴파일러가 C++ 파일별로 오버레이를 나눠 플레이어의 진행 경로에 따라 코드를 다른 위치에 동적으로 적재한다는 점이었다. 형제는 스택에 CS:IP를 넣고 명령 포인터를 'Loading WING COMMANDER' 문자열 번지로 옮기는 트램펄린 기법을 고안했고, 이 시도가 레이저 캐논을 작동시키는 것을 확인했다.

가장 집요하게 괴롭힌 버그는 Borland 오버레이 로더가 스택의 BP 프레임 체인을 훑어 복귀 주소를 패치하는 동작이었다. 프레임 구조가 없는 수제 스텁은 이 과정에서 쓰레기 값을 읽어 게임이 무작위로 죽었고, 트램펄린을 Borland 함수처럼 위장하고서야 해결됐다. 2017년 3월에는 메인 루프(0560:20E3)에 예측 가능한 훅 지점을 확보했고, 8월에는 protobuf 메시지를 쓰는 단순한 TCP 클라이언트/서버 프로토콜을 작성했다. 매 프레임 각 기체의 위치와 발사·피격·소멸 이벤트를 주고받되, 각 플레이어가 자기 기체를 엔티티 0, 상대를 엔티티 1로 보도록 패킷 수신 시 슬롯을 맞바꾸는 구조였다.

이후로도 소모성 객체를 12~15번 슬롯에 가두고, 서버와 로컬의 함선 ID를 매핑하며, 64K 데이터 세그먼트를 네트워크로 통째로 복사해 이진 탐색으로 미션 승점 집계 위치(13D3:D248, C280 등)를 찾아내는 작업이 이어졌다. 2020년에는 통신 음성 텍스트 함수를 후킹해 채팅을 윙맨의 VDU 화면에 띄우는 기능까지 구현했다.

공유의 장벽을 WebRTC로 낮추다

기술적으로는 2020년에 플레이 가능한 수준에 도달했지만, 정작 친구들과 나누기가 어려웠다는 점이 흥미롭다. 오래된 게임 사본을 구하고, 특수 빌드된 DOSBox를 받고, 서로의 공인 IP를 공유하며 방화벽을 뚫어야 하는 과정은 현실적으로 너무 높은 문턱이었다. 프로젝트가 몇 년간 깃허브에서 잠들어 있던 이유다. 최근 들어 WebRTC와 emscripten 지원이 성숙하면서 작성자는 프로젝트를 되살렸고, 'lobbylink'라는 Go 기반 로비 시스템을 새로 만들었다. 이는 웹소켓 라이브러리 하나에만 의존해 방 코드로 P2P WebRTC 연결을 중개하며, coturn을 함께 돌려 TURN 자격 증명을 발급해 제약이 심한 방화벽 뒤의 플레이어도 참여하게 한다.

실무자 관점에서 이 기록은 두 가지로 읽을 만하다. 하나는 구조 정보가 전혀 없는 바이너리를 통제 실험과 차분 분석, 워치포인트, IDA 주석으로 점진적으로 해부하는 전형적인 방법론의 교본이라는 점이다. 다른 하나는 접근성 문제를 전통적인 NAT 트래버설 대신 브라우저 네이티브 WebRTC와 공용 로비 서버로 풀어낸 선택이다. 다만 작성자 스스로 밝혔듯 emscripten 빌드 스크립트 구성과 GOG 설치 패키지 처리, 음성 채팅 추가에는 LLM의 도움을 받았고, 게임 데이터 자체는 사용자가 GOG에서 정품을 받아 브라우저 저장소에 끌어다 넣어야 한다. 저작권 문제를 우회하지 않으면서도 한 세대 전 게임을 현대 웹 환경에서 되살린 접근은, 오래된 소프트웨어를 보존하고 공유하려는 이들에게 참고할 만한 사례다.

SOURCE · HACKER NEWS
원문 전체 보기 → https://fireflyk64.github.io/wcmulti/
SHARE
NEXT · CHOOSE

변화를 읽었다면,
내가 만들 수익 구조를 고릅니다.

정보를 더 모으는 데서 멈추지 않고, 광고·외주·판매·중개·구독 중 내 상황에 맞는 출발점을 정해보세요.

21가지 수익 구조 살펴보기 →
처리 중...