いろいろなものを解析してみよう(その1)
Posted on 2011-09-08 by ta2決済系のシステムエンジニア、低レイヤのソフトウェアプログラマを経て、現職では芸者東京エンターテインメントでアプリケーションエンジニアとして働いています、 ta2 と申します。今回は、直近の業務にはほとんど関係しないものの、奥が深いプログラムの解析をテーマにしてみようと思います。
私自身はそれほど解析に詳しいわけではありませんが、プログラムの解析で必要なのは、その解析で何を達成したいのかが重要だと思います。プログラムの解析に限った話ではないですが。
そもそも、プログラムの解析を始めたのは、ゲーム中で流れる音楽をゲームプログラムを起動しなくても、個人的に自由に聞きたいということがきっかけです。
注意! 一般的には、プログラムの解析では、リスクを伴いますので、あくまで自己責任にてお願いします。
- 法的リスク。ソフトウェア使用許諾契約書などにリバース・エンジニアリングを禁止する条項があり、その内容に同意した場合に、プログラムの解析をすると、問題となる場合があります。
- 解析にともなうリスク。実行内容を変更するツールを用いるため、実行プログラムが予想しない動作を引き起こす可能性があります。対解析ツール用に防御機構を備えているソフトウェアもあります。
とはいっても、解析は非常に有用です。例えば以下のようなことに役立つのではないかと考えています。
- 外部のモジュールとの関係や動作の仕組みを実際に理解する
- 暗号化アルゴリズムで、メモリの内容を嗅ぎ回られるリスクが最小限になっているかどうかの判定
今回は、自作の Windows(x86) プログラムを解析してみることとします。
使用するツール
以下に紹介するツールは、Windows 7 SP1 x64 での動作を確認しました。 wow64環境で動作しています。
- バイナリエディタ。私の場合は、Stirlingというツールを使います。
- OllyDbg。Windows(x86)で、 C/C++ で作成されたプログラムを強力に解析できるツール。レジスタの内容や、スタック、メモリの内容をのぞけます。対象とするスレッドやモジュールも簡単に切り替えることができます。C# のプログラムを解析することはできないようです。また、x64 native の Windows プログラムも解析できないようです。バージョン2.0 では、様々な機能が追加されているようですが、Windows 7 や x64 上の環境ではあまりテストしてないようです。
次に OllyDbg の画面の説明を簡単にします。
- 逆アセンブルコードの表示。プログラムが実行される様子が追えます。Visual Studio や、 Eclipse などの開発環境と似たような感覚で使用できます。ブレイクポイントを置いたり、実行内容を変更したり、ステップ実行できたりします。
- CPU のレジスタの情報表示。実際にどのような値が演算されているか確認できます。
- メモリ内容の一部が表示されます。ASCII や UNICODE として表示させることが出来ます。
- スタック内容の表示。
解析の目標
先ほどダウンロードしていただいたファイルを解凍すると、コンソールプログラム本体「encryptedTexts.exe」と、暗号化済みテキスト「secret.txt」が展開されます。展開された「secret.txt」を復号し、メッセージを見つけることが目標です。
解析の手順(前半)
- 先ほどダウンロードしていただいたファイルを解凍し、バイナリエディタで、「secret.txt」を開いてみます。先頭に後述するマジックナンバーが書かれています。今はこういう感じでファイルがセーブされている程度の理解で問題ありません。
- OllyDbg を起動します。Windows Vista や、Windows 7 では、「管理者として実行」を選んで起動してください。
- OllyDbg の EncryptedTexts.exe を実行します。
- OllyDbg が注目しているスレッドを”main”、モジュールを”encryptedTexts.exe” に切り替えます。
このあとどうやって解析を進めればいいでしょうか?私の場合は以下のような方法でプログラムを解析しています。
方法
- 頻繁に呼び出される箇所を探す。ループ回数がやたら多い、関数呼び出しの多いところを探す。音声データのロードや画像データのロードだと、頻繁に呼び出される関数は、ReadFile 系の関数だと推測ことができます。
- ”all referenced text strings” で、プログラムが参照している文字列が見えるので、「マジックナンバー」や、意図を持った文字列がないかどうか確認する。
解析の手順(後半)
今回の例の場合は、プログラムを参照している文字列を表示させます。すると、文字列の中に 「/decrypt」という、以下にもコマンドのスイッチみたいな表現が見つかります。
そこで、プログラムを引数付き(/decrypt のスイッチつき)で再スタートさせてみます。すると、以下のように、復号後の文字列が表示されます。これで目的の文字列が得られたため、解析終了です。
マジックナンバーとは?拡張子ogg のファイルをバイナリエディタなどでのぞくと、先頭に “OggS” という文字列が書かれています。また、ビットマップ画像ファイルでは、マジックナンバーは、”BM”に設定されています。メモリ上で、これらのマジックナンバーを探すことで、データ本体に辿りつけることもあります。ファイルフォーマットをよく知っておくことが、データ本体にたどり着く近道です。
おまけ
実はこの記事を書くために、secret.txt を自作する必要がありました。そのために、広く知られている、RC4 互換のArcFour アルゴリズムを利用して、暗号化を実現しています。初期化キーはプログラムに埋め込まれています。興味のある方は、ここから zip ファイルをダウンロードして、実際に暗号化・復号を確かめることも出来ます。また、「secret.txt」のフォーマットは、次の画像のようにヘッダ部(マジックナンバー:GteT、データ部のテキスト長: 1D 00 00 00)、データ部になっています。
解析の様子を実際に確かめてみたい方は、zip で固めたデータ、encryptedTexts をダウンロードして試してみてください。その際、もしかすると、Microsoft Visual C++ 2010 再頒布可能パッケージ (x86)などが必要となるかもしれません。なお、注意で書いた防御機構は実装していません。自由に解析していただいて結構です。
※プログラムは、本業の合間を見つけて作ったので、大半のエラーチェックやフォーマットを真面目に考えて実装しているわけではありません。したがって、今回の例程度よりも文字列長が長い文字のエンコード・デコードはうまく動作しないしない場合がありますので、あらかじめご了承ください。
私の次回の執筆テーマ
Wireshark で、パケットをキャプチャして、ダウンロードされるファイルのデータを取得してみるような内容にしようかと考えています。