1P by GN⁺ 11시간전 | ★ favorite | 댓글 1개
  • 13KiB 크기의 단일 파일로 Windows, Linux, 브라우저에서 모두 실행되는 Snake 게임으로, 세 플랫폼을 하나의 소스에서 지원
  • 뱀을 조작해 먹이를 먹고 벽에 부딪히지 않도록 하는 고전적인 Snake 규칙을 따르며, 점수·레벨·미로 구조가 포함됨
  • 각 플랫폼별로 C(WinAPI/X11)JavaScript(HTML5 Canvas) 로 구현되었으며, 각각 3~5KiB 수준으로 압축·병합됨
  • Windows는 비정상적인 PE 헤더와 apphelp 메커니즘, Linux는 lzma 압축 및 셸 드로퍼, 브라우저는 HTML/CSS 트릭을 이용해 실행
  • 세 구현을 결합한 결과 13,312바이트의 단일 실행 파일이 완성되어, 멀티플랫폼 실행 파일 구조의 실험적 가능성을 보여줌

Cosmopolitan libc에서 착안한 멀티플랫폼 시도

  • Cosmopolitan libc는 C 소스 코드를 여러 운영체제에서 실행 가능한 단일 바이너리로 컴파일할 수 있는 툴킷
    • Windows, Linux, BSD 등 다양한 OS에서 네이티브 실행 지원
  • GUI 미지원과 큰 바이너리 크기 한계로 인해, 저자는 16KiB 이하의 비디오 게임을 직접 제작하는 도전을 선택
    • 목표는 Windows, Linux, 브라우저에서 모두 실행되는 단일 소스 기반 게임 제작

게임 구조와 규칙

  • 게임은 표준 Snake 게임으로, 방향키 또는 WASD로 조작
    • ESC로 종료, R로 리셋, P로 일시정지, 스페이스바로 시작
  • 먹이를 먹을 때마다 점수가 증가하며, 일반 먹이는 10점, 노란색 먹이(15% 확률) 는 20점
    • 먹이는 일정 시간 후 사라지며, 사라지는 시간은 뱀의 속도(길이에 비례)에 따라 결정
  • 10개의 먹이를 먹으면 다음 레벨로 이동, 벽 배치가 무작위로 변경
    • 항상 먹이까지의 경로가 존재하도록 미로 생성
    • 뱀의 초기 위치도 무작위지만, 최소 5칸의 여유 공간이 확보된 방향으로 배치
  • 완성된 게임 파일 크기는 13,772바이트

세 플랫폼별 구현 방식

  • Windows 버전은 WinAPI 기반 C 코드로 작성되어, 압축 스크립트와 디컴프레서 스텁을 포함
    • PE 헤더의 MZ 시그니처 이후 자유롭게 제어 가능한 바이트를 활용해 셸 스크립트를 삽입
    • 이로 인해 파일이 Windows 실행 파일이면서 동시에 Linux 셸 스크립트로도 유효
    • 첫 실행 시 “The application was unable to start correctly (0xc0000005)” 오류가 발생할 수 있으나, 재실행 시 정상 동작
  • Linux 버전lzma 압축을 사용하고, 작은 셸 드로퍼가 압축된 ELF64 바이너리를 추출·실행
    • 파일의 앞뒤 일부를 건너뛰며 실행되도록 구성
  • HTML 버전은 브라우저가 파일의 불필요한 앞부분을 무시하고 HTML을 처리하는 특성을 이용
    • CSS를 통해 불필요한 데이터가 화면에 보이지 않도록 처리

단일 파일 결합 및 구조

  • 세 플랫폼용 파일을 특정 순서로 연결(concatenate) 하여, 각 환경이 자신에게 맞는 부분만 실행하도록 구성
    • Windows는 PE 섹션, Linux는 ELF 섹션, 브라우저는 HTML 섹션을 인식
  • 최종 파일 크기는 13,312바이트로, 세 환경에서 모두 실행 가능한 폴리글롯 바이너리 완성
  • 파일 내부에는 Windows PE 헤더, Linux용 LZMA 압축 코드, HTML/CSS/JavaScript 코드가 순차적으로 포함됨
    • 예시 코드 블록에는 MZ 시그니처, ks 마커, <html> 태그, <script> 블록 등이 순서대로 존재

기술적 의의

  • 단일 파일로 Windows, Linux, 브라우저를 모두 지원하는 실행 구조를 구현
  • PE, ELF, HTML 포맷의 중첩 활용을 통해 플랫폼별 실행 경로를 분기
  • 13KiB라는 극도로 작은 크기에서 압축, 포맷 해킹, 멀티플랫폼 실행을 결합한 실험적 성취
Hacker News 의견들
  • 리눅스 실행 파일을 추출했는데, readelfobjdump가 제대로 읽지 못해서 놀랐음
    조사해보니 PT_DYNAMIC 헤더의 비사용 필드에 동적 링커 이름을 억지로 넣어 공간을 절약한 구조였음

    1. 이건 수동으로 한 건지, 아니면 이런 식으로 처리하는 툴이 있는지 궁금함
    2. 이런 비정상적인 바이너리를 분석할 수 있는 툴이 있는지도 알고 싶음
    • ndisasm이나 헥스 에디터로 읽을 수 있음
      하지만 이런 포맷을 일부러 망가뜨리는 건 무의미한 절약이라 생각함
      안티바이러스나 DEP 같은 보안 기능과 충돌할 수도 있어서 이런 실행 파일은 건드리고 싶지 않음
    • “choke”가 무슨 의미인지 모르겠음, 내 환경에서는 두 툴 모두 정상 작동했음
  • 원본 젤다(Zelda) 게임의 파일 크기가 너무 작아서 놀라움
    그렇게 적은 코드와 데이터로 얼마나 큰 감동과 몰입감을 만들어냈는지 경이로움
    The Legend of Zelda (Wikipedia)

    • 진짜 마법 같음. Commodore 64Eindeloos라는 게임도 64KB 안에 거대한 맵을 담았음
      40년 만에 맵을 추출했는데 PNG로만 800KB가 넘음
      게임 맵 보기
    • Zelda 1은 128KB였고, 압축도 없었음. 속편은 그 두 배 정도였음
    • 던전과 동굴이 사실 하나의 직사각형 맵 안에 모두 들어 있었음
      디자이너들이 공간 제약 안에서 퍼즐처럼 구성했음
      Zelda 맵 구조 참고
  • 내 테스트 결과

    • 브라우저: 확장자를 .html로 바꾸면 실행됨
    • 리눅스: lzma 명령이 없다는 오류가 나서 xz 패키지를 설치하니 작동함
    • 윈도우: .com이나 .exe로 실행 시 오류(0xc0000005)가 났는데, DEP 설정을 해제하니 실행됨
    • Windows 11에서도 정상 작동함
    • 단순히 chmod +x snake.com 후 실행하면 Mono가 시도되며 실패함
      대신 bash snake.com으로 실행하면 잘 됨. Debian 13 기준임
  • 흥미로운 점은 이 파일이 세 개의 실행 파일이 하나로 합쳐진 형태라는 것임
    그래서 각 플랫폼에서 완전히 다른 프로그램을 담을 수도 있음

  • kkrieger라는 96KB짜리 FPS 게임이 떠오름
    당시 그래픽 수준이 놀라웠음
    kkrieger (archive)

    • 관련 토론: 2017, 2023, 2024
    • 지금도 최신 PC에서 실행 가능함. 직접 다운로드해서 돌려봄
    • 최근 Metroid Prime 4를 하면서 이런 아이디어로 현대 게임을 만든다면 어떨까 생각했음
  • 맥에서 브라우저 외에 실행할 방법이 있는지 궁금함
    cannot execute binary file 오류가 발생함

  • 이런 메커니즘을 발전시켜 진짜 범용 실행 파일(universal binary) 을 만들 수 있을지 궁금함
    예를 들어 Haxe로 코드를 작성해 C++로 컴파일하면 Win32와 Linux용을 만들고,
    JavaScript로 변환해 HTML에서도 실행 가능하게 한 뒤,
    세 결과물을 하나의 파일로 합치는 식으로 구현할 수 있을 것 같음

  • 하나의 파일로 어디서든 실행 가능한 단일 실행 앱 개념이 마음에 듦
    나도 서버리스 플랫폼을 만들며 이런 방향을 연구 중임
    단 하나의 .html 파일로 데이터 기반 앱을 만들고, web-components를 원격에서 불러오는 구조임
    file:// 프로토콜로 HTML을 직접 여는 기능이 강력한데, 종종 간과됨

    • 원문 작성자는 실제로 세 번 구현했음 — WinAPI 기반 C, X11 기반 C, 그리고 HTML5 Canvas 기반 JS 버전
      즉, 단순히 브라우저 인스턴스를 띄운 게 아니라 완전한 네이티브 앱 두 개를 만든 셈임
    • 아쉽게도 HTTPS가 아닌 환경에서는 브라우저 기능 제약이 많음
    • 단일 HTML 앱 개발 방식을 더 알고 싶음. 혹시 공개된 예제가 있는지 궁금함
  • Polyglot 파일이 이렇게 늦게 등장한 게 신기함
    기술적으로는 10~20년 전에도 가능했을 것 같음

    • 최초의 polyglot 파일이 언제 등장했는지 궁금함
      EICAR.COM이 텍스트와 실행 파일을 겸한 초창기 예시로 떠오름
  • js13kGames 같은 초소형 웹게임 대회가 생각남