プログラミング
未文書化データベースのストレージフォーマットのリバースエンジニアリング
Reverse engineering the storage format for an undocumented database (blog.glazer.ee)
要約
本記事では、既存のツールで正しく解析できなかったCronosProデータベースファイル(CroBank.dat、CroIndex.dat、CroStru.dat)の解析プロセスを解説します。特に、バージョン固有のニュアンスにより解析が困難なCronosProフォーマットのバイナリファイルを、CSVのような機械可読フォーマットに変換する作業に焦点を当てています。Codexを活用し、Cronodumpコードベースを改良して、破損していると見なされたデータベースの解析を改善しました。このプロセスでは、ファイルの構造理解、難読化されたスキーマの復旧、パーサーの仮定の修正、および解析値が正しいスキーマ列の下に表示されることの検証が含まれます。
全文翻訳
目次
目次
私たちは常に異なるデータセットを扱っており、それらをデータレイクに正規化しています。最近、CronosProデータベースファイル(CroBank.dat、CroIndex.dat、およびCroStru.dat)を受け取りましたが、既存のツールでは正しく解析できなかったため、破損していると考えられていました。CronosProフォーマットを扱ったことのある人なら誰でも、その生のデータファイルがCSVのような機械可読フォーマットに変換するのが非常に難しいことを知っています。CronosダンプコンバーターCronodump alephdata/cronodumpにかなりの作業が費やされてきましたが、データベースファイル構造のバージョン固有のニュアンスのため、100%機能するわけではありません。この問題に取り組む目的で、Codexをダンプ構造の分析に採用し、Cronodumpコードベースを改良して、問題があるとされたデータベースの解析を修正しました。Cronodumpコンバーターはフォーマットの大部分を読み取ることができましたが、この特定のダンプを正しくデコードすることはできませんでした。ファイルがどのように組み合わさっているかを理解し、難読化されたスキーマを復旧し、いくつかのパーサーの仮定を修正し、解析された値が正しいスキーマ列の下に表示され続けることを検証する必要がありました。この記事では、Cronosに関する事前の知識なしに、最初からそのプロセスを説明します。
Cronosとは何か?
Cronos、別名CronosProは、プロプライエタリなデスクトップデータベースおよび情報管理システムです。歴史的にロシアやその他の旧ソビエト諸国で、レジストリ、検索可能なアーカイブ、ドキュメントコレクション、および内部情報システムを構築するために使用されてきました。Cronosのインストールは、従来のデータベースとはわずかに異なる用語を使用します:
従来の用語 | Cronos用語
データベース | Bank
テーブル | Table
レコード | Record
フィールド | Field
レコードID | System Number
Cronosデータベースは通常、いくつかの関連するバイナリファイルで表されます:
ファイル | 目的
CroStru.dat および CroStru.tad | データベース構造: テーブル、フィールド、フォーム、その他の定義
CroBank.dat および CroBank.tad | 実際のレコード
CroIndex.dat および CroIndex.tad | 検索インデックス
CroSys.dat および CroSys.tad | Cronosインストールが認識するデータベースに関する情報
その他のファイル | フォーム、数式、辞書、埋め込みドキュメント
.datファイルにはデータが含まれています。対応する.tadファイルはディレクトリとして機能し、ソフトウェアに各.datファイル内のレコードの場所を指示します。有用なメンタルモデルは次のとおりです:
CroStru -> データベースの外観を説明する
CroBank -> 実際の行が含まれている
CroIndex -> Cronosが行を見つけるのを助ける
この区別が復旧の中心となりました。レコードデータ自体は読み取り可能でしたが、それを解釈するためのスキーマは保護されていました。
「正規化」とはどういう意味か?
この記事では、正規化はリレーショナルデータベースの正規化(第1、第2、または第3正規形)を意味しません。ここでは、プロプライエタリなバイナリデータベースを、ポータブルでレビュー可能な表現に変換することを意味します:
Cronosバイナリファイル
↓
デコードされたテーブルとフィールド
↓
正しく型付けされ、整列された値
↓
UTF-8 CSVファイル
目標は単に文字列を抽出することではありませんでした。結果は、以下間の関係を維持する必要がありました:
テーブルとレコード
列名と値
日付とその意味
テキストとその元の文字エンコーディング
内部フィールドの位置
埋め込みファイル参照
誤ったヘッダーの下で読み取り可能な値を含むCSVは、明白なエラーよりも悪いでしょう。なぜなら、それは有効に見えながら意味論的に破損している可能性があるからです。
既存のパーサーの選択
私たちはオープンソースのCronodumpパッケージから始めました。これは2つの主なコマンドを提供します:
crodump | Cronosファイルを検査し、その内部構造を出力します。
croconvert | データベースをCSV、PostgreSQL SQL、またはHTMLにエクスポートします。
典型的なダンプの場合、変換は次のように簡単です:
croconvert --csv /path/to/cronos-dump
内部的には、パッケージはいくつかのジョブを実行します:
.tadファイルを読み取ってレコードを特定します。
.datファイルから対応するバイトを取得します。
必要に応じてレコードを解凍します。
KODテーブルを使用して保護されたレコードをデコードします。
CroStruからスキーマを読み取ります。
そのスキーマを使用して、CroBankレコードをフィールドに分割します。
結果のテーブルをCSVに書き込みます。
リポジトリのドキュメントでは、Cronosフォーマットの一部はまだ完全にリバースエンジニアリングされていないことが明示的に述べられています。パーサーは多くのデータベースをサポートしていますが、珍しいバージョン固有の詳細が調査を必要とする場合があります。
最初の失敗
コンバーターはCroStru.datの読み取り中に失敗しました。これにより、次のような基本的な質問にまだ答えられませんでした:
テーブルはいくつ存在するか?
それらの名前は何か?
各テーブルにはいくつのフィールドがあるか?
どのフィールドが名前、日付、識別子、またはファイル参照か?
各値は出力のどこに属するか?
大きなCroBank.datファイルには実際のレコードが含まれていましたが、有効なスキーマがないと、バイナリマーカーで区切られた値のストリームにすぎませんでした。状況は次のようになりました:
CroStru.dat -- デコード失敗 --> 信頼できる列定義なし
↓
CroBank.dat --------------------> 値は安全に解釈できない
何かをクラックしようとする前に、すべての主要ファイルのヘッダーを検査しました。ダンプはCronos 01.11フォーマットを使用しており、Cronos v4に関連付けられていました。コンポーネントフラグは重要な詳細を明らかにしました: CroStruはKODエンコードされていました。CroBankは圧縮されていましたが、KODエンコードされていませんでした。CroIndexも圧縮されていましたが、KODエンコードされていませんでした。これにより、問題の範囲が大幅に縮小しました。数10ギガバイトの保護されたレコードデータをデコードする必要はありませんでした。比較的小さいスキーマファイルを復旧するだけで済みました。スキーマが読み取り可能になれば、通常のパーサーがはるかに大きいレコードファイルを解釈できるようになります。
圧縮と保護は異なるレイヤー
混乱を招く可能性のある2つの概念を分離することは有用です。圧縮は、データが占めるスペースを少なくするためにデータを変更します:
元のバイト -> 圧縮 -> より小さいエンコードされたバイト
KOD保護は、置換テーブルを使用してバイト値を変更します:
元のバイト -> 位置依存の置換 -> 保護されたバイト
ファイルは次のいずれかになります:
圧縮もKODエンコードもされていない
圧縮のみ
KODエンコードのみ
圧縮とKODエンコードの両方
このダンプのファイルはすべて同じ組み合わせを使用していたわけではありません。それは重要でした。なぜなら、cronodumpのクラッキング方法の1つは、圧縮されたCroBankおよびCroIndexレコードの予測可能なバイトからKODテーブルを学習できると仮定しているからです。ここでは、これらのファイルはKODエンコードされていなかったため、その仮定は適用されませんでした。
KODテーブルとは何か?
Cronos v4以降は、KODテーブルまたはKOD S-boxと呼ばれる256エントリのバイト置換テーブルを変更することによってデータベースを保護できます。最も単純なレベルでは、置換テーブルは次のように述べています:
暗号化されたバイト 0x00 -> デコード値 X
暗号化されたバイト 0x01 -> デコード値 Y
...
暗号化されたバイト 0xFF -> デコード値 Z
Cronosは別の複雑さを追加します: デコードはバイトの位置とレコード番号にも依存します。概念的には、アルゴリズムは次のとおりです:
plaintext[i] = KOD[ciphertext[i]] - i - record_number (mod 256)
ここで:
ciphertext[i] は格納されているバイトです。
KOD[...] は置換を実行します。
i はレコード内の位置です。
record_number は別のシフトを提供します。
算術は256でラップアラウンドします。
実際の結果は、1バイトの違いでさえ、それに続くすべてのデコードを変更することです。これは、妥当なKODテーブルを復旧した後でも、1つのスキーマレコードが読み取り不可能であった理由を後に説明しました。
既存のクラッキングツールは何をするか?
cronodumpには、2つの関連する復旧オプションが含まれています:
crodump --strucrack ...
crodump --dbcrack ...
これらは、パスワードの総当たり攻撃ではなく、Cronosファイルの統計的プロパティを使用します。
strucrack
バイナリスキーマには、特にゼロバイト(長さ、フラグ、パディング、整数で使用される)の繰り返し値が多く含まれています。strucrackは、暗号化されたバイトをその効果的な位置ごとにグループ化し、最も一般的な結果がプレーンテキストのゼロを表すと仮定します。十分なスキーマデータがあれば、これによりKODテーブルの多くが明らかになる可能性があります。
dbcrak
圧縮されたレコードには認識可能なヘッダーがあります。適切なデータベースでは、これらのヘッダーの予測可能なバイトを使用して、CroBankおよびCroIndexからKODマッピングを推測できます。どちらも