1P by GN⁺ | ★ favorite | 댓글 1개
  • TheZZAZZGlitch는 Game Boy Advance 충돌음을 녹음해 카트리지 안의 게임 데이터를 식별하고, 결국 같은 ROM을 복원할 수 있음을 보여줌
  • 핵심은 충돌 뒤 출력되는 오디오를 ROM 데이터로 해석하는 것이지만, 소스 형식별 조정이 많이 필요해 범용 덤프 도구로 쓰기엔 어려움
  • 4시간 넘는 녹음 중 약 1시간 50분 지점에서 특징적인 파형이 나타났고, 이후 게임의 악기음과 오디오 샘플이 순차적으로 들림
  • Python 스크립트와 정렬 보정으로 99.76% 정확도까지 도달했지만 부팅에는 실패했고, 3회 녹음을 다수결 알고리듬으로 병합하자 99.979%까지 개선됨
  • 7개 녹음 병합과 빈 공간 필터링 끝에 100% 일치를 달성했으며, 충돌음만으로 GBA ROM을 복원할 수 있다는 실험적 가능성을 확인함

충돌음에서 ROM 데이터를 읽어낸 실험

  • TheZZAZZGlitch는 GBA가 소프트웨어 충돌 후 내는 소리에 게임 데이터가 포함될 수 있음을 시연함
  • 충돌한 GBA는 카트리지 내부 데이터를 기반으로 한 소리를 계속 낼 수 있고, 특수 하드웨어와 코드로 이 오디오를 분석하면 어떤 게임인지 식별 가능함
  • 다만 이 방식은 카트리지 데이터를 쉽게 덤프하는 방법이 아니며, 바로 쓸 수 있는 해결책도 아님
    • 서로 다른 소스 형식에 맞춘 튜닝이 많이 필요함

긴 녹음에서 드러난 파형

  • GBA를 충돌시킨 뒤 4시간 이상 녹음한 결과, 약 1시간 50분 지점에서 특징적인 파형이 나타남
  • 이후 구간에서는 게임에 포함된 실제 악기음과 오디오 샘플이 순서대로 들림
  • 나머지 데이터는 13,100Hz의 8비트 데이터로 들리며, 일부 구간은 매우 이상하게 들림

Python 스크립트와 첫 복원 시도

  • TheZZAZZGlitch는 “2일간 버그를 고친 뒤” 깨끗한 GBA 충돌 덤프 녹음을 읽는 Python 스크립트를 준비함
  • ROM 데이터에는 0바이트 구간이 크게 존재하고, 이 부분은 무음처럼 나타나 오디오에서 파싱하기 어려움
  • 원본 ROM 내 위치를 기준으로 섹션을 다시 정렬하는 별도 스크립트를 실행한 뒤, 복원 ROM은 99.76% 정확도에 도달함
  • 이 ROM은 여전히 부팅되지 않았고, 알려진 ROM 데이터를 이용해 알 수 없는 데이터를 드러내는 방식이라 기술적으로 “치팅”에 해당함
    • 완전히 블라인드로 진행하더라도 적용할 수 있는 가정과 추정은 남아 있음

여러 녹음을 병합해 정확도 높이기

  • 다음 단계에서는 녹음 품질 개선에 집중함
  • 3번 녹음한 결과를 “다수결” 알고리듬으로 병합하자 정확도는 99.979% 까지 올라감
  • 이 출력 ROM은 부팅에는 성공했지만, 텍스트가 깨지고 타이틀 화면에서 크래시가 발생함
  • 이후 7개의 녹음을 결합하고 빈 공간을 필터링하자 100% 일치를 달성함

물리 하드웨어와 추가 실험

  • 영상 후반부에서는 이 방식이 물리 하드웨어에서 어떻게 동작하는지도 확인함
  • 다른 게임에서도 실험하며, 복제 카트리지 안의 ARM 코드와 관련된 미스터리도 함께 추적함
  • 더 나은 녹음을 얻는 방법도 시도됨
    • 그중 하나는 한 채널로 거칠게 믹스다운하는 “cursed adapter” 사용임

댓글과 토론

Hacker News 의견들
  • 0x00이 길게 이어질 때의 문제는 클록 복구(clock recovery) 와 관련 있음
    일부 디지털 데이터 스트림, 특히 디스크 드라이브 자기 헤드의 원시 데이터나 Ethernet 같은 고속 직렬 통신은 별도 클록 신호 없이 전송됨
    수신기는 대략적인 주파수 기준으로 클록을 만들고, 위상 고정 루프(PLL)로 데이터 스트림의 전이에 클록 위상을 맞춤
    이 방식이 동작하려면 PLL 발진기의 드리프트를 보정할 만큼 데이터 전이가 충분히 자주 나와야 하며, 전이 없이 얼마나 오래 버틸 수 있는지를 최대 연속 동일 숫자(CID) 사양으로 부름
    https://en.wikipedia.org/wiki/Clock_recovery

    • 예전에는 8b/10b처럼 짧은 비트 구간을 세심하게 다루는 영리한 코드북 방식으로 클록 복구 가능성을 보장하고 선로 정전용량 문제를 피했던 점이 좋았음
      이후에는 64/66b처럼 큰 비트 덩어리에 짧은 헤더를 붙여 클록 전이를 보장하고, 전체를 의사난수 스크램블러에 통과시키는 방식으로 넘어감
    • 다른 걱정은 파형 어딘가가 교류 결합(AC coupling) 되어 직류가 통과하지 못하는 경우임
      클록이 완벽히 동기화돼 있어도, 긴 구간에서는 거의 전부 1인 신호와 거의 전부 0인 신호가 결국 같아져 버림
    • 이 경우에는 별로 관련 없어 보임
      오디오는 아날로그이고, 비트스트림으로 디코드하려면 DAC가 필요하며, 특별한 동기화 없이 44.1kHz나 48kHz 같은 고정 주파수로 전송됨
    • 이 페이지에서 Wireless Set Number 10이라는 아주 흥미로운 글을 찾았음
      https://en.wikipedia.org/wiki/Wireless_Set_Number_10
  • 거의 20년 전 4세대 iPod 펌웨어를 피에조 스피커로 덤프했던 원래 iPodLinux 해킹이 떠오름
    https://web.archive.org/web/20140810083116/http://www.newscientist.com/article/dn7085
    우연히도 그 덕분에 iPod에서 GBA 게임도 돌릴 수 있었지만, 클릭 휠로 Doom을 하고 흑백 영상을 보는 것만으로도 충분히 만족스러웠음

    • 좋은 추억임
      아직 iPod Classic을 갖고 있고, 배터리를 업그레이드한 뒤 256GB MicroSD 카드 4장을 넣었음
      최근 Bluetooth를 추가하는 개조도 봤지만 뒷면 케이스를 교체해야 해서 거기까지는 안 갈 듯함
      디자인에도, 음악 파일의 복사본을 직접 소유한다는 점에도 시간이 지나도 바래지 않는 느낌이 있음
  • 여기서 더 주목받게 되어 반가움
    며칠 전에도 올라왔지만 묻혔음: https://news.ycombinator.com/item?id=39037104
    원본 영상에는 이 짧은 글에 없는 내용이 많고, 해커가 DS에서 적절한 오디오 품질을 얻기 위해 직접 잘라 붙여 만든 맞춤 어댑터도 포함됨

  • Zzazz는 매년 만우절 대회/이벤트를 열고, 보통 어느 정도의 레트로 해킹이나 역공학이 들어감
    참여를 추천함
    지난 대회들은 GitHub에 있음

  • Nintendo의 오디오 아키텍처는 늘 흥미로웠음
    원래 NES에는 임의 파형을 만들 수 있는 샘플 생성기가 있었고 두 가지 방식으로 구동할 수 있었음
    하나는 메모리 주소를 넘기면 비트를 읽어 아주 단순한 파형으로 처리하는 방식인데, 1은 “값을 하나 올림”, 0은 “값을 하나 내림”이라서 평평한 파형을 만들려면 10101010처럼 반복해야 했음
    다른 하나는 CPU에서 “초기값”을 계속 직접 넣어 칩을 직접 구동하는 방식인데, 실제로는 오디오 드라이버가 RAM에서 비트를 읽는 것보다 빨랐음
    문제는 이 방식이 CPU 사이클을 전부 잡아먹어서 다른 일을 하지 않을 때만 쓸 수 있었다는 것임
    Battletoads 같은 게임은 이를 활용해 액션이 멈춘 동안 더 높은 음질의 드럼 히트를 재생했고, 타이틀 화면, 적에게 마지막 타격을 줄 때 잠깐 모든 액션이 멈추는 “바삭한” 효과, 기억에 남는 일시정지 음악에 썼음
    게임이 직접 구동 모드와 칩이 샘플을 읽는 모드를 전환하는 데모가 여기 있음. Retro Game Audio가 에뮬레이터로 수정한 영상을 올려 직접 구동 서브루틴에 들어간 순간을 보여줌: https://www.youtube.com/watch?v=JGT0FM3yh-w

  • 애초에 왜 이런 일이 생기는지 궁금함
    이런 게임들이 상태를 오디오로 덤프하는 일이 흔한가? 게임 개발자를 위한 의도적인 디버깅 도구인가?

    • 작성자의 이전 영상[1]이 이 동작의 기술적 세부사항을 설명함
      기본적으로 GBA 사운드는 RAM의 버퍼에서 오디오를 스트리밍하고, 인터럽트가 하드웨어에 버퍼 처음부터 다시 읽으라고 알려야 함
      하지만 게임이 크래시한 경우처럼 인터럽트가 발생하지 않으면 오디오 스트림이 버퍼를 넘어 메모리의 다른 영역을 읽게 됨
      [1] https://www.youtube.com/watch?v=wSWNkpqjtQY&t=361s
    • 꽤 드문 일이고, 의도적인 디버깅 도구도 아님
      이론적으로 GBA는 게임이 크래시했을 때 아키텍처를 “정지”시키거나, 주기적으로 실행돼야 하는 상태 갱신을 마스크 불가능 인터럽트에 묶어 그 갱신이 멈추면 재부팅하는 워치독을 둘 수도 있었음
      하지만 그런 기능은 비용이 더 들기 때문에 GBA에는 없음
      Nintendo는 오래된 게임 카트리지 제조사들의 전통적 접근, 즉 “우리 게임에 버그가 없으면 정의되지 않은 하드웨어 상태의 동작을 걱정할 필요도 없다”를 택한 셈임
      그래서 GBA 게임이 인터럽트가 비활성화된 무한 루프 같은 크래시 상태에 빠지면 오디오 칩은 시스템이 크래시한 줄 모르고 RAM의 연속 비트를 읽어 소리로 바꾸는 단순한 일을 계속함
      정상 동작 중이라면 읽기 작업을 관리하던 정리 루틴이 사라지면서 계속 읽다가 결국 카트리지 ROM의 값을 나타내는 비트까지 도달함
  • 정말 말도 안 되게 인상적임
    여기서 쓰인 다수결 알고리즘 같은 기법들은 여러 산업에서 충분히 활용되지 못하고 있을 것 같음

    • 관심 있다면 정교한 잡음 신호 복원 기법은 이제 거의 100년 가까이 축적돼 있음
      자기 저장 매체는 기본적으로 이 해킹과 같은 원리로 동작함
      https://en.wikipedia.org/wiki/Partial-response_maximum-likelihood
      여기에도 같은 발상을 적용할 수 있는데, GBA ROM 내용은 강한 편향을 가질 것이기 때문임
      다수결은 많은 정보를 낭비함
    • 다수로 나온 값을 택하거나 더 일반적으로 중앙값을 택하는 흥미로운 응용으로, 같은 시점에서 찍은 여러 사진의 노이즈나 사람을 제거하는 방법이 있음
      모든 사진을 겹친 뒤 각 픽셀마다 중앙값만 남기면 됨[1]
      [1]: https://patdavid.net/2013/05/noise-removal-in-photos-with-median_6/
    • 데이터 복구에서는 꽤 흔함
      디스크 이미지를 계속 읽고 정족수 판단을 돌리다가 체크섬을 통과하는 결과가 나오면 제대로 동작하는지 보는 식임
      파일 서명처럼 더 높은 수준의 체크섬이 있으면 추가 검증에 더 좋음
      일부 항공우주 응용에서도 쓰임
    • 필름 스캔, 특히 4K77 같은 팬 프로젝트에서 쓸 수 있지 않을까 생각했음
      pristine한 마스터가 아니라 손상됐을 수 있는 극장 상영 프린트를 다루기 때문에, 여러 벌을 이용해 스크래치 등을 제거할 수 있다면 후반 수작업 수정 시간을 엄청나게 줄일 수 있을 것임
  • 0xFF가 0x00으로 바뀌는 건 직류 차단 커패시터나 고역 통과 필터링 때문일 수 있음
    오디오 회로는 비가청 콘텐츠에 별로 적합하지 않음
    운이 좋다면 칩의 오디오 출력에 디지털 오실로스코프를 직접 연결하면 캡처 정확도가 더 좋아질 수 있겠지만, 그래도 부팅 가능한 이미지를 얻어낸 건 꽤 인상적임

    • YouTube 영상 댓글에서 읽은 기억으로는, 가능한 한 기본 장비만으로 해보는 것이 목적이었음
      그래서 제대로 된 데이터 로깅 오실로스코프 대신 여러 번 반복 캡처해 오류를 평균화하는 데 몇 시간을 쓴 것임
    • 맞음, 직류 바이어스가 없는 신호를 만들어야 함
      Manchester 부호화처럼 단순한 방식만 써도 큰 도움이 됨
      그걸로 충분하지 않다면 NRZ나 심지어 합성곱 부호화도 가능함
      또한 사인파를 보내거나, 그럴 수 없다면 적어도 구형파 주파수를 충분히 높여 교류 결합 커패시터에 먹히지 않게 해야 함
  • 이 모든 것에서 가장 인상적인 부분은, 개인적으로 불법 복제업자들이 ROM+휘발성 저장 메모리 대신 쓰기 가능한 플래시에서 게임을 실행하도록 코드를 수정한 방식

    • 불법 복제 Game Boy와 Game Boy Advance 게임에서 배터리 비용 몇 센트를 아끼려고 쓰는 매우 흔한 기법임
      사실 이런 패치를 만드는 것도 그렇게 어렵지 않음
      불법 복제업자들은 게임 코드가 저장하는 위치를 약간 역공학해, 게임별 패치를 작성해 저장 내용을 쓰기 가능한 플래시에 플러시함
      다만 공식 GBA 게임은 항상 Nintendo SDK의 함수를 사용해 저장하므로, 그 함수들을 후킹하면 배터리 없는 복제 카트리지에서도 아무 GBA 게임이나 저장할 수 있게 만드는 범용 패치가 꽤 간단해짐
      이를 수행하는 패처를 작성했고 여기서 볼 수 있음
      https://github.com/metroid-maniac/gba-auto-batteryless-patcher
  • TheZZAZZGlitch의 에뮬레이터가 게임이 잘못된 주소로 점프하려 한다고 보고할 때 내부에서 무슨 일이 일어나는지 아는 사람이 있나?
    GameBoy Advance에 쓰인 ARM7 프로세서에 익숙하지 않지만, 잘못된 값으로 점프 호출을 구성하는 게 어떻게 가능한지 상상이 잘 안 됨
    또 TheZZAZZGlitch가 잘못 복원한 ROM 중 하나를 실제 GameBoy에서 실행하면 어떻게 될지도 궁금함

    • bx 명령어를 쓰면 레지스터에 저장된 임의의 주소로 점프할 수 있음
      그리고 잘못 복원된 ROM을 실제 GameBoy에서 실행하면 크래시하고, 결국 ROM을 스피커로 재생하기 시작할 것임
      그게 영상의 핵심임 :)
    • 에뮬레이터가 GBA 메모리 맵의 유효한 영역 접근만 에뮬레이션하고, 유효하지 않은 영역이 접근되면 그 오류를 던지는 것일 가능성이 큼
      실제 하드웨어에서는 어떻게 될지… 누가 알겠음 :)