Capture The Frog

かえるぴょこぴょこw

MENU

アセンブリ言語入門 その1

今回から、何記事かにわたってアセンブラ言語について書いていきたいと思います。少し前に、マルウェアの分析を初めて1本記事を書いたのですが、

qwertytan.hatenablog.jp

マルウェアの挙動の分析をしていてアセンブラがわからなくて悔しい部分があったのでアセンブリ言語について勉強しようと思いました。

 

まず、最初に

頭の片隅に置いておくと理解がすすむもの

・バイト→ビット ×8
・ビット→バイト /8
アセンブリとは、マシンコードをアセンブリコードに変換すること

x86 CPUには、8つの汎用レジスタがある。
 EAX・EBX・ECX・EDX・ESP・EBP・ESI・EDI
 これらは全て32ビット(4バイト)のサイズ
 プログラムは、これらのレジスタに32(4バイト),16(2バイト),8(1バイト)ビットの値と         

 してレジスタにアクセスすることができる。


・各レジスタの下位16ビット(2バイト)には
 AX・BX・CX・DX・SP・BP・SI・DI
 これらは、全て16ビットだから16,8ビットの値として、プログラムはレジスタにアク 

 セスできる。
 後で、アセンブリ命令の格納先として出てくるので理解しとく。

 

・ちなみにc言語だと
 1バイト   char
 2バイト   short int
 4バイト   int
         long int

         float
   float(浮動小数点は、EAXなどの汎用レジスタではなく)浮動小数レジスタ(sd・snが

   使用される。 
   8バイト         double
                         long double

  となっている。


・リトルエンディエン方式とは、

 下位バイトは下位アドレスに格納され、後続のバイトはメモリ内の連続した上位アド 

 レスに格納される。
 「リトルエンディエン方式とは、データをバイト単位で並べる際のやりかたの一つ

 で、「最後」のバイトから順番にデータを並べる方式のこと」

  https://wa3.i-3-i.info/word11428.htmlより引用

 

・実行する操作を指定する部分を"オペコード"という
 そして、操作される対象を"オペランド"と呼ぶ

 オペランド デスティネーション, ソース
 命令    格納先,  格納元

 みたいな感じ。
 今回は、デスティネーション(格納先)を先に書くやり方で書いていく。

 この書式をIntel Syntaxと呼ぶ。MASM・NASMで採用されている。


・;の後は、コメント文

 

アセンブリ命令

mov命令

mov dst, src
この命令はデータを格納元から格納先へ移動する。
Cとかの代入に似ている。

レジスタへの定数の格納

movの最初のバリエーションは、定数(コード中に直接書かれた値をレジスタへ格納する例。

mov eax, 30 ;eax=30という代入操作と同じで、30をEAXレジスタに代入する。
mov bx, 7 ;bx=7とおなじ
mov eax, 64h ;16進数の64h(100)をEAXに代入

 

レジスタからレジスタへの値の移動

mov eax, ebx ;EAXの値をEBXに代入する。EAX=EBXと同じ

実践
mov eax, 20
mov ebx, eax
さあ、EBXはいくつでしょう。
eax=20
ebx=eaxなので、EBXは20となる。

 

 

メモリからレジスタへの値の移動

アセンブリ言語でメモリからレジスタに値を移動するには、値のメモリアドレスが必要。
値はメモリにリトルエンディエン方式で格納されている。
メモリアドレスはの中にいれて表す。
そして、その
の番地だけを指しているのではなくて、その番地からはじまるデータ全体を指す。

メモリアドレス

0x403204
0x403203 00
0x403202 00
0x403201 00
0x403200 64

mov eax, [0x403200]
これは、メモリアドレスに代入されているデータ全体を指すから、
eaxには、00 00 00 64が代入される。

そして、4バイトだということをオペコード、オペランドで指定する必要がないことに注目
格納先のレジスタのサイズに基づいて移動するバイトが自動的に決まる。

 

 

内が、レジスタ・レジスタ+レジスタ・レジスタ+定数の場合

Cのポインタみたいな働きをする。内がポインタ
全て[]内に指定されたメモリアドレスに格納されている値をレジスタに移動する命令コード

mov eax, [ebx] ;EBXレジスタで指定されたレジスタの値をEAXに格納している。
mov eax, [ebx+ecx] ;EBX+ECXで指定されたアドレスの値をEAXに格納している。
mov eax, [ebp-4] ;EBP-4で指定されたレジスタで指定されたアドレスの値を EAXへ格納する。

 

レジスタからメモリへの値の移動

メモリアドレスをデスティネーションに置き、レジスタをソースにすることで
メモリにレジスタの値を書き込む。

mov [0x403200], eax ;0x403200から始まるメモリ位置にeaxの4バイトの値を格納
mov [ebx], eax ;eaxの4バイトの値をebxで指定したメモリアドレスに格納

 

dword ptr・word ptr

これらのメモリは定数値をメモリ内に格納する命令
dword ptrは、dword値(4バイトの値をメモリ内に移動する。
word ptrは、word値(2バイトの値をメモリに移動する。

mov dword ptr [40200], 13498h ;dword値0x13498を0x40200へ格納する。
mov dword ptr [ebx], 100 ;dword値100をebxが指すメモリアドレスへ格納する。
mov word ptr [ebx], 100 ;word値をebxが指すメモリアドレスへ格納する。

 

 

 

LEA命令

LEAとは、Load Effictive Address,(有効なアドレスを読み込むの略称。
値の代わりにアドレスを読み込む。

lea ebx, [0x403200] ;アドレス0x43200をEBXに格納する。
lea eax, [ebx] ;EBXに0x43200が格納されていた場合、EAXにも0x43200が格納される。

 

 

今回は、レジスタとメモリアドレスの代入について書いてきました。

代入は、C言語での基本的な代入・ポインタを知っていれば理解できそうです。

次の記事では実践的なアセンブラ言語の使い方について書いていきます!

qwertytan.hatenablog.jp