こんにちは!セキュリティの卵の皆さん 🌱
前回、私たちは強力な無料のリバースエンジニアリングツールであるGhidra(ギドラ)のインストールを終えました。ツールをインストールしたら、次は使ってみるべきですよね?
しかし、最初から大がかりなマルウェアを分析しようとすると、頭が痛くなるだけで、すぐに疲れてしまいます。🤯そこで今日は、最も基礎的でありながら最も重要な第一歩、「Hello World」プログラムを分析してみましょう。
「え、Hello Worldはただ出力するだけじゃないですか?」と思われますか?はい、その通りです!しかし、「私たちが知っているソースコード」が「コンピューターが理解する機械語」に変わり、それを再び「私たちが理解できるように復元(逆コンパイル)」する過程を理解するには、これ以上の例はありません。
ここに私たちの頼もしい味方、生成AIまで加わったら?リバースエンジニアリングはもう怖くありません!さあ、始めてみましょうか?🚀

🛠️ 準備物
- インストール済みのGhidra: (まだインストールしていない場合は、以前の投稿を参照してください!)
- 分析対象ファイル (hello.exe): C言語で「Hello World」を出力する非常にシンプルなプログラムです。
- AIチャットボット: ChatGPT、Claude、Geminiなど、何でも構いません。
💡 参考: 分析対象ファイルの作成 Cコンパイラ(GCC、Visual Studioなど)をお持ちの場合は、以下のコードをコンパイルしてhello.exeを作成してみてください。お持ちでない場合は、インターネット上にたくさんある「Hello World exe」ファイルを何でも入手しても構いません。
>
`
#include
>
int main() { printf(“Hello, AI Reversing World!
“); return 0; }
`
STEP 1. Ghidraにファイルを読み込ませる (Import) 📥
まず、Ghidraを実行し、プロジェクトを一つ開きます。(例: MyFirstReversing)
- 準備したhello.exeファイルをGhidraのプロジェクトウィンドウにドラッグ&ドロップします。
- 「Import」ウィンドウが表示されたら、特別な設定なしに[OK]をクリックします。
- プロジェクトリストにhello.exeが追加されたのが見えるはずです。ダブルクリックしてファイルを開いてください。
(ドキドキ)ついに分析画面へ突入!
ファイルを初めて開くと、Ghidraが尋ねます。「このファイルを分析しますか? (Analyze?)」もちろん[Yes]をクリックし、デフォルトオプションのまま[Analyze]ボタンをクリックしてください。Ghidraがファイルを一生懸命に噛み砕き、分解し、味わい、楽しむ作業を開始します。🍖
STEP 2. エイリアン言語と向き合う (Listingビュー vs Decompilerビュー) 👽
分析が終わると、画面に膨大な情報が表示されます。慌てないでください!私たちはたった2つの場所だけを見れば十分です。
1. リスティング(Listing)ビュー (中央の大きな画面)
ここは「アセンブリ言語(Assembly)」の世界です。PUSH、MOV、CALLのような機械語命令が見えます。コンピューターはこの言葉を理解しますが、私たちは…うーん…まだ難しいです。😅
2. デコンパイラ(Decompiler)ビュー (通常は右側の画面)
✨ 今日の主役です! ✨ Ghidraの強力な機能であるデコンパイラが、エイリアン言語のようなアセンブリ言語を、私たちが慣れ親しんだC言語に似た形式(擬似コード、Pseudo-code)に変換して表示してくれる場所です。
STEP 3. main関数を探す 🕵️
プログラムが開始されると最初に実行される場所、それがmain関数です。これを見つける必要があります。
- Ghidra左側の「Symbol Tree」パネルを見てください。
- 「Exports」または「Functions」フォルダを開いてみます。
- 運が良ければ、mainという名前がはっきりと見えるでしょう。(見えない場合は、通常entryやWinMainなどを辿っていくと見つかりますが、簡単な実習なのでmainが見えると仮定します!)
- mainをダブルクリックしてください。
じゃーん!🎉 リスティングビューとデコンパイラビューが同時にmain関数の位置に移動します。
STEP 4. 私のコードを返して! (逆コンパイル結果の確認) 👀
右側のデコンパイラビューをよく見てください。先ほど私たちが書いた(または予想した)Cソースコードと似ていますか?
// Ghidraが表示する逆コンパイルコードの例(実際とは異なる場合があります)
int __cdecl main(int _Argc,char **_Argv,char **_Env)
{
__main(); // コンパイラが追加した初期化関数
puts("Hello, AI Reversing World!"); // printfがputsに最適化されることもあります
return 0;
}
あれ?少し違いますね。
- printfを使ったのにputsが見えたりします(これはコンパイラが最適化したものです)。
- __main(); のように、私が書いていないコードも含まれています。
- 関数パラメータ名も _Argc のように複雑に見えます。
元のソースコードと100%同じではありませんが、「ああ、このコードは文字列を出力して終了するんだな」という核心ロジックは把握できます。これこそがリバースエンジニアリングの核心です!
STEP 5. AIにコード構造を尋ねる (ついにAI登場!🤖)
さて、コードが簡単すぎてつまらないですか?もしコードがもう少し複雑になると、undefined4 uVar1; のような奇妙な変数名が乱立して、理解するのが難しくなります。
このとき、AIが輝きを放ちます。Ghidraが表示した逆コンパイルコードをAIに投げかけて、解釈させてみましょう。
1. コードをコピーする
デコンパイラビューにあるコード全体をドラッグしてコピー(Ctrl+C)します。
2. AIにプロンプトを入力する
お使いのAIチャットボットに行って、次のように尋ねてみてください。(ペルソナを与えると、より良い回答が得られます!)
🧑💻 私のプロンプト: 「あなたは今からシニアセキュリティアナリストです。私がリバースエンジニアリングツール(Ghidra)で逆コンパイルしたCコードを渡しますので、このコードの全体的な構造と、どのような役割を果たすのかを初心者にも分かりやすく説明してもらえますか?
>
`
(先ほどコピーしたコードをここに貼り付け)
`
3. AIの回答を確認する
AIは何と答えるでしょうか?おそらく、このように答えてくれるでしょう。
🤖 AIの回答(例): はい、ご提示いただいたコードは、典型的なCプログラムのエントリポイントであるmain関数の逆コンパイル結果です。
>
コード構造と役割の説明:
>
1. 関数定義 (main): プログラムが実行される際にオペレーティングシステムによって最初に呼び出されるメイン関数です。int型を返し、コマンドライン引数(_Argc, _Argv)を受け取っています。
2. 初期化ルーチン (__main()): 実際のユーザーコードが実行される前にコンパイラが挿入したプログラム初期化関連の関数と思われます。あまり気にする必要はありません。
3. 主要機能 (文字列出力):
– puts(“Hello, AI Reversing World!”);
– この部分が最も重要です。「Hello…」という文字列を画面(コンソール)に出力する役割を果たします。元のソースではprintfを使用していたとしても、単に文字列のみを出力する場合、コンパイラがより高速なputs関数に最適化(変更)することがよくあります。
4. 終了 (return 0;): 関数が0を返し、正常に終了したことをオペレーティングシステムに通知します。
>
要約: このプログラムは、実行時に複雑なロジックなしに「Hello, AI Reversing World!」という挨拶メッセージを出力し、すぐに終了する非常にシンプルな構造を持っています。
🎉 実習を終えて
いかがでしたか?AIの説明は素晴らしいと思いませんか?🤩
私たちが目で漠然と推測していた内容を、AIは明確な用語(エントリポイント、初期化ルーチン、最適化、戻り値)を使って構造的に整理してくれました。
今日の実習を通して、私たちは2つの大きな収穫を得ました。
- 機械語の世界を少し垣間見た: 私たちが書いた美しいソースコードが、実際にはこんなに複雑に変化するということを知りました。
- AIという強力な助手を手に入れた: 今後分析するコードがどんなに複雑で、変数名がiVar1、uVar2のようにめちゃくちゃでも、AIに尋ねれば全体像を把握できるという自信を得ました。
次回は、いよいよ「分析」らしい分析を行う予定です。コードを操作してプログラムの動作を変更する「パッチ(Patch)」の実習を準備してきます!
それまで、今日学んだ内容をぜひ復習してみてください!さようなら!👋
コメントを残す