
死んだUSBプロトコルの復元:ホットナイフが解き放つ携帯機器の秘密、忘れ去られたUSBインターフェースを蘇らせる学際的な旅
2024年、bjiruがME2ハンドヘルドデバイスに関する動画をアップロードしました。これは2008年頃に製造されたおもちゃで、USBを使ってデバイスとオンラインワールド間でポイントやジェムを同期する機能を備えていました。このゲームは非常にニッチだったため、少なくともbjiruがオンラインゲームクライアントを提供するまで、ソフトウェア、ドライバ、アセットはアーカイブされていませんでした。
私はMiuchiz Rebornのリーダーです。これは2015年に始まった取り組みで、オンライン部分とUSBで接続されたハンドヘルド部分を持つ類似のゲームの保存、リバースエンジニアリング、エミュレーション、アクセシビリティの維持を行っています。ゲームの年代とタイプが似ているため、ME2は2018年に私のMiuchizコミュニティから既に注目されていました。彼らは(誤って)アーキテクチャ上の類似性があると考えていたからです。私はこのデバイスの存在を何年も前から知っていましたが、bjiruの動画がようやく私に研究を始めるきっかけを与えました。
私の最初の取り組みは、bjiruのコンピュータゲームのコピーを再び機能させるために必要なサーバーを再現することだけに費やされましたが、その過程で必然的に注意はハンドヘルドデバイスに移りました。オンラインゲームの再現は、デバイスとの間でポイントを同期するメカニズムなしには決して完全とは言えません。結局のところ、コンピュータとME2デバイス間のこの通信がゲームの主要なギミックでした。私は、Miuchizハンドヘルドデバイスでの以前の経験が、彼らが期待するどんな通信儀礼を解きほぐすのにも役立つだろうと考えました…リバースエンジニアリングできるコードさえ手に入れば。
私の好奇心はME2の犠牲を要求しました。eBayは不換紙幣の犠牲を要求しました。やがて、これらの標本が私の前に横たわりました。

これらは小さなユニットで、数個のボタンとメスのmini-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をそんな方法で脱カプセル化できるとは知りませんでした。きれいに飛び出しました。その温度を考えると、私の方向に飛んでこなくて良かったです。非常にきれいですが、ここから先に進む方法が実際にあります。電子顕微鏡で拡大してみましょう。

まあ、それが取扱説明書の主張です。公平を期すために確認しましたが、少なくとも1つの電子が含まれています。
小さな部品が目を悩ませる他のおもちゃを破壊「ハッキング」している間、はんだごての先で何が起こっているのかほとんどわかっていないことが明らかになりました。友人からの非常に丁寧な推薦により、コインやはんだ付け用の安価なデジタル顕微鏡を購入しました。

取扱説明書の主張とは裏腹に、この顕微鏡はこの作業に本当は適していませんが、この画像を撮影しました。ダイ上のテキストを解読できるレベルには程遠いですが、全体的なレイアウトは明らかであり、このような画像をさらに見つけることができる場所を知っていました。
Siliconpr0n(現在はSiliconprawnとして知られています)には、多くの人々がダイショットをアップロードしたアーカイブがあります。ただし、通常は私のものよりも高品質です。残念ながら、私が持っていた情報ではサイトを有用に検索する方法がなかったため、クリック、スクロール、繰り返しを始めました...

その指紋が記録に残っています!
数時間後、午前4時に、ついに見覚えのあるものを見つけました。私のものより高品質ですが、レイアウトは間違いありません。John McMasterが撮影した一致する画像と比較すると、180度回転したGPL162002A(またはB)です。これはGeneralPlusマイクロコントローラで、データシートはインターネットで入手可能であり、命令セットはμ'nSPです。
μ'nSPは、この種の玩具や年代ではかなり一般的であることが判明しました。ラテンアルファベットにない文字を含む命令セットを推測できなかったことをお許しいただけると幸いです。それでも、Ghidraが標準でサポートしていないほどニッチです。幸い、既存のサードパーティの作業があるため、Ghidraで逆アセンブルを開始し、関数に名前を付け、データシートからレジスタ名をインポートすることができました。
ここに、16進ダンプだけからUSBコードであると確信していた関数があります。マイクロコントローラのデータシートで指定されているUSBレジスタとやり取りしています:

前述の通り、私はこのようなUSBマスストレージデバイスの通信方法についてある程度既に知識がありました。特に、libusbを使用してMiuchiz USBライブラリをmacOSに移植する実験的な作業のおかげです。USBマスストレージデバイスは本質的にSCSIコマンドをトンネルし、それらはオンラインで十分に文書化されています。例えば、デバイスからの読み取りや書き込みを要求するコマンドがあります。

しかし、一般的に、読み取りや書き込みなどの標準コマンドは私には役に立たないことを知っていました。それらはコンピュータが内蔵のマスストレージドライバですでに実行方法を知っているものです。コンピュータはそれらを発行して、通常のリムーバブルメディアデバイスとやり取りします。この場合、読み取りコマンドはヘルプファイルを含むファイルシステムを取得するだけで、書き込みコマンドは何もしません。書き込み可能ではないからです。これらはフラッシュチップ全体とインターフェースするためのものではなく、実質的に初めてのユーザーを支援するための小さなシミュレートされたCD-ROMです。
しかし、一部のコマンドIDは、ベンダーが実装したいものを何でも予約されています。いくつかの予約IDのハンドラは、通常のIDルックアップが実行される前に粗雑に注入されています。

静的解析を通じて、探していた関数(フラッシュの読み取り、プログラム、消去)を特定し、名前を付けることができました。これらはすべて、ME2およびおそらく他のGeneralPlusデバイス向けに実装された非標準コマンドであり、ほぼ間違いなくデバイスに元々付属していたソフトウェアとドライバによって使用されていました。USBメッセージを作成して、これらのパスのいずれかをトリガーできます。読み取りはフラッシュからデータを取得できます。プログラムはフラッシュを「プログラム」できます。消去はフラッシュ領域のすべてのビットを1にリセットし、プログラムコマンドと組み合わせて使用することで、フラッシュへの完全な書き込みを発行できます。「プログラミング」はビットを1から0にしか反転できないためです。私が関心を持っていたカスタムコマンドはすべて、予約ID 0xFFとそれに続くサブコマンドのIDおよび操作に必要なパラメータを使用しています。
コマンドの正確な構造は読者にとって特に重要ではありませんが、方法論は重要かもしれません。USBを介したすべてのやり取りにはlibusb(実際にはrusb)を使用しました。この方法により、新しいドライバを書くのではなく、ユーザーランドコードを書いてUSBデバイスとやり取りできます。
Windows用のME2ソフトウェアがインターネットから姿を消したとき、その言語の最後から2番目の話者が亡くなったかのようでした。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バッファからコピーするように設定されている場合、おそらくそのデータを使用してフラッシュをプログラムしており、フラッシュから読み取っているわけではありません。

このコードは、例えば、フラッシュの外部にある関数を呼び出して、自分自身の下からコードを引き出さないようにしてから、結局は引き出したばかりのコードに戻ります。デバイスをブリックしないように非常に注意する必要があります。
問題のメモリ領域は、データシートによって明確にレイアウトされています:

特に「embadded」なROMが128キロワードあり、まだアクセスできておらず、システムを完全に理解する妨げになっていました。
幸い、カスタムフラッシュ読み取りコマンドの関数はバウンドチェックを行いません。つまり、非常に高いフラッシュアドレスからの読み取りを試みる特別に細工されたメッセージを使用すると、マイクロコントローラのアドレス空間全体をラップアラウンドして、先頭に戻ることができます。これは任意読み取り能力に相当するため、今回はオンデバイスのダンプコードを書く必要がありませんでした!このバグによりすべてのメモリが読み取り可能であるため、Embadded ROMを読み取り、後でリバースエンジニアリングするために保存しました。
すべてのメモリを使って、デバイスのRAM内のフレームバッファを見つけることができました。当時デバイスの画面に表示されていた画像が表示されていました:

また、データシートにあるべき場所を参照することで、デバイスのアドレス空間から汎用入出力(GPIO)レジスタを読み取ることができました。このバグを毎秒数十回トリガーすることで、効果的にボタン入力をポーリングし、必要に応じてUSBコントローラに変えることができました:(動画)

テスト中のある時点で、フラッシュ内の値が奇妙に変更されていることに気づきました。それはセーブデータであるはずもないように思えました。

0x00AA(このシステムのワードサイズは16ビットであることを忘れないでください)が、私が要求していないフラッシュ内の場所に書き込まれていました。Embadded ROMにより、これを説明するコードをようやく見ることができます。

これらのフラッシュチップは、特定のオフセットに書き込むことでコマンドを受け取ります。書き込まれたデータを即座にコミットするRAMとは異なり、フラッシュチップは書き込みをコマンドの一部としてのみ解釈しようとするため、フラッシュのアドレス空間への単一の書き込みでは実際にデータを変更するには不十分です。コードがフラッシュをプログラムしたい場合、0x5555に0xAAを書き込むことから始まり、目的のアドレスに目的のデータを書き込むことで終了する複数ステップのコマンドシーケンスを発行します。暇を持て余したユーザー(しかもヒートガンとナイフを持っているかもしれない)が、デバイスの動作を調査しようとして、フラッシュチップの容量を超えるセクタにプログラムを要求することを思いつくかもしれません。プロセッサはすべてのステップを認識していますが、フラッシュチップは認識していません。代わりに、その最後のコマンドサイクルはフラッシュチップのアドレス空間を完全に逸脱するため、フラッシュはどの値をどこにプログラムすべきか待ち受けます。
プロセッサ: 「おいフラッシュ!別のワードのプログラミングを開始したい!」
フラッシュ: 「了解!0xAAを0x5555にプログラミング中!」
プロセッサ: 「…は?」
コマンドサイクルの同期が外れたため、フラッシュは次のコマンドの最初のサイクルを前のコマンドの最後のサイクルと誤認し、0xAAが0x5555にプログラムされます。典型的な8ビットバイトでの同等アドレスは0xAAAAであり、これは私のフラッシュダンプで0x00AAが書き込まれた場所と一致します。
これは、その特定のワードをフラッシュ内で破損しても構わないのであれば、任意書き込みに使用できる可能性がありますが、デバイスはすでに十分に掌握されているため、これ以上ユニットを文鎮化する気はありません。組み込みROMのリバースエンジニアリングにより、ROM自体にUSBハンドラとフラッシュ読み出し/プログラム/消去の実装が含まれていることが判明したため、これらのデバイスを救済できる可能性もあります。しかし、私は一度だけROMがその状態(フラッシュコードから起動する代わりに)に入ったことがあるだけで、その後は二度とありませんでした。ROMの逆コンパイルに基づくと、未接続のGPIOポートに依存している可能性があると推測していますが、確信はありません。いずれにせよ、ここでの私のミッションは既に達成されていました。
このいたずらの最終結果は、以下のことができるコマンドラインユーティリティです。
これらは、ゲームサーバーコードやその他の研究とともに、ME2-Restoration リポジトリで公開されています。実装の詳細はそこにあり、通常の読者には興味がないと思われるため、ここでは技術的な詳細を省略し、プロセスと技術の説明に重点を置いています。
より重要なのは、元のPC側ソフトウェアがその機能を理解・保存するために厳密に必要ではないことを示している点です。公式ソフトウェアが時間の経過とともに失われたとしても、ME2というブラックボックスを開け、ハードウェアとファームウェアからそのプロトコルを再構築し、死んでいたインターフェースを再び使えるものに復元することが可能でした。これはUSBのようなインターフェースに限りません。10年前のベクターエディタを蘇らせるために、長く死滅したライセンスサーバーを再現した方法をお読みください。
また、これは私にとって初めての集積回路の脱帽(デキャップ)でした。そのため、敬意を表してより良い顕微鏡を購入し、GPL162002A/Bの最高品質の写真をsiliconprawnに提供しました。以下にウェブ表示用に解像度を下げたプレビューを示します。
