マシンコードでどのようなヒントが生成されたコンパイラを指摘できますか?


31

私は、アプリケーションのマシンコードを見ているとき、どのコンパイラ(そしておそらくはバージョン)がそれを生成するのに使われたかを示す、生成されたマシンコードから分かるヒントとパターンがありますか?

アプリケーションを生成するために使用されるコンパイラを知っていると、生成されたオブジェクトからソースコードの内容にリバースエンジニアリングするのに役立ちますか?

+1

「生成されたオブジェクトから生成されたオブジェクトをより効率的にリバースエンジニアリングして元のコードに戻す手助けをしてください」と言えば、コードを逆コンパイルしたり、コードの機能を理解することはあなたの目標ですか? 19 3月. 132013-03-19 20:25:31

  0

コードを完全に逆コンパイルすることは可能ですか?可能であれば逆コンパイルして、それ以外の場合は少なくともその機能を理解するように言います。 19 3月. 132013-03-19 20:43:31

30

この分野にはいくつかの学術研究がありますが、あなたが望むキーワードは「ツールチェーンの起源」です。 Nate Rosenblum on this topicによってかなり良い論文がありました。私がこの論文を読んでからしばらくありましたが、この情報を確立するために多くのテクニックを使用することができます。私は機械学習を使う人もいれば、ヒューリスティックなやコンパイラの振る舞いに関する公理を使う人もいると思います。

これを確立することは、ユーティリティIMOの制限です。これはマルウェアグループや脅威俳優に関する情報を入手しようとしている敵対的な状況において有用かもしれませんが、この種の情報は難読化または破壊される可能性があることに留意してください。この情報の潜在的な用途の1つは、バイナリソフトウェアが、その会社固有の署名情報を持つコンパイラを含むいくつかの企業SDKを使用してコンパイルされていることを確認することです。ツールチェーンの出所を確立することで、SDKを購入した人がマルウェアを作成するなどして、ライセンスや契約に違反している場合があります。

動作の違いの例は、パラメータ書き込みです。スタックに値を配置するには、pushを使用する方法とmovを使用し、アドレスをespに基づいてデスティネーションオペランドにする方法が2つあります。

 
push eax 
push ebx 

を、もう一つは、これを行うことができます:だから1つのコンパイラはこれを行うことができます

 
mov [esp+foo], eax 
mov [esp+foo+4], ebx 

をそして、彼らはありません。一般に、MSVCは最初の例を実行し、GCCは少なくとも今では非常に限定されたテスト/観察で少なくとも2番目の例を行います...


4

マシンコード(またはアセンブリコード)について言えば、あまり情報はありません。現代のコンパイラのほとんどは、同様の出力を生成するか、または出力が違いを見るのに十分ではありません。私が経験していない、他の誰かがチャイムインする必要があるコンパイラの最適化です。あなたがELFファイル全体を持っていて、シンボルが利用可能な場合、あなたはどのような種類のものに基づいて結論を導くことができます。ライブラリーがリンクされています(例えば、libgcc)。コンパイラー固有の関数の名前。 ELFにデバッグ情報が含まれていると、 "GCC:(Ubuntu/Linaro 4.6.3-1ubuntu5)4.6.3"のようなものも見えます。あなたがC++コードを扱っているなら、シンボル名のmanglingはそれを遠ざけることができます。

しかし、自分自身に尋ねたように、なぜこの情報が必要なのか不思議です。私は、それができるようにしたコンパイラを知ることによってどのくらいの助けを得るのか分かりません。私はARMでもっと仕事をしていますが、そのプラットフォームでは、コンパイラ/アセンブリコードが守らなければならないアプリケーションバイナリインターフェイスがあります。このABIは、関数を呼び出す方法、何に使用するレジスタを何に使うべきかなどについての情報を提供します。厳しいABIのないプラットフォームでは、オペレーティングシステムはしばしばそのようなトピックについて開発者に情報を提供します。いずれにしても、コンパイラは互換性のあるコードを作成する必要がありますので、コードを作成したコンパイラを識別するための使用方法はわかりません。

+7

この回答には、出力に違いがない理由の根拠や参照がありません。 x86の私の個人的な経験はこれと矛盾しますが、私のサンプルサイズは小さすぎてこれが一般的であると言うことはできません。また、なぜこの情報が必要なのかは、実際には答えの一部ではなく、明確化の要求が多く、質問のコメントによく合います。 19 3月. 132013-03-19 20:31:30

+1

建設的な批評をいただきありがとうございます。私は質問に答えることに新しいので、私はすべての詳細を理解していない。もっと参考にしてみよう。 19 3月. 132013-03-19 20:34:57

+4

コンパイラ間には驚くほど多くの違いがあります。特にx86コードでは、さまざまな指示があります。 switch文の実装、スタックレイアウトの決定、およびレジスタの選択は、どのコンパイラが使用されたかのヒントを提供します。 20 3月. 132013-03-20 02:23:00


10

マシンコードを見ると、通常、生成されたバイナリがどのようにスクラブされていないかを追うことができる "トレイル"があります。

enter image description here:たとえば、私は今あなたがhexeditようなツールを取る場合は、マシンコードに見ることができる情報を建てる含むセクションがある標準オプションgcc -Wall hello.cと私のLinuxボックス上でGCCを使用して、小さな「Hello World」アプリケーションを生成しました

私はGCCバージョン4.6.3でこれを作成しました。他のコンパイラには、他の種類のシグネチャMicrosoft's "rich" signatureがあります。

+2

ファイルを取り除いた後にどのように見えるかは面白いです... 20 3月. 132013-03-20 20:07:27

  0

質問は、具体的にはマシンコードに関するものでした。 OPはすでにヘキサエディタやobjdumpを使って簡単な文字列を探しているような基本的な方法を試してみたいと願っています。この場合、これは答えではありません。しかし、確かに、どうにかしていなければ、それは意味があります。 ;-) 03 4月. 162016-04-03 13:04:34

  0

@underscore_d - 「誰かが望むだろう」私は単にOPがこれを知っていることを願っていないことを確認していました。私はあまりにも多くの仮定をしないことが好きです! 15 5月. 162016-05-15 06:48:07


9

「Packer Genetics:The Selfish Code」というタイトルのリコンこれに対するアプローチ。コンパイルされたプログラムから最も一般的なコード・シーケンスを抽出するためにいくつかの統計を使用し、アンパックの終了を検出するために統計を使用しましたが、このアプローチを使用して特定のコンパイラーを簡単に識別できます。

ここスライド15から参照してください:スライドはやや切り捨て思えるhttp://blog.zynamics.com/2010/07/16/recon-slides-packer-genetics-the-selfish-code-bochspython/

、私は実際のプレゼンテーションがより多くの情報を持っていたと信じています。


4

アプリケーションを生成するために使用されるコンパイラを知っていれば、生成されたオブジェクトからソースコードの可能性をより効果的にリバースエンジニアリングするのに役立ちますか?

はい、役立ちます。

さらに良い:

  • 正確なコンパイラのバージョン。
  • 正確なコマンドラインパラメータ。
  • ビルド環境(OS、パッチレベル、...)。

アイデアはにある:異なる構造を紹介し、それらをコンパイルする別の例(小さな小さなプログラム)のロットの

  • ビルド・テスト・ケース。

  • 結果のマシンコード(パターンに気付く)を見てください。

これらのケースの多くは、コンパイラ(ifおよび他の制御構造、基本的な言語機能、...)のメジャーバージョンの上に一般化することができます。

コンパイラ固有の最適化には、同じプログラムで大きく異なるものがあります。

(特定のコンパイラが生成するマシンコードのリバースエンジニアリングを支援するための一般的な/便利なケースのためのテストケースライブラリが存在する場合、私は疑問に思う。)

  0

鈍いことは申し訳ありませんが、あなたの書式作成に取り組み、ランダム首都を取り除く必要があります。今、答えは読みにくいです。 19 3月. 132013-03-19 22:39:29

  0

改善を編集しましたか? 19 3月. 132013-03-19 22:56:26

+1

@ Gilles:ありがとう。 19 3月. 132013-03-19 23:04:40


7

は私を助けてアプリケーションを生成するために使用するコンパイラを知ってい より効率的にリバースエンジニアリングして、生成されたオブジェクトから ソースコードになっている可能性があります。

私は、以下の理由により非常に重要なステップとして知っ使用コンパイラを考えてみます。

  1. それはあなたがターゲットを分析するための適切なツール(複数可)を選択できます。
  2. ランタイムを知ることは解析にとって重要です。たとえば、Delphi TFileStreamは、ファイルの読み取り/書き込みによく使用されるオブジェクトです。例と1を明確にするなど

をそのオブジェクトのvtableのを知ってオフセットがリード/ライトされている場合、私が理解するのに役立ちます/求めて:そのようIDRなどのツールは、より良いフィットDelphiの目標のためのIDA Proによりかもしれません。または、少なくともIDAのシンボルを改善するMAPファイル/ IDCスクリプトを生成することができます。しかし、Visual Basicで書かれたターゲットでは、VB Decompilerなどを使用することがあります。


6

リンカのバージョンではなくコンパイラのバージョンを意味しない限り、コンパイラのバージョンを判断するためにまずやるべきことは、実行可能ファイルのPEヘッダーの "MajorLinkerVersion"フィールドと "MinorLinkerVersion"フィールドを調べることです。 EXE、DLL、またはSYS。以下のリストを参照してください。

メジャーマイナー

0x5と0x0の(5.0)のBorland C++/MSリンカー5.0

0x6に0x0の(6.0)は、Microsoft Visual Studioの6

0x7のの0xAが(7.10)は、Microsoft Visual Studioの2003

0x8 0x0(8.0)Microsoft Visual Studio 2005

0x9 0x0(9.0)Microsoft Visual Studio 2008

0xAが0x0の(10.0)のMicrosoft Visual Studio 2010の

を0x2の0x15の(2.21)MinGWの

を0x2の0x19(2.0.0.25)Borland Delphiの(リンカ2.0.0.25)

残念ながら、パッカーとプロテクターは、これらの値を上書きして独自のものを作成したり、元のコンパイラーを推測するプロセスを強化する傾向があります。

また、実行可能ファイルのリソースディレクトリは、特定のリンカー情報を検索するのに適しています。例えば「DVCLAL」という名前のリソースを持つRT_RCDATAは、Borland C++またはDelphiの記号であり、MSVCビルドの実行可能ファイルの場合の「RT_MANIFEST」は、リンクされているランタイムDLLの特定のバージョン、したがってコンパイラのバージョンについて教えてくれます。

また、「TimeDateStamp」フィールドが0x2A425E19に設定された実行可能ファイルは、Delphiでビルドされていることの兆候です。

アセンブリコードからコンパイラを決定する場合は、最近のMSVCコンパイラバージョンの記号が、エントリポイントでスタッククッキーを生成する関数を参照しています。

エントリポイントのJMP命令の後ろに "fb:C++ Hook"という文字列が続くように見えるのは、Borland C++の記号などです。