honeylab's blog

各種ハードウェアの改造、主にファミコンミニなどをやってます(ました)

CursorAIでリバースエンジニアリング(AIプログラミング)

長らくリバースエンジニアリングで遊んでいますが、特にリバエンだと、何か気が付いたことがあったときにそれを迅速に確認したり、仮説をもとにいろいろな実装を組んでみたり、などのエンジニアリング作業が発生することが多いです
しかし、それを実装しようとしても実装に時間がかかったり、試しているうちにやっぱり違った、となったり、うまくいかない理由が実装のミスだったりして、なかなかエネルギーがけずられることになることが多いです。

しかし、最近導入したCursorを使えば、仮説をもとにプログラムを実装してもらったり、ちょっと実装を変えてもらったり、という人に頼んだらブチ切れそうなこまごまとしたプログラミングのトライアンドエラーをいくらでも試すことができます。
これはとてもリバエンと相性がいいと思います。(データ解析とかもそうかもね)

 

というわけで、今回は部屋に転がっていた2000年ぐらいのカラオケマシーンの外付け機器である、CD-ROMチェンジャーの中に入っていたカラオケデータCDを解析してみることにしました。

 

対象機器はBMBのBeMAX’ sというとうの昔にサービスが終了したマシンです。
通信カラオケは回線経由でデータが送られてくるため、CD-ROMがなぜ必要なの?と今の間隔だと思いますが、黎明期にはまだHDDが高価で容量も小さかったため、それを補うためにリリース済みの曲は外付けCD-ROMなどに収納し、差分だけが回線経由でダウンロードされるという方法だった時期があります。
この機器には4枚のCD-ROMが入っていたため、これだけで約2GバイトのHDD容量が抑えられた、ということになりますね。

 

以前動画CDだと書かれていたJOYSOUNDのCD-ROMは、ダンプすることはできましたが、ディスク全体に何らかの暗号化がかかっていて解析することができませんでした。

 

しかし、このCDは普通のISO9600フォーマットで、容易にファイルが取得できることがわかりました。

 

曲データと思われるファイルは拡張子PCTがついています

中身を見てみると。。。。-lh0-という文字列。。。。
ええええ?LHA形式のアーカイブ?????

ということで、lha x してみると中にファイルが入っていました。
以前誰かがTwitterのリプで何かの機種のデータがLHAだった、って言ってる人がいて、またまたー、とか思ってましたが、本当にあったのか・・・・

解凍してみると、拡張子dat,tmz,pcdのファイルが出てきました。

 

datは曲メタデータpcdは空に近いものが多いですが、もしかすると画像でも入ってそうな気がしました。

で、tmzのファイルはさらにlh5のヘッダ。解凍してみると。。。tmpという拡張子のファイルが出てきます。

なんかそれっぽいデータが出てきました

それっぽいデータ、というのはF0~F7のSysExや、0x9nのノートオンイベントなどです。

バイナリエディタで眺めてみると、これ以上暗号化されている気配はないです。

また、明らかにMIDIイベントのようなデータがたくさん見えてきました。
このままエクスポートできる気がしますが、よくよく見ると、タイムコードがありません。

 

ChatGPTにhexdumpを食わせてみると、大変寄り添ってくれました。


MIDIイベントの塊の前には、明らかにインデックスっぽいものが入っています。

ChatGPTも私と同じ意見です

このままではChatGPTに勝手にプログラミングを始められてしまうので、ここはCursorにやってもらうことにします。


これがいるのかどうかわからないですが、まず、これからやることを宣言します

MIDIデータを含むバイナリファイルからSMFファイルを出力する フォーマットは道なのでこれから解析していく

「未知」を道とtypoしましたが、わかってくれたようで、なんかいきなりやる気を出して、SMFファイルを書き出すpythonスクリプトをいきなり書きやがりました。すげぇ。

先走りしているCursorをなだめながら、わかっていることを叩き込んでいきます

・フォルダ内にある拡張子tmpのファイルが解析対象になる このファイルは先頭部分に一定サイズのヘッダがあり、続いてMIDIイベントタイムスタンプまたはデルタタイムを含むインデックスエリア、そのあとにタイムスタンプの無いMIDIイベントの羅列が含まれる タイムスタンプデータをもとに、適切な数のMIDIイベントを拾い上げて、タイムスタンプ付きのMIDIデータに再構成する必要がある

・仮の構造として、0x78バイトまでは未解析のヘッダとして取り扱う タイムスタンプブロックが始まり、「8バイトのイベントサイズ構造体(先頭4バイトは未解析のビッグエンディアンのDWORD値、2バイトでイベントのバイトサイズ、2バイトは未定義)、続いて8バイトのタイムコード(先頭2バイトは未解析、2バイトのイベントコードA、2バイトのデルタタイム、2バイトのイベントコードB)」の16バイトセットが続く イベントコードBが0003になったところでタイムスタンプは終わる

頼んでもいないのに、ログレベル可変のlogging機能まで実装してくれていますので、注文を追加します。

・TImestamp blockのlogのINFOで、何バイト目を処理中なのかを表示して また、仮に10ブロック読んだところでいったん強制終了して

書いてもらった仮コードをもとに、何回か実行してフォーマット仮説をアップデートしていきます

・タイムスタンプブロックに割り当てられるイベントサイズはMIDIイベントの個数ではなく、イベントを構成するバイト数のこと

・イベントブロック一つに対して、既定のバイト数読み込んだらMIDIデータのカーソルはそのバイト分進めて、次のイベントブロックを処理し、そこに割り当てる いまの動作は違う気がする

MIDIデータにランニングステータスが使用されているように見える そのためUnknownと表示されているようだ ランニングステータスを解釈できるようにしつつ、MIDIイベントとして破綻したデータが発見されたら直ちにそのバイト位置を​表示して異常終了して

・デルタタイムの処理を明確にする タイムスタンプブロックに入っているデルタタイムは、そのブロック処理後に現在再生Tickに追加される これをもとに、MIDIイベントの再生ポジションを設定し、表示して この時点で処理可能ならSMFのためのストリームに設定してエクスポートしてみて

・SMF出力時の時間分解能の値を48に

・absolute tickのカウントアップは、次のTimeBlockを読み込んだ時で、同じTimeBlock内にあるMIDIイベントは同一absolute timeに

・0x48から始まる2バイト、BEがSMFの分解能になる

・4バイトだと思っていたが、1バイト目はどうやらフラグの可能性がある 下位3バイトだけをテンポとし、1バイト目はフラグとして扱ってみて また、フラグがあったブロックはそれもプロパティとして

 

細かい注文を付けていきます。これ、興味がない他人にやらせたらブチ切れると思います。

っていうか、何でこの注文を理解して、応答が生成されるのか、マジでもうAI意味わかんないです。

 

あれやこれややった結果、高々数時間でカラオケ用のデータからSMFファイルをエクスポートすることができました。
AIすごい。
ある程度のリバエンの知識があれば、このような推測をもとに未知のファイルフォーマットから必要なデータを取り出すようなプログラムができてしまいました。

 

 


今回マジで一行もコード書いてません。っていうか、私Pythonのコード書けないです。

ソースコードはこちら

https://gist.github.com/bakueikozo/e41a7a788fe19335b5a1ebc7248c4ca5#file-tmp_midi_extractor-py

とはいえ、これは1990年代に作られたようなシステムのデータであり、暗号化や復号化のレベルはたかが知れています。
最近のシステムや、もっとがっちりしたプロテクトがかかっているものの解析を、放り込んだだけでできるようなものにはまだまだならない気がします。

ただ、こういった古い機器に埋まっている貴重なデータの解析、今まで自力でコードを書かないといけなかった部分をAIにチャチャっと、マジでチャチャっとやらせることができるため、人生においてリバエンに使うことができる時間を増やし、より多くの収穫を得ることができるようになったと思います。

 

さらに多くの収穫を得るため、CD-ROMの内容をいったんハードディスクにコピーし、
この中身を再帰的に解凍し、メタデータとともにファイル名を付ける上位スクリプトを作成してもらいます。

 

できちゃった。すげぇ。
手元にある4枚のCD-ROMのタイムスタンプを見るに、どうやら2000年ぐらいまでのデータが入っているっぽいです。

これはとっても大事なコレクションができました。わいわい。