SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Windows実行ファイル「EXE」の謎に迫る

x86系CPUのネイティブコードを解析する

Windows実行ファイル「EXE」の謎に迫る 第5回


  • X ポスト
  • このエントリーをはてなブックマークに追加

ネイティブコードの構造

 基礎的なアセンブラ命令を説明したところで、早速ネイティブコードの構造を突き詰めていきましょう。x86は拡張命令用のビットなどが用意されているため、すべてが統一されたフォーマットで表現できるわけではありません。まずは一般的なネイティブコードの構造から紹介していきます。

一般的なネイティブコードフォーマット
一般的なネイティブコードフォーマット
  • 命令プリフィックスは、16ビット演算の場合や拡張命令を指定したいときなど、少し特殊な場合に使用します。32ビット演算のmovaddsubなどの単純な命令のときは省略されることがほとんどです。
  •  
  • オペコードには命令を識別するための値を指定します。
  •  
  • ModR/M、SIBにはレジスタ・メモリを参照する際のアドレッシングモードを指定します。詳細は後述します。
  •  
  • ディスプレースメント、即値には8ビット~32ビットの値を指定できます。

 これらの各要素はオペコードの種類、アドレッシングモードの状態により、省略されることがあります。

アドレッシングモード

 アドレッシングモードはx86のオペコードを理解する上で一番重要なポイントであり、最も複雑なポイントであるとも言えます。mov eax,ecxなど、レジスタ間のやり取りだけであれば比較的簡単な機械語フォーマットになっているはずですが、x86では、下記のようなケースにも対応しなければなりません。

mov eax,dword ptr[ecx]
mov eax,dword ptr[ecx+edx]
mov eax,dword ptr[0x00400000]
mov eax,dword ptr[0x00400000+ecx]

 そこで登場するのがアドレッシングモード「ModR/M」および「SIB」です。ModR/Mは8086の時代からありましたが、SIBはx86が32ビット化されたときに追加された機能です。アドレッシングモード自体が拡張されているので、そのフォーマットは残念ながら汚くなるはずです。

ModR/M

 ModR/Mではレジスタ・メモリのモードを指定します。1バイトで表現され、各ビットは下記の図のような意味を持ちます。

ModR/Mのビットフィールド(1バイト)
ModR/Mのビットフィールド(1バイト)

 まずは先頭のModビットから説明します。2ビットなので4種類のフラグを表現でき、それぞれ下記のような意味づけがされています(※実効アドレスを指定した場合はそのアドレスに書き込まれている値が評価されます)。

Modビット
意味
00 レジスタのみで実効アドレスを指定するモード。
01 レジスタおよび8ビットのディスプレースメントで実効アドレスを指定するモード。
10 レジスタおよび32ビットのディスプレースメントで実効アドレスを指定するモード。
11 レジスタ値を指定するモード。

 Reg/Opecodeビットおよびr/mビットは機械語の種類により、意味が異なります。独自のオペコードが指定されることがありますが、一般的には下記のようにレジスタを表すことが多いです。

Reg/Opecodeビットおよびr/mビット
意味
000 eax(またはalaxmm0xmm0
001 ecx(またはclcxmm1xmm1
010 edx(またはdldxmm2xmm2
011 ebx(またはblbxmm3xmm3
100 esp(またはahspmm4xmm4
101 ebp(またはchbpmm5xmm5
110 esi(またはdhsimm6xmm6
111 ebi(またはbhdimm7xmm7

SIB

 SIBとはscale(スケール)、index(インデックスレジスタ)、base(ベースレジスタ)の略です。ModR/Mだけでも32ビットのアドレス空間を扱うことができるのですが、SIBバイトを活用すると下記のような複雑なアドレス指定を表現できるようになります。

mov eax,dword ptr[ecx+edx*4]
mov eax,dword ptr[0x00400000+ecx+edx*4]

 SIBバイトは1バイトで表現され、各ビットは下記の図のような意味を持ちます。

SIBのビットフィールド(1ビット)
SIBのビットフィールド(1ビット)

 indexはインデックスレジスタ、baseはベースレジスタのことを示します。レジスタの識別コードは、先ほどr/mの説明で出てきたものと同様です。scaleにはスケール(インデックスレジスタの値×スケール)を指定します。スケールのビット内容は下記のようになります。

スケールのビット内容
説明
00 スケールは1
01 スケールは2
10 スケールは4
11 スケールは8

実際のネイティブコードを解析してみよう

 お察しの通り、ネイティブコードのフォーマットは非常に複雑な内容となっています。いきなりすべてを理解するのは大変なので、実際のネイティブコードをビット単位で解析し、一つ一つの機械語がどのような意味を持つビットで構成されているのかを調べてみましょう。

アセンブラコードの例
mov eax,1
mov ecx,2
add eax,ecx
mov dword ptr[edx],eax

 1+2の演算結果を、edxが示すアドレスに書き込むだけの単純なプログラムです。このアセンブラは下記のようなネイティブコードと対になります。

ネイティブコードの例
    10: mov eax,1
004113AE B8 01 00 00 00    mov       eax,1
    11: mov ecx,2
004113B3 B9 02 00 00 00    mov       ecx,2
    12: add eax,ecx
004113B8 03 C1             add       eax,ecx
    13: mov dword ptr[edx],eax
004113BA 89 02             mov       dword ptr [edx],eax

 それでは、1行目のmov eax,1から見ていきましょう。この命令のポイントは下記のようになります。

  • 命令プリフィックスは無し
  • オペコード(即値からレジスタへのmov)は10111(2)である
  • レジスタがeaxであるというのはオペコードバイト内で指定されている
  • 32ビットの即値が付加されている

 既にお気づきの方もいるかとは思いますが、この一つの命令の意味を構成するのは、実は1バイト目の0xB8なのです。後に続く4バイトは即値である1を示しています。即値がリトルエンディアン形式で指定される点にも注意しておきましょう。

 先頭バイトの0xB8は下記の図のような構成になっています。

オペコードフィールド:「0xB8」の意味
オペコードフィールド:「0xB8」の意味

 この命令の場合はレジスタと即値のみを扱うため、アドレッシングモードを指定する必要はありません。レジスタを識別するための値は、オペコード内の2~0ビットに保持されます。

 2行目のmov ecx,2も上記の内容とまったく同じです。レジスタを示す値と即値の内容が変わっただけです。

 3行目のadd eax,ecxはどのような構造なのでしょうか? レジスタ-レジスタ間ということで、単純なアドレッシングモードが要求されることになります。0x03、0xC1は下図のような構成からなる値です。

オペコードフィールド:「0x03」「0xC1」の意味
オペコードフィールド:「0x03」「0xC1」の意味

 4行目のmov dword ptr[edx],eaxは0x89、0x02というネイティブコードに変換されていますが、同じく、下図のような構成からなります。

オペコードフィールド:「0x89」「0x02」の意味
オペコードフィールド:「0x89」「0x02」の意味

次のページ
ネイティブコード生成モジュールを作ってみよう

修正履歴

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
Windows実行ファイル「EXE」の謎に迫る連載記事一覧

もっと読む

この記事の著者

山本 大祐(ヤマモト ダイスケ)

普段はActiveBasicと周辺ツールの開発を行っています。最近は諸先輩方を見習いながら勉強中の身。AB開発日記

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/420 2010/04/19 10:10

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング