アセンブラ入門(弊研究室の某課題について考える一日目)

はじめに

弊研究室の某課題について考えるの一日目の記事です。

新しく入ってくる方たちになにとぞ覚えていただきたいのがBoFとかPwnable系の知識だと思うのでそのための入門編のアセンブラ入門です。

なのでx86, x64系の説明になります。

お品書き

アセンブラについて

計算機は機械語(0と1のコード)を実行するがそれを人間にわかりやすくした言語です。大学3年生ならそこらへんはわかってるよねってことで割愛

(注) アセンブラを人に説明する際に

アセンブラを進捗報告で取り扱う際は何のアセンブラなのかを明確にしましょう。アーキテクチャが何なのか、記法は何を使用しているのかを必ず示しましょう。

記法について

x86系のアセンブラにはIntel記法とAT&T記法があります。この記事では基本的にintel記法で説明していきます。

違いはこんな感じ

Intel記法

<命令> <命令先> <命令元>

AT&T記法

<命令> <命令元> <命令先>

レジスタ

CPUにはデータを操作するための変数のようなレジスタと呼ばれるデータを格納する場所がいくつか用意されています。レジスタはCPUの中にあらかじめ決められた個数だけ用意されていて名前とその用途も決まっています。

主要なレジスタの簡単な説明をします。詳しい説明はこちら

後のアセンブラを読んでみようでわからなくなったらここに戻ってきてください。

であとで気づいたんですが32bitでコンパイルしたのでこの記事のレジスタはeがrになってることがあります。ごめんね。

レジスタの名前 用途
EAX 算術計算、返り値の格納
EBX 算術計算に使用される
ECX ループ等の回数を数えるのに使用される
EDX 算術計算、データI/Oに使用される
ESP スタックのトップを指し示す
EBP スタックのベースを指し示す
ESI 書き込み先アドレスを指し示す
EDI 読み込み先アドレスを指し示す
EIP 次に実行するアドレスが入ります

アセンブラの形式を知る

アセンブラには記述方式があります。まずは下を見てください

f:id:kataware8136:20171201173826p:plain

最初に関数のアドレスが存在して、関数が始まるとインデントが下がり、関数の終わりまでそのインデントで記述されています。

次の行からが関数の内容で、左からその命令のアドレス、機械語のバイナリ、アセンブラニーモニックと並びます。

16進の機械語は人間にはわからないので、人間にも多少わかりやすくしたものをニーモニックと呼びます。アセンブラニーモニックはこんな関係です。

アセンブラと書いてあってもニーモニックのことを指している場合もあるので、「ニーモニック」という単語があるんだという認識でいいと思います。

アセンブラ命令を覚える

簡単なアセンブラコード(とC言語のコード)を見て覚えましょう。

objdumpコマンドを使うことでアセンブラを見ることができます。

$ objdump -d ./a.out
//C言語ソース
#include<stdio.h>

int main(void){
 int a = 1;
 int b = 2;
 int c = a + b;

 printf("%d\n", c);

 return 0;
}

//アセンブラのmain部
000000000000064a <main>:
 64a:   55                      push   rbp
 64b:   48 89 e5                mov    rbp,rsp
 64e:   48 83 ec 10             sub    rsp,0x10
 652:   c7 45 f4 01 00 00 00    mov    DWORD PTR [rbp-0xc],0x1
 659:   c7 45 f8 02 00 00 00    mov    DWORD PTR [rbp-0x8],0x2
 660:   8b 55 f4                mov    edx,DWORD PTR [rbp-0xc]
 663:   8b 45 f8                mov    eax,DWORD PTR [rbp-0x8]
 666:   01 d0                   add    eax,edx
 668:   89 45 fc                mov    DWORD PTR [rbp-0x4],eax
 66b:   8b 45 fc                mov    eax,DWORD PTR [rbp-0x4]
 66e:   89 c6                   mov    esi,eax
 670:   48 8d 3d 9d 00 00 00    lea    rdi,[rip+0x9d]        # 714 <_IO_stdin_used+0x4>
 677:   b8 00 00 00 00          mov    eax,0x0
 67c:   e8 af fe ff ff          call   530 <printf@plt>
 681:   b8 00 00 00 00          mov    eax,0x0
 686:   c9                      leave  
 687:   c3                      ret    
 688:   0f 1f 84 00 00 00 00    nop    DWORD PTR [rax+rax*1+0x0]
 68f:   00 

C言語のコードとアセンブラのコード

mov

mov eax ebx

modはsourceをdistにコピーします。mov eax ebxならebxの値をeaxにコピーします。

add

mov eax, 0x5
mov ebx, 0x3
add eax, ebx

addは名前の通り加算します。add eax ebxの時、eaxの値とebxの値を足した結果をeaxに格納します。

eaxebxの値を足すという感じです。引き算も同じ動作になります

sub

subは引き算です。足し算と同じですね。

mov eax, 0x5
mov ebx, 0x3
sub eax, ebx

push

push ebp

pushはスタックに値をpushします。そのままです

pop

pop ebp

ついでにpopです。スタックの値をebpに格納します。

push、popは明日の記事で重要な要素になってきます

DWORD PTR

これが多分初心者が戸惑うものだと思います。DWORD PTRは対象の値(レジスタ)を何バイトとして扱うかということを意味します。

mov DWORD PTR [rbp-0x8],0x2

という文がありますが、rbpのアドレスから8引いた値からDWORD(4バイト)分の場所に0x2をコピーしています。

メモリに値を格納する際、そのメモリアドレスの何バイト分に値を格納するのかがわかりません。ゆえにDWORD PTRで指定しているのです。

そういったものはDWORDの他にもあります。

  • DWORD : 4バイト
  • WORD : 2バイト
  • BYTE : 1バイト

WORD PTR <addr> ならaddrから2バイト分ってことになります。

他の命令について

大体読み方分かったと思うので、わからない命令が出てきたらその都度調べればなんとかなるでしょう

ココとか

アセンブラを読んでみよう

さてでは先ほどのアセンブラを読んでみましょう。下の図と合わせてみるとわかりやすいはず

最初の3行は関数の時に必ずある処理なので次の回で話します。

次の2行ではどうやらメモリに0x10x2mov命令を使ってコピーしています。どうやらint a = 1; int b = 2;っぽいです。

次の4行の3行目にはadd命令があります。そうみてみるとその前の2行ではabの値をレジスタにコピーして、4行目で加算命令をした後にメモリにmov命令を書き込んでいるのでint c = a + b;ですね。

次の塊ではprintf関数を読んでいます。なのでちょっと面倒です(次回詳しく話すところです)、呼んでるなぁってことが分かればいいので飛ばそうと思いましたが説明しますね。飛ばしたい人は飛ばしてどうぞ

最後にreturn命令ですね。ねアセンブラ意外と読めるでしょ。

f:id:kataware8136:20171201184023p:plain

気になる人向けのprintfのブロック

66eアドレスでmov esi, eaxとありますが、その前の行でeaxにはcの値が入っています。なのでesiレジスタにはprintfの第二引数を入れておきます。

670アドレスでmov rdi, [rip+0x9d]とありますがprintfの第一引数はrdiレジスタに入ります。[rip+0x9d]"%d\n"があるってことですね。

これでprintfを呼ぶことによってcの値が表示されるってことになります。

関数を呼ぶときは引数を規則に従ってレジスタに叩き入れます。参照

レジスタ 引数
edi 第一引数
esi 第二引数
edx 第三引数
ecx 第四引数

最後に

この記事読んでアセンブラってそんなに難しそうじゃないなと感じていただければ幸い、

明日は関数の仕組み系統について書きます。力尽きなければ

参考文献

  • 熱血アセンブラ入門
  • 楽しいバイナリの歩き方
  • セキュリティコンテストプログラミングブック
  • Binary Hacks
  • HACKING 美しき策謀