教育プロジェクトとしてx86逆アセンブラを書くことに興味があります。
私が見つけた唯一の本当のリソースは、スパイラルスペースの「 逆アセンブラーの書き方 」です。これにより、逆アセンブラのさまざまなコンポーネントについてのナイスな高レベルの説明が得られますが、さらに詳細なリソースに興味があります。私も NASM's ソースコードをざっと見てみましたが、これは学ぶのがやや重いです。
このプロジェクトの主要な課題の1つは、処理する必要があるかなり大きなx86命令セットであることを理解しています。基本的な構造、基本的な逆アセンブラリンクなどにも興味があります。
X86逆アセンブラの記述に関する詳細なリソースを誰かに教えてもらえますか?
80386プログラマーズリファレンスマニュアル の セクション17.2 をご覧ください。逆アセンブラーは、実際には美化された 有限状態マシン です。分解の手順は次のとおりです。
F3
、F2
、またはF0
);もしそうなら、あなたはREP
/REPE
/REPNE
/LOCK
接頭辞を持っています。次のバイトに進みます。67
)。その場合、現在32ビットモードの場合は16ビットモードで命令の残りの部分のアドレスをデコードし、現在16ビットモードの場合は32ビットモードでアドレスをデコードします。66
)。その場合、現在32ビットモードの場合は16ビットモードで即値オペランドをデコードし、現在16ビットモードの場合は32ビットモードで即値オペランドをデコードします。2E
、36
、3E
、26
、64
、または65
)。その場合、デフォルトのセグメントレジスタの代わりに、アドレスのデコードに対応するセグメントレジスタを使用します。0F
、それは拡張オペコードであり、次のバイトを拡張オペコードとして読み取ります。オペコードは、実行されている操作を通知します。オペコードの引数は、Mod R/M、SIB、変位、および即値の値からデコードできます。 x86の複雑な性質により、多くの可能性と多くの特別なケースがあります。詳細な説明については、上記のリンクを参照してください。
私はいくつかのオープンソースの逆アセンブラー、できれば distorm をチェックすることをお勧めします。
ドキュメント自体は、オペコードと命令に関するジューシーな情報でいっぱいです。
引用元https://code.google.com/p/distorm/wiki/x86_x64_Machine_Code
80x86命令:
80x86命令は、いくつかの要素に分割されます。
- 命令のプレフィックスは、命令の操作の動作に影響を与えます。
- SSE命令のオペコードバイトとして使用される必須のプレフィックス。
- オペコードバイトは、1バイト以上(最大3バイト)の場合があります。
- ModR/Mバイトはオプションであり、オペコード自体の一部を含む場合があります。
- SIBバイトはオプションであり、複雑なメモリ間接形式を表します。
- 変位はオプションであり、さまざまなサイズのバイト(バイト、ワード、ロング)の値であり、オフセットとして使用されます。
- イミディエートはオプションであり、さまざまなサイズのバイト(バイト、ワード、ロング)から構築された一般的な数値として使用されます。
形式は次のようになります。
/-------------------------------------------------------------------------------------------------------------------------------------------\ |*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 で説明されています
見積もり:
デコードフェーズ
- [プレフィックス]
- [オペコードを取得]
- [フィルターオペコード]
- [オペランドを抽出]
- [テキストのフォーマット]
- [16進ダンプ]
- [デコードされた命令]
各ステップについても説明します。
元のリンクは、歴史的な理由で保持されています。
http://code.google.com/p/distorm/wiki/x86_x64_Machine_Code および http://code.google.com/p/distorm/wiki/diStorm_Internals
アセンブルされた小さなプログラムから始めて、生成されたコードと命令の両方を提供します。 命令アーキテクチャ を使用して参照を取得し、生成されたコードの一部をアーキテクチャ参照で手動で操作します。命令は、inst op op opの非常に典型的な構造であり、オペランドの数はさまざまです。必要なのは、コードの16進数または8進数表現を命令に一致するように変換することだけです。少し遊んでみると分かります。
自動化されたそのプロセスは、逆アセンブラーの中核です。理想的には、内部で(またはプログラムが本当に大きい場合は外部で)命令構造のn配列を構築する必要があるでしょう。次に、その配列をアセンブラー形式の命令に変換できます。
ロード元のオペコードのテーブルが必要です。
基本的なルックアップデータ構造はトライですが、速度をあまり気にしないのであれば、テーブルで十分です。
基本オペコードタイプを取得するには、beginswith match on the tableを使用します。
レジスター引数をデコードするいくつかの標準的な方法があります。ただし、それらのほとんどを個別に実装する必要がある特殊なケースが十分にあります。
これは教育的なものなので、ndisasmをご覧ください。
チェックアウトobjdumpソース-これは素晴らしいツールです。多くのオペコードテーブルが含まれており、ソースは独自の逆アセンブラを作成するための素晴らしいベースを提供します。