close
IDA Pro

逆コンパイルと逆アセンブルの概要

逆コンパイラは、実行可能なバイナリファイルを読み取り可能な形式で表します。 正確に言うと、バイナリコードを、ソフトウェア開発者が読み取って変更できるテキストに変換します。 ソフトウェアセキュリティ業界は、プログラムの分析と検証はこのトランスフォーメーションに頼っています。 ソースコード(ソフトウェアのテキスト形式)は企業秘密と見なされているため、従来は利用できないため、 分析はバイナリコードに対して実行されます。

バイナリコードをテキスト形式に変換するプログラムはいつもあります。 プロセッサ命令コードの命令ニーモニックへの単純な1対1のマッピングは、逆アセンブラによって実行されます。 多くの逆アセンブラが、無料と商用の両方で市場に出回っています。最も強力な逆アセンブラはIDAProです。 膨大な数のプロセッサのバイナリコードを処理でき、開発者がアドオン分析モジュールを作成できるオープンアーキテクチャを備えています。

逆コンパイラは、1点大きく逆アセンブラと異なります。 どちらも人間が読めるテキストを生成しますが、逆コンパイラはより簡潔で読みやすく、はるかに高いレベルのテキストを生成します。

低水準アセンブリ言語と比較して、高水準言語表現にはいくつかの利点があります。

 
  • 簡潔
  • 構造化されている
  • 開発者はアセンブリ言語を知る必要がない
  • 低レベルのイディオムを認識し、高レベルの概念に変換する
  • 混乱が少なく、理解しやすい
  • 繰り返しが少ない
  • データフロー分析を使用する

これらの点を詳しく考えてみましょう。

通常、逆コンパイラの出力は、逆アセンブラの出力より5〜10倍短くなります。 たとえば、典型的なプログラムには、400KBから5MBのバイナリコードが含まれています。 このようなプログラムの逆アセンブラの出力には、約5〜100 MBのテキストが含まれ、完全に分析するには数週間から数か月かかる場合がありますが、 アナリストは予算の観点から数か月も単一のプログラムに時間をかけることは出来ません。

一般的なプログラムの逆コンパイラの出力は、400KBから10MBになります。 これはまだ読んで理解するには大きなボリュームですが(厚い本のサイズ程度)、分析時間に必要な時間は1/10以下になります。

2番目の大きな違いは、逆コンパイラの出力が構造化されていることです。 各行が他のすべての行と類似している命令の線形フローの代わりに、テキストはプログラムロジックを明示的にするためにインデントされます。 条件ステートメント、ループ、スイッチなどの制御フロー構造には、適切なキーワードが付けられています。

逆コンパイラの出力はハイレベルであるため、逆アセンブラの出力よりも理解しやすいです。 逆アセンブラを使用できるようにするには、アナリストはターゲットプロセッサのアセンブリ言語を知っている必要があります。 主流のプログラマーは日常のタスクにアセンブリ言語を使用しませんが、今日では事実上すべての人がハイレベル言語を使用しています。 逆コンパイラは、典型的なプログラミング言語と出力言語の間のギャップを取り除きます。 逆アセンブラよりも多くのアナリストが逆コンパイラを使用します。

逆コンパイラは、アセンブリレベルのイディオムをハイレベルのアブストラクションに変換します。 一部のイディオムは、分析に非常に長く時間がかかる場合があります。

x = y / 2;
上記の1行のコードは、コンパイラによって一連の20〜30個のプロセッサー命令に変換できます。 経験豊富なアナリストがパターンを認識し、元の線に置き換えるには、少なくとも15〜30秒かかります。 コードにそのようなイディオムが多数含まれている場合、アナリストはメモを取り、各パターンに短い表現でマークを付ける必要があるため、 分析が大幅に遅くなります。 逆コンパイラはアナリストから負担を軽減することが出来ます。

分析するアセンブラ命令の量は膨大です。互いに非常に似ており、パターンは非常に反復的です。 アナリストは、似たような2つのコードスニペットを混同し、出力で簡単に道に迷ってしまいます。 これらの2つの要因(テキストのサイズと退屈な性質)は、次の現象を引き起こします。 バイナリプログラムが完全に分析されることはありません。 アナリストは、ヒューリスティックと自動化ツールを使用して、疑わしい部分を見つけようとします。 例外は、プログラムが非常に小さい場合、またはアナリストが分析に不釣り合いに膨大な時間を費やしている場合に発生します。 逆コンパイラは両方の問題を軽減します。出力は短く、繰り返しが少なくなります。 出力にはまだ繰り返しが含まれていますが、人間が管理できます。さらに、この繰り返しは、分析を自動化することで対処できます。

バイナリコードの繰り返しパターンは解決策が必要です。 明らかな解決策の1つは、コンピューターを使用してパターンを見つけ、人間のアナリストが把握しやすいようにパターンを短くして簡単なものに縮小することです。 一部の逆アセンブラ(IDA Proを含む)は、分析を自動化する手段を提供します。 ただし、使用可能な分析モジュールの数は少ないままであるため、コードの繰り返しが引き続き問題になります。 主な理由は、バイナリパターンの認識が驚くほど難しい作業だからです。 足し算や引き算などの基本的な算術演算を含む「単純な」アクションは、バイナリ形式で無限の方法で表すことができます。 コンパイラは、減算に加算演算子を使用する場合があり、その逆の場合もあります。 メモリのどこかに定数を格納し、必要に応じてそれらをロードできます。 いくつかの操作の後、レジスタ値は既知の定数であることが証明でき、レジスタを再初期化せずに使用するだけです。 使用される方法の多様性は、利用可能な分析モジュールの数が少ないことを説明しています。

逆コンパイラでは状況が異なります。 逆コンパイラがアナリストにハイレベルの概念を提供するため、自動化がはるかに簡単になります。 多くのパターンは自動的に認識され、抽象的な概念に置き換えられます。 残りのパターンは、逆コンパイラが導入する形式のために簡単に検出できます。 たとえば、関数パラメータと呼び出し規約の概念は厳密に形式化されています。 逆コンパイラを使用すると、パラメーターが呼び出し命令から遠く離れて初期化されている場合でも、関数呼び出しのパラメーターを非常に簡単に見つけることができます。 逆アセンブラの場合、これは困難な作業であり、各ケースを個別に処理する必要があります。

逆コンパイラは、逆アセンブラとは対照的に、入力に対して広範なデータフロー分析を実行します。 これは、「変数はどこで初期化されますか?」などの質問を意味します。 そして、「この変数は使用されていますか?」関数を広範囲に検索しなくても、すぐに回答できます。 アナリストは日常的にこれらの質問を提起して回答し、回答を得るとすぐに生産性が向上します。

逆アセンブルと逆コンパイルを並べて比較

以下に、逆アセンブルと逆コンパイルの出力を並べて比較します。次の例を使用できます。

このページには、次の例が表示されています。

  1. 2で割る
  2. シンプルか?
  3. 変数はどこか?
  4. 算数はロケット科学ではない
  5. サンプルウィンドウ手順
  6. 短絡評価
  7. インライン文字列操作

(1)2で割る

サイズの違いに注意してください! 逆アセンブル出力では、コンパイラが符号付き除算とモジュロ演算用にこのような複雑なコードを生成することを知っている必要があるだけでなく、パターンの認識にも時間を費やす必要があります。 言うまでもなく、逆コンパイラは物事を本当に簡単にします。

(2)シンプルか?

  • 関数の可能な戻り値は何ですか?
  • 関数は文字列を使用しますか?
  • 関数は何をしますか?

上記のような質問は、逆コンパイラの出力を見るとほぼ瞬時に答えることができます。 言うまでもなく、ローカル変数の名前を変更したので見栄えが良くなりました。 逆アセンブラでは、レジスタの使用が隠されて混乱を招く可能性があるため、レジスタの名前が変更されることはめったにありません。

(3)変数はどこか?

IDAは現在の識別子を強調表示します。この機能は、ハイレベルの出力ではるかに便利であることがわかります。 このサンプルでは、取得した関数ポインターが関数によってどのように使用されるかを追跡しようとしました。 逆アセンブルの出力では、逆コンパイラが望んでいたことを正確に実行している間に、多くの間違ったeaxが強調表示されます。

(4)算数はロケット科学ではない

算数はロケット科学ではありませんが、より理解している人が解決することは良い方法です。 あなたには焦点を当てるべきもっと重要なことがあります。

(5)サンプルウィンドウ手順

逆コンパイラはswitchステートメントを認識し、ウィンドウプロシージャを適切に表現しました。 この手段がなければ、ユーザーは自分でメッセージ番号を計算する必要があります。 特段難しいことではないですが時間がかかってしまいます。もし計算を間違えたらどうしますか?


(6)短絡評価

これは、短絡評価を説明するための大きな関数からの抜粋です。 長い関数では複雑なことが発生するため、逆コンパイラを使用して人間の方法で表現すると非常に便利です。 アドレス空間に散らばったコードが2つのifステートメントで簡潔に表示されていることに注意してください。

(7)インライン文字列操作

逆コンパイラは、strcmp、strchr、strlenなどの頻繁にインライン化された文字列関数を認識しようとします。 このコードスニペットでは、strlen関数の呼び出しが認識されています。