
죽은 USB 프로토콜 재구성: 핫 나이프로 잠금 해제된 핸드헬드의 비밀, 잊혀진 USB 인터페이스를 부활시키는 다학제적 여정
2024년, bjiru가 ME2 휴대용 기기에 관한 영상을 업로드했습니다. 2008년경에 생산된 이 장난감은 USB를 통해 기기와 온라인 세계 간에 포인트와 젬을 동기화하는 기능을 제공했습니다. 이 게임은 매우 한정적이어서 소프트웨어, 드라이버, 에셋이 전혀 보관되지 않았으며, 적어도 bjiru가 온라인 게임 클라이언트를 찾아내기 전까지는 그랬습니다.
저는 Miuchiz Reborn의 책임자입니다. 이 프로젝트는 2015년에 시작되어, USB로 연결된 온라인 부분과 휴대용 부분이 있는 비슷한 게임을 보존, 리버스 엔지니어링, 에뮬레이션, 그리고 접근성을 유지하기 위한 노력입니다. 비슷한 연도와 게임 유형 덕분에, ME2는 이미 2018년에 Miuchiz 커뮤니티를 통해 제 주의를 끌었습니다. 그들은 (잘못 생각하여) 아키텍처가 유사할 수 있다고 생각했습니다. 수년간 이 기기의 존재를 알고 있었지만, bjiru의 영상이 마침내 제가 이 기기에 대한 연구를 시작하게 만들었습니다.
초기 노력은 전적으로 bjiru가 가진 컴퓨터 게임 사본을 다시 작동시키기 위해 필요한 서버를 재현하는 데 집중되었습니다. 하지만 그 과정에서 자연스럽게 휴대용 기기로 관심이 옮겨갔습니다. 온라인 게임의 재현은 기기와 포인트를 동기화하는 메커니즘 없이는 결코 완성될 수 없을 것입니다. 결국, 컴퓨터와 ME2 기기 간의 이 통신이 게임의 주요 특징이었습니다. 저는 Miuchiz 휴대용 기기에 대한 이전 경험이 그들이 기대하는 통신 의례를 푸는 데 도움이 될 것이라고 생각했습니다. 제가 리버스 엔지니어링할 코드를 얻을 수만 있다면 말이죠.
제 호기심은 ME2의 희생을 요구했습니다. 이베이는 법정화폐의 희생을 요구했습니다. 곧, 이 표본들이 제 앞에 놓였습니다.

이것들은 버튼 몇 개와 암컷 미니 USB 포트만 있는 작은 장치입니다. 상자에 케이블이 포함되어 있지만 소프트웨어나 드라이버 디스크는 없습니다. 그 USB 포트는 컴퓨터와 휴대용 기기 간에 포인트를 동기화하는 방법이 될 것입니다. 하지만 Miuchiz 휴대용 기기에 대해 같은 여정을 시작했을 때, 저는 그 Windows 소프트웨어가 어떻게 작동하는지 리버스 엔지니어링하여 플래시 메모리에 대한 완전한 접근 권한을 얻었습니다. ME2에는 그러한 소프트웨어가 없으므로, 기기와 통신하는 방법을 알아내기 위해 리버스 엔지니어링할 것이 없습니다. Wayback Machine과 bjiru를 확인한 후에도, 이 기기와 통신하는 데 사용된 소프트웨어의 사본은 남아 있지 않은 것으로 보입니다. 제 생각에는 ME2 Desktop Buddy라고 불렸던 것 같지만, 그 애플리케이션은 bjiru가 복구한 게임 클라이언트와는 별개였습니다. 휴대용 기기는 이동식 저장 장치로 노출되지만, 내용물은 단지 ME2 게임을 다운로드하라는 온라인 링크로 연결되며, 이는 더 이상 사용할 수 없습니다.
앞으로 나아갈 길은 명확합니다. 선택지는 하나뿐입니다: 하드웨어를 열어보는 것입니다.

ME2의 주요 펌웨어는 SST39VF3201, 2메가워드 (4메가바이트, 16비트 주소 단위) 플래시 칩에 저장되어 있습니다. 메인 마이크로컨트롤러는... 단단한 에폭시 글로브탑 아래에 있습니다. 이것을 칩-온-보드(CoB)라고 하며 일반적으로 비용 절감을 위한 조치이지만, 내부 집적 회로에 대한 식별 정보를 숨기는 부작용이 있습니다. 일반적으로 패키징된 칩에는 플래시 칩처럼 식별 표시가 있습니다. 이러한 기기에 사용되는 마이크로컨트롤러에는 종종 내부 ROM이 포함되어 있기 때문에, 제가 리버스 엔지니어링하고자 했던 USB 코드의 일부 또는 전체가 그 ROM에 있을 가능성이 있습니다. 코드가 ROM에 있으면 벽돌이 된 기기를 복구하거나, 제조사가 선택한다면 조립 후에 기기를 플래싱할 수 있다는 이점이 있습니다. 그 ROM은 제가 식별할 방법이 없는 칩 안에 존재할 것입니다.
플래시 칩에서 데이터를 검색하는 것은 간단하고 잘 문서화된 과정입니다. 칩을 납땜 제거하고, XGecu 같은 일반적인 플래시 프로그래머에 넣은 다음 내용을 덤프합니다. 마이크로컨트롤러의 ROM에서도 정보가 필요하다면, 그것은 덜 간단하지만, 보호 기능이 없을 가능성이 높은 이와 같은 기기에서는 여전히 가능합니다. 과거에 저는 Tamagotchi Pix의 SPI 플래시에 코드를 추가하여 부트 ROM을 플래시 칩의 여유 공간에 복사한 후, 코드를 주입하는 데 사용한 동일한 플래시 프로그래머로 읽을 수 있도록 했습니다. 그러나 그 경우 마이크로컨트롤러는 적절히 패키징되어 있고 모델 정보가 인쇄되어 있었기 때문에 데이터시트를 찾아 어떤 명령어 세트를 사용하는지, ROM이 메모리 공간의 어디에 있는지 알 수 있었습니다. 이 시점에서 ME2의 수수께끼 같은 칩-온-보드에 대한 그러한 정보는 전혀 없었습니다.
불확실성에도 불구하고, 여기서 앞으로 나아갈 유일한 방법은 플래시 칩을 납땜 제거하는 것입니다. 또한 플래시 칩용 소켓 몇 개를 구매하여 휴대용 기기의 PCB에 납땜할 수 있기를 바랐습니다. 이렇게 하면 ME2를 다시 프로그래밍할 수 있고, 마이크로컨트롤러의 내부 ROM을 덤프하기 위한 코드를 작성해야 할 경우 빠르게 반복할 수 있었습니다.
불행히도, 저는 칩을 손상시키지 않고 납땜 인두로 플래시 칩을 떼어낼 수 없었습니다. 여러 번 실패한 후 이 기술 문제를 해결하기 위해, 대신 리워크 스테이션(실제로 500°C에 도달한다고 주장하는 열풍기)을 구입하고 뜨거운 공기로 납을 녹여 칩을 제거했습니다. 이를 통해 플래시 내용을 문제없이 덤프할 수 있었지만, 구입한 소켓을 실제로 사용하는 것이 제 능력을 넘어설 것임을 알게 되었습니다. 작은 핀 48개를 모두 PCB에 납땜해야 할 뿐만 아니라, 소켓의 플라스틱이 녹지 않도록 충분히 빠르게 작업해야 했습니다. 이를 처리할 도구나 기술이 없었기 때문에, ROM이 필요하다면 다른 전략이 필요했습니다.
덤프는 좋아 보였습니다. 그리고 제가 이미 펌웨어 덤프에서 압축되지 않은 비트맵을 찾기 위해 특별히 구축한 도구를 사용하여, 기기에 일반적으로 표시되는 이미지를 찾을 수 있었습니다:

플래시 칩에서 펌웨어 덤프를 얻었지만, 본격적인 리버스 엔지니어링을 하기 전에 적어도 기기가 어떤 명령어 세트를 사용하는지 알아야 합니다. 하드웨어 자체에 표시가 없었으므로, 추측해야 했습니다. Ghidra에서 코드를 분석해 보았습니다. Ghidra는 오픈 소스 디스어셈블러, 디컴파일러, 그리고 저를 계속 고용하게 만드는 지저분한 악몽 같은 도구입니다. 제공된 거의 모든 종류의 프로세서 사양으로 시도했습니다. ARM 변종? 6502 계열? MIPS? 문자 그대로 Ghidra가 지원하는 다른 모든 것? 모두 "아니요"였습니다.
모든 것을 시도했지만 어떤 것도 이 코드를 디스어셈블하지 못했습니다. 이것이 코드라는 것은 알 수 있었습니다. 왜냐하면 제가 찾고 있던 코드의 일부를 찾을 수 있었기 때문입니다!

Miuchiz 휴대용 기기에 대한 과거 작업 덕분에 USB 대용량 저장 장치가 어떻게 작동하는지 어느 정도 알고 있었습니다. 이 스니펫은 거의 확실히 어떤 곳에 'U', 'S', 'B', 'S'를 이동시키는 것으로, 이는 제가 찾고 있던 USB 대용량 저장 통신의 특정 시그니처입니다. 이 기기와 상호 작용하는 방법을 알아내기 위해 리버스 엔지니어링해야 할 USB 코드의 일부 또는 전체가 분명히 이 플래시 덤프에 있었지만, 어떤 명령어 세트로 작성되었는지 전혀 몰랐기 때문에 디스어셈블할 수 없었습니다.
이 시점에서 저는 몇 개의 고장 난 ME2 장치를 가지고 있었습니다. 바보같이 들리겠지만, 아마 에폭시 덩어리 아래 어딘가에 표시가 있을까요? 아마 그렇지 않을 것입니다. 하지만 연구 단계에서는 때때로 완전히 파괴된 장치가 단순히 고장 난 장치보다 더 가치 있습니다.
자, 저는 열풍기와 칼을 가지고 있었습니다. 흔히 말하듯, 열풍기와 칼이 있으면 모든 것이... 못처럼 보이나요? 그런 말인 것 같습니다.

리워크 스테이션을 최대 온도로 설정하고 칼로 들어 올려 에폭시 덩어리 전체를 떼어냈습니다. 그 덩어리가 떨어지면서 칩-온-보드(이제는 보드에서 떨어짐) 아래에는 표시가 전혀 드러나지 않았습니다. 마이크로컨트롤러의 실리콘 다이 아래쪽이 보입니다. 에폭시에는 몇 개의 기포가 있어 본드 와이어를 볼 수 있습니다.
제가 말했듯이, 때로는 파괴된 장치가 고장 난 장치보다 가치가 있습니다. 저는 열풍기, 칼, 그리고 숙어를 많이 연습해야 할 절박한 필요가 있었습니다.

오.
허.
CoB를 그런 식으로 디캡슐레이트할 수 있다는 것을 전혀 몰랐습니다. 그냥 깔끔하게 튀어나왔고, 온도를 고려할 때 제 쪽으로 튀지 않아서 다행이었습니다. 매우 예쁘지만, 실제로 여기서 앞으로 나아갈 방법이 있습니다. 전자 현미경으로 더 자세히 살펴보겠습니다.

음, 사용자 매뉴얼이 그렇게 주장하는 것입니다. 공정히 말하자면, 제가 확인했을 때 적어도 하나의 전자가 들어 있습니다.
작은 부품 때문에 눈이 어려운 다른 장난감들을 파괴하면서 "해킹"하는 동안, 납땜 인두 반대쪽에서 무슨 일이 일어나고 있는지 거의 알지 못한다는 것이 분명해졌습니다. 친구의 매우 정중한 추천으로 주화 및 납땜용 저렴한 디지털 현미경을 구입했습니다.

작업에 적합한 장비는 아니지만, 사용자 매뉴얼의 주장과는 달리, 이 현미경으로 이 이미지를 캡처했습니다. 다이의 텍스트를 해독할 수준에는 한참 모자라지만, 일반적인 레이아웃은 명확했고, 이런 이미지를 더 찾을 수 있는 곳을 알았습니다.
Siliconpr0n은 현재 Siliconprawn으로 알려져 있으며, 많은 사람들이 다이 사진을 업로드한 아카이브가 있습니다. 비록 보통 제 사진보다는 품질이 좋지만 말이죠. 불행히도, 제가 가진 정보로 사이트를 검색할 유용한 방법이 없었기 때문에, 클릭하고, 스크롤하고, 반복하기 시작했습니다...

그것의 지문이 기록에 있습니다!
몇 시간 후, 새벽 4시에 마침내 익숙한 것을 발견했습니다. 제 사진보다 품질이 좋지만 레이아웃은 틀림없습니다. John McMaster가 촬영한 일치하는 이미지와 비교하여 180도 회전된 GPL162002A(또는 B)입니다. GeneralPlus 마이크로컨트롤러이며, 데이터시트는 인터넷에서 구할 수 있고, 명령어 세트는 μ'nSP입니다.
μ'nSP는 알고 보니 이런 유형과 연도의 장난감에서 꽤 흔합니다. 라틴 알파벳에도 없는 문자를 포함하는 명령어 세트 이름을 추측하지 못한 것을 용서받을 수 있기를 바랍니다. 그럼에도 불구하고 Ghidra가 기본적으로 지원할 만큼 충분히 보편적이지는 않습니다. 다행히도 기존의 서드파티 작업이 있기 때문에, Ghidra에서 디스어셈블을 시작하고, 함수 이름을 지정하고, 데이터시트에서 레지스터 이름을 가져올 수 있었습니다.
16진수 덤프만 보고 USB 코드라고 확신했던 함수가 여기 있습니다. 마이크로컨트롤러의 데이터시트에 명시된 USB 레지스터와 상호 작용합니다:

앞서 언급했듯이, 저는 이미 USB 대용량 저장 장치가 어떻게 통신하는지 어느 정도 알고 있었습니다. 특히 Miuchiz USB 라이브러리를 libusb를 사용하여 macOS로 포팅하는 실험적인 작업 덕분이었습니다. USB 대용량 저장 장치는 기본적으로 SCSI 명령을 터널링하며, 이는 온라인에 잘 문서화되어 있습니다. 예를 들어, 장치에 읽기 또는 쓰기를 요청하는 명령이 있습니다.

그러나 일반적으로 읽기나 쓰기 같은 표준 명령은 저에게 유용하지 않을 것임을 알고 있었습니다. 그것들은 컴퓨터가 내장된 대용량 저장 드라이버로 이미 수행하는 방법을 알고 있는 것들입니다. 컴퓨터는 일반적인 이동식 미디어 장치처럼 상호 작용하기 위해 이러한 명령을 발행할 것입니다. 이 경우 읽기 명령은 도움말 파일이 포함된 파일 시스템만 검색하고, 쓰기 명령은 쓰기가 가능하지 않아야 하므로 아무것도 하지 않을 것입니다. 이것들은 전체 플래시 칩과 인터페이스하기 위한 것이 아니라, 처음 사용자를 돕기 위한 작은 시뮬레이션된 CD-ROM에 가깝습니다.
그러나 일부 명령 ID는 공급업체가 구현하고자 하는 대로 예약되어 있습니다. 일부 예약된 ID에 대한 핸들러는 일반 ID 조회가 실행되기 전에 조잡하게 삽입됩니다.

정적 분석을 통해 제가 찾고 있던 함수를 식별하고 이름을 지정할 수 있었습니다: 플래시 읽기, 프로그래밍, 지우기입니다. 이들은 모두 ME2 및 다른 GeneralPlus 장치용으로 구현된 비표준 명령이며, 거의 확실히 원래 장치에 포함된 소프트웨어와 드라이버에서 사용되었습니다. 이러한 경로 중 하나를 트리거하는 USB 메시지를 제작할 수 있습니다. 읽기를 사용하면 플래시에서 데이터를 검색할 수 있습니다. 프로그래밍을 사용하면 플래시를 "프로그래밍"할 수 있습니다. 지우기를 사용하면 플래시 영역의 모든 비트를 1로 재설정할 수 있으며, 프로그래밍 명령과 함께 사용하면 플래시에 대한 전체 쓰기를 수행할 수 있습니다. "프로그래밍"은 비트를 1에서 0으로만 변경할 수 있기 때문입니다. 제가 관심을 가진 각 사용자 정의 명령은 예약된 ID 0xFF 뒤에 하위 명령 및 작업에 필요한 매개변수에 대한 ID가 옵니다.
명령의 정확한 구조는 독자에게 특별히 관련이 없지만, 방법론은 관련이 있을 수 있습니다. 저는 libusb (사실은 rusb)를 사용하여 모든 USB 상호 작용을 용이하게 했습니다. 이 방법을 사용하면 새 드라이버를 작성하는 대신 사용자 공간 코드를 작성하여 USB 장치와 상호 작용할 수 있습니다.
Windows ME2 소프트웨어가 인터넷에서 사라졌을 때, 마치 그 언어의 두 번째로 마지막 화자가 사라진 것과 같았습니다. ME2 휴대용 기기는 어떤 의미에서 터미널 화자가 되었습니다. 약간의 실험과 때로는 정확하지 않은 디컴파일을 읽으면서, 저는 거의 사라진 언어의 단어를 배우기 위해 그 마음을 읽고 있었습니다. 그것이 대답했을 때, 저는 올바른 길에 있다는 것을 알았습니다.
Č̶̯a̴̩͗n̵͉͆ ̴͍͠Ǐ̶̜ ̴͈͌h̷̙̔á̶͉v̸͈̽é̴̢ ̵͍͛a̵̞͝ ̴̤̉s̵̡͊ē̴̮c̸̭̅t̶̛͖o̸̡͠r̶̺̊ ̶̥̀ǫ̸̀f̸̦́ ̷̈́ͅỳ̷͎o̶̦̐u̵͙̚r̶͙͒ ̵̥̕f̸̡͝l̷͈̄a̶͍͋s̸̢̓h̸̗͝?̴̪̕
...아니요? 제 억양 때문인가 봅니다. 조정해서 다시 물어보죠: 플래시 섹터 하나를 가져도 될까요? 다음 섹터는요? 그 섹터의 비트 중 일부를 프로그래밍할 의향이 있나요? 변경되었는지 확인하기 위해 플래시를 다시 가져도 될까요? 감히 섹터를 지우라고 요청할 수 있을까요... 그리고 어느 섹터를 파괴하라고 요청하는지 이해하기를 바라며?
하나씩, 저는 ME2가 듣기를 원하는 메시지를 구조화, 채우고 전송하는 코드를 작성했습니다. 우리가 같은 페이지에 도달했을 때, 저는 다른 양의 포인트를 가지고 있는 상태에서 몇 가지 플래시 덤프를 보내달라고 말했습니다. 그것들을 비교한 후, 포인트가 플래시에 저장된 위치를 식별하고 마침내 컴퓨터를 사용하여 그것들을 수정할 수 있었습니다!

실제로, 활발히 사용 중인 코드를 지우지 않는 한, 이러한 명령을 사용하여 기기에 원하는 모든 것을 할 수 있었습니다. ME2는 Miuchiz Reborn 엠블럼이 있어서는 안 될 곳에 표시된 기기 컬렉션에 합류했습니다. 여기에는 다이 사진을 찍은 디지털 현미경도 포함됩니다.

솔직히 말해, 처음 플래시 읽기/쓰기를 시도했을 때는 약간 무모했습니다. 실행 중인 모든 코드를 볼 수 없었기 때문입니다. 예를 들어, 일부 코드는 마이크로컨트롤러의 내부 ROM이나 ROM에 의해 복사된 RAM 루틴을 호출합니다. 다른 함수에 대한 추측 중 일부는 직접 메모리 접근(DMA) 레지스터가 어떻게 설정되는지에 의해 정보를 얻었습니다. 예를 들어, DMA가 USB 버퍼에서 복사하도록 설정된 경우, 아마도 그 데이터를 플래시를 프로그래밍하는 데 사용하는 것이지 플래시를 읽는 데 사용하는 것이 아닐 것입니다.

예를 들어, 이 코드는 플래시 외부에 있는 함수를 호출하여 자기 아래에서 코드를 빼내지 않도록 한 후, 어쨌든 방금 빼낸 코드로 돌아갑니다. 기기를 벽돌로 만들지 않도록 매우 조심해야 합니다.
문제의 메모리 영역은 데이터시트에 명확히 나와 있습니다:

128킬로워드의 특별히 "embadded" ROM이 있어 아직 접근할 수 없었고, 시스템을 완전히 이해하지 못하게 했습니다.
다행히도 사용자 정의 플래시 읽기 명령의 함수는 경계 검사를 수행하지 않습니다. 즉, 매우 높은 플래시 주소에서 읽기를 시도하는 특수 제작된 메시지를 사용하면 마이크로컨트롤러의 전체 주소 공간을 감싸서 시작 부분으로 돌아올 수 있습니다. 이는 임의 읽기 기능에 해당하므로, 이번에는 온디바이스 덤핑 코드를 작성할 필요가 없었습니다! 이 버그로 모든 메모리를 읽을 수 있었고, 나중에 리버스 엔지니어링을 위해 Embadded ROM을 읽었습니다.
모든 메모리를 통해, 기기의 RAM에 프레임버퍼가 있는 것을 발견했으며, 그 당시 기기 화면에 표시된 이미지를 표시하고 있었습니다:

또한 데이터시트에서 GPIO 레지스터가 있어야 할 위치를 참조하여 기기의 주소 공간에서 범용 입출력(GPIO) 레지스터를 읽을 수 있었습니다. 초당 수십 번 버그를 트리거하여 버튼 누름을 효과적으로 폴링하고 원한다면 USB 컨트롤러로 전환할 수 있었습니다: (비디오)

테스트 중 어느 시점에, 플래시에서 이상한 값 수정을 발견했는데, 그것은 저장 데이터로 의도된 것 같지 않았습니다.

0x00AA (이 시스템의 워드 크기는 16비트임을 기억하세요)가 제가 요청하지 않은 플래시 위치에 기록되었습니다. Embadded ROM을 통해 마침내 이를 설명하는 코드를 볼 수 있습니다.

이 플래시 칩들은 특정 오프셋에 쓰기를 통해 명령을 받습니다. 즉시 기록된 데이터를 커밋하는 RAM과 달리, 플래시 칩은 명령의 일부로 쓰기를 해석하려고 시도하므로, 플래시의 주소 공간에 단일 쓰기를 해도 실제로 데이터를 변경하기에 충분하지 않습니다. 코드가 플래시를 프로그래밍하려고 할 때, 0x5555에 0xAA를 쓰는 것으로 시작하여 원하는 주소에 원하는 데이터를 쓰는 것으로 끝나는 다단계 명령 시퀀스를 발행합니다.If a user with too much spare time (and perhaps a heat gun and a knife) comes up with the idea to try probing for how the device works, they may end up requesting the device to program to a sector that is beyond the capacity of its flash chip. The processor is aware of every step, but the flash chip is not. Instead, that final command cycle misses the flash chip's address space entirely, so the flash eagerly awaits what value should be programmed where.
Processor: Hey flash! I want to start programming another word!
Flash: Loud and clear! Programming 0xAA to 0x5555!
Processor: ...Huh?
Due to the desynchronized command cycles, the flash confuses the first cycle of the next command for the last cycle of the previous command, and 0xAA gets programmed to 0x5555. The equivalent address for typical 8-bit bytes is 0xAAAA, which matches where 0x00AA got written to in my flash dump.
This could potentially be used for an arbitrary write, as long as you are okay with corrupting that specific word in flash, but the device is already sufficiently pwned that I'm not interested in bricking more units. It might be possible to save these devices, as reverse engineering the Embadded ROM also showed that it contains its own USB handler and flash read/program/erase implementations. However, I have only ever gotten the ROM to enter that state (instead of booting into flash code) once, and never again. Based on the ROM's decompilation, I suspect it might rely on a GPIO port that has been left floating, but I'm not sure. In any case, my mission here had already been accomplished.
The end result of this mischief is a command-line utility that can:
This, along with game server code and other research, is available in the ME2-Restoration repository. Since implementation details are available there and are likely not interesting to the typical reader, specific technical details were omitted here in favor of describing processes and techniques.
More importantly, this demonstrates that the original PC-side software is not strictly required to understand or preserve its functionality. Even with the official software lost to time, it was possible to open up the black box that was the ME2 and reconstruct its protocol from its hardware and firmware, restoring an otherwise dead interface into something usable again. This is not limited to interfaces like USB, either. Read how I recreated a long-dead license server to bring a decade-old vector editor back to life.
This is also my first time decapsulating an integrated circuit, so to pay it the respect it deserves, I purchased a better microscope and have since contributed the highest-quality photo of the GPL162002A/B to siliconprawn, previewed here at a reduced resolution for web-friendliness:
