今回から、何記事かにわたってアセンブラ言語について書いていきたいと思います。少し前に、マルウェアの分析を初めて1本記事を書いたのですが、
マルウェアの挙動の分析をしていてアセンブラがわからなくて悔しい部分があったのでアセンブリ言語について勉強しようと思いました。
まず、最初に
頭の片隅に置いておくと理解がすすむもの
・バイト→ビット ×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言語での基本的な代入・ポインタを知っていれば理解できそうです。
次の記事では実践的なアセンブラ言語の使い方について書いていきます!