1998년 Ultima Online 데모 서버 역공학
6 days ago
10
- OUO는 1998년 Ultima Online 데모 서버를 완전히 리버스 엔지니어링한 프로젝트로, MSVC x86 바이너리의 약 5,000개 함수를 디스어셈블해 휴대 가능한 C99로 옮김
- UoDemo.exe는 Ultima Online: The Second Age 첫 릴리스에 포함된 독립 실행형 데모였고, 클라이언트와 Windows로 포팅된 전체 서버 코드·데이터를 함께 담고 있었음
- 각 함수는 원본 바이너리와 명령어 단위로 비교됐으며, 클래스 계층과 vtable 레이아웃을 맞춘 뒤 원본과 같은 제어 흐름·구조체 레이아웃·분기를 유지하도록 수동 변환됨
- 복원본은 1998년 중반 실제 라이브 Ultima Online 서버 코드에 가깝지만, 충돌·오버플로·초기화되지 않은 변수 같은 안정성 문제와 스킬 상승·스폰 밀도 같은 게임플레이 문제가 태그와 함께 수정돼 있음
- 원래 데모는 클라이언트 1.25.33만 지원했지만, 복원본은 1.25.30부터 5.0.9.1까지의 클라이언트를 암호화 유무와 관계없이 지원하며, 1997~2003년 서버 데이터 파일도 요청 중
데모 파일의 출처와 범위
- 각 함수는 원본 바이너리와 명령어 단위로 비교됐으며, 10년에 걸친 간헐적 작업 끝에 최근 LLM 발전으로 마무리할 수 있었음
- UoDemo.exe의 날짜는 1998-09-02이며, 서버 데이터는 1998년 6월 2일 운영 서버에서 추출된 것이었음
- 데모용으로 일부 기능이 스텁 처리되고 플레이 가능한 지도는 Ocllo 섬으로 줄었지만, 나머지는 1998년 중반 실제 라이브 Ultima Online에서 돌던 운영 서버 코드였음
- Ultima Online은 Origin Systems Inc.가 개발한 1997년 MMORPG였고, 상업적으로 성공한 초기 MMORPG 중 하나였음
- Windows에서 클라이언트가 실행됐고, 서버인 “shards”는 여러 Solaris 머신에서 돌아갔으며 지도는 지역별로 나뉨
- 데모는 Ocllo 섬에서 드래곤을 죽이는 간단한 퀘스트를 제공했고, 대화, 거래, 전투 등 기본 게임 메커니즘을 둘러볼 수 있게 구성됨
- 여러 UO 서버 에뮬레이터가 이 데모의 일부를 재사용했지만, 지금까지 완전히 역공학한 경우는 없었음
- UoDemo.exe는 Microsoft Visual C++ 5.0, 즉 Visual Studio 97로 컴파일됐고, C++98 이전 방언의 C++를 대상으로 했음
역공학 방법
-
디스어셈블과 심볼 추정
- 디스어셈블에는 radare2를 사용함
- 심볼 이름은 C++ 심볼이 포함된 실험적 Linux 포트 UO 클라이언트 1.25.37에서 유추함
-
C99 수동 변환
- 각 함수는 원본 바이너리와 같은 제어 흐름, 구조체 레이아웃, 분기를 유지하도록 손으로 C99로 번역됨
- 차이가 있는 부분은 데모의 실제 버그 수정 또는 플랫폼 적응이며, 소스에 표시돼 있음
-
검증 방식
- C 빌드를 다시 r2로 디스어셈블해 원본과 비교함
- 두 결과가 일치할 때만 함수가 완료된 것으로 표시됨
- 헬퍼 함수는 반복되는 인라인 패턴에만 쓰였고, 헬퍼가 인라인 버전과 같은 코드로 다시 확장될 때만 사용됨
-
클래스 계층 복원
- 초기에 가장 중요했던 작업은 클래스 계층을 정확히 맞추는 것이었음
- 핵심 계층은 CEntity (0x10) -> CResourceEntity (0x1C) -> CItem (0x50) -> CContainer (0x5C) -> CMobile (0x37C) -> CPlayer (0x458)였음
- 가상 디스패치는 vtable 슬롯을 통해 이뤄졌고, 예를 들어 vtable[0x18]은 IsPlayer, [0xD0]은 IsMobile, [0xE4]는 IsNPC였음
- 이 레이아웃이 확정된 뒤에는 바이너리 대부분을 비교적 직접적으로 번역할 수 있었음
복원 결과와 원본과의 차이
- 결과물은 1998년 Ultima Online 서버의 거의 완벽한 복제에 가깝지만, 일부 차이가 있음
- 원본 코드 대비 충돌, 오버플로, 초기화되지 않은 변수 같은 안정성 문제가 수정됨
- 스킬 상승, fame/notoriety 방향, 스폰 밀도 같은 게임플레이 문제도 고쳐짐
- 각 수정은 소스에 태그가 붙어 있어, UoDemo.exe와 비교하는 사람이 무엇이 왜 바뀌었는지 정확히 확인할 수 있음
- 스폰 시스템과 decay 시스템 같은 일부 기능은 깨져 있었고, 데모 릴리스를 위해 부분적으로 비활성화되거나 스텁 처리됐을 가능성이 있음
- 해당 기능들의 코드는 남아 있었지만 라이브 호출 지점이 도달하지 않았고, 따로 디컴파일한 뒤 디스패치를 다시 연결하는 것만으로 동작시킬 수 있었음
- 게임 지도는 Ocllo 섬만 담는 등 일부 데이터가 빠져 있었음
- 서버 데이터 포맷을 조작하는 전체 도구 모음을 만들었고, 나머지 세계의 문, 표지판, 장식, 텔레포터, 함정, 상자, 스폰 위치를 완전히 재구성함
남아 있던 생태계 시스템
- 은퇴한 유명한 ecology system은 함수 호출이 끊긴 상태였지만 코드 안에 여전히 남아 있었음
- 포식자, 먹이, 청소동물 시스템을 다시 연결해 늑대가 토끼를 쫓거나 까마귀가 아이템을 먹는 모습을 볼 수 있게 됨
- 다만 정확한 데이터가 부족해 전체 자원·생산 시스템까지 구현하지는 않음
- 관련 배경 자료로 Raph Koster의 UO ecology system 및 UO 자원 시스템 글 1, 2, 3가 연결돼 있음
추가 기능과 클라이언트 호환성
- OSI가 1999년 2월 추가한 Meditation, Stealth, Remove Trap 스킬이 새로 들어감
- 이 기능들의 일부 초기 흔적은 이미 코드에 남아 있었음
- 대부분의 새 기능은 시작 시 -features 매개변수로 켜거나 끌 수 있음
- 데모 서버에는 계정 시스템이 완전히 없었기 때문에, 원 개발자들이 구현했을 방식을 추정해 약간 현대화된 형태로 다시 구현함
- 원래 데모 서버는 클라이언트 1.25.33만 지원했지만, 1.25.30부터 5.0.9.1, 즉 2007-03-27까지의 모든 클라이언트를 암호화 유무와 관계없이 지원하도록 확장됨
- 여러 해 동안 완전히 다른 암호화 방식이 다섯 가지 있었기 때문에, 각 방식을 클라이언트 바이너리에서 역공학해야 했음
32비트 원본과 64비트 기본 빌드
- 원본 바이너리는 32비트였지만, 현재 기본 빌드는 64비트를 대상으로 함
- 클래스 계층은 C 구조체 임베딩으로 원래 C++ 상속을 재현함
- 이 방식 덕분에 CMobile*을 CContainer*가 필요한 곳에 전달할 수 있음
- 64비트에서 포인터 폭이 넓어지면 상속된 필드 위치가 밀릴 수 있기 때문에, 일부 구조체는 32비트와 64비트 모두에서 상속 및 vtable 레이아웃이 바이너리와 맞도록 의도적으로 패딩됨
공개 리소스
Ultima Online 커뮤니티에 대한 요청
- 1997~2003년 무렵 원래 Ultima Online 서버의 dynamic0.mul, dynamic0.bkp, regions.txt, resbank.mul 파일을 가진 사람이 있다면 전달을 요청함
- dynamic0.mul과 dynamic0.bkp는 서버 저장 파일이고, regions.txt는 스폰 정의, resbank.mul은 자원 정의 파일임
- 원본 dynamic0.mul이나 dynamic0.bkp가 완전히 사라졌을 가능성은 낮아 보임
- dynamic0.mul 파일에서 플레이어 데이터를 제거해 개인정보를 보존한 뒤 배포할 수 있는 도구는 이미 갖춰져 있음
- 이 파일들은 Ultima Online 세계 콘텐츠를 매우 정확하게 재현하는 데 큰 가치가 있음
-
Homepage
-
Tech blog
- 1998년 Ultima Online 데모 서버 역공학