web-dev-qa-db-ja.com

逆アセンブラの書き方は?

教育プロジェクトとしてx86逆アセンブラを書くことに興味があります。

私が見つけた唯一の本当のリソースは、スパイラルスペースの「 逆アセンブラーの書き方 」です。これにより、逆アセンブラのさまざまなコンポーネントについてのナイスな高レベルの説明が得られますが、さらに詳細なリソースに興味があります。私も NASM's ソースコードをざっと見てみましたが、これは学ぶのがやや重いです。

このプロジェクトの主要な課題の1つは、処理する必要があるかなり大きなx86命令セットであることを理解しています。基本的な構造、基本的な逆アセンブラリンクなどにも興味があります。

X86逆アセンブラの記述に関する詳細なリソースを誰かに教えてもらえますか?

65
mmcdole

80386プログラマーズリファレンスマニュアルセクション17.2 をご覧ください。逆アセンブラーは、実際には美化された 有限状態マシン です。分解の手順は次のとおりです。

  1. 現在のバイトが命令プレフィックスバイト(F3F2、またはF0);もしそうなら、あなたはREP/REPE/REPNE/LOCK接頭辞を持っています。次のバイトに進みます。
  2. 現在のバイトがアドレスサイズバイト(67)。その場合、現在32ビットモードの場合は16ビットモードで命令の残りの部分のアドレスをデコードし、現在16ビットモードの場合は32ビットモードでアドレスをデコードします。
  3. 現在のバイトがオペランドサイズバイト(66)。その場合、現在32ビットモードの場合は16ビットモードで即値オペランドをデコードし、現在16ビットモードの場合は32ビットモードで即値オペランドをデコードします。
  4. 現在のバイトがセグメントオーバーライドバイト(2E363E2664、または65)。その場合、デフォルトのセグメントレジスタの代わりに、アドレスのデコードに対応するセグメントレジスタを使用します。
  5. 次のバイトはオペコードです。オペコードが0F、それは拡張オペコードであり、次のバイトを拡張オペコードとして読み取ります。
  6. 特定のオペコードに応じて、Mod R/Mバイト、Scale Index Base(SIB)バイト、変位(0、1、2、または4バイト)、および/または即値(0、1 、2、または4バイト)。これらのフィールドのサイズは、以前にデコードされたopcode、アドレスサイズオーバーライド、およびオペランドサイズオーバーライドに依存します。

オペコードは、実行されている操作を通知します。オペコードの引数は、Mod R/M、SIB、変位、および即値の値からデコードできます。 x86の複雑な性質により、多くの可能性と多くの特別なケースがあります。詳細な説明については、上記のリンクを参照してください。

62
Adam Rosenfield

私はいくつかのオープンソースの逆アセンブラー、できれば distorm をチェックすることをお勧めします。

ドキュメント自体は、オペコードと命令に関するジューシーな情報でいっぱいです。

引用元https://code.google.com/p/distorm/wiki/x86_x64_Machine_Code

80x86命令:

80x86命令は、いくつかの要素に分割されます。

  1. 命令のプレフィックスは、命令の操作の動作に影響を与えます。
  2. SSE命令のオペコードバイトとして使用される必須のプレフィックス。
  3. オペコードバイトは、1バイト以上(最大3バイト)の場合があります。
  4. ModR/Mバイトはオプションであり、オペコード自体の一部を含む場合があります。
  5. SIBバイトはオプションであり、複雑なメモリ間接形式を表します。
  6. 変位はオプションであり、さまざまなサイズのバイト(バイト、ワード、ロング)の値であり、オフセットとして使用されます。
  7. イミディエートはオプションであり、さまざまなサイズのバイト(バイト、ワード、ロング)から構築された一般的な数値として使用されます。

形式は次のようになります。

/-------------------------------------------------------------------------------------------------------------------------------------------\
|*Prefixes | *Mandatory Prefix | *REX Prefix | Opcode Bytes | *ModR/M | *SIB | *Displacement (1,2 or 4 bytes) | *Immediate (1,2 or 4 bytes) |
\-------------------------------------------------------------------------------------------------------------------------------------------/
* means the element is optional.

データ構造と復号化フェーズについては https://code.google.com/p/distorm/wiki/diStorm_Internals で説明されています

見積もり:

デコードフェーズ

  1. [プレフィックス]
  2. [オペコードを取得]
  3. [フィルターオペコード]
  4. [オペランドを抽出]
  5. [テキストのフォーマット]
  6. [16進ダンプ]
  7. [デコードされた命令]

各ステップについても説明します。


元のリンクは、歴史的な理由で保持されています。

http://code.google.com/p/distorm/wiki/x86_x64_Machine_Code および http://code.google.com/p/distorm/wiki/diStorm_Internals

22
hannson

アセンブルされた小さなプログラムから始めて、生成されたコードと命令の両方を提供します。 命令アーキテクチャ を使用して参照を取得し、生成されたコードの一部をアーキテクチャ参照で手動で操作します。命令は、inst op op opの非常に典型的な構造であり、オペランドの数はさまざまです。必要なのは、コードの16進数または8進数表現を命令に一致するように変換することだけです。少し遊んでみると分かります。

自動化されたそのプロセスは、逆アセンブラーの中核です。理想的には、内部で(またはプログラムが本当に大きい場合は外部で)命令構造のn配列を構築する必要があるでしょう。次に、その配列をアセンブラー形式の命令に変換できます。

6
Charlie Martin

ロード元のオペコードのテーブルが必要です。

基本的なルックアップデータ構造はトライですが、速度をあまり気にしないのであれば、テーブルで十分です。

基本オペコードタイプを取得するには、beginswith match on the tableを使用します。

レジスター引数をデコードするいくつかの標準的な方法があります。ただし、それらのほとんどを個別に実装する必要がある特殊なケースが十分にあります。

これは教育的なものなので、ndisasmをご覧ください。

4
Joshua

チェックアウトobjdumpソース-これは素晴らしいツールです。多くのオペコードテーブルが含まれており、ソースは独自の逆アセンブラを作成するための素晴らしいベースを提供します。