アセンブリ言語について

※筆者、かなり頭が緩い人なので誤謬とかコメントで指摘してもらえるとすごーい助かります

コンピューターは、その内部においてCPU(Central Process Unit)が脳の役割を果たしている。このCPUが、RAMっていう記憶領域（たしかstatic RAM(SRAM) と　Dynamic RAM(DRAM)があったはず）を持っていて、より頻繁に使うデータは SRAMとかにキャッシュさせておいてその他は DRAMにおいておく、つまりここにメモリってものがある。

ちなみに、このRAMってのはふつうにデータをぽんぽんおいていくとぷよぷよみたいな虫食い状態になるんで、それをきれいに整列して無駄なくしてくれる allocator（アロケータ）ってのがある、一般的にLinuxとかだと Slab allocatorが使われている。はず。

まあ何がいいたいかというとこの過程でコンピュータがどうやってこれを作業しているかっていうと、コンピューターは結局大量のスイッチとゲート(XOR, OR, AND, NAND...)の集まりなので、このスイッチに電荷が入っている状態とそうでない状態、で (0, 1)と表現される。なので、例えば 16ビットのメモリの場合

```
0100 1000 0110 0001
```

みたいになる。ちなみに、この01の集まりも

命令関数、データ、宣言データ、ヒープ、スタック、引数（ないし環境変数）

みたいな順番に並んでいる。

text, data, bss, heap, stack, ... みたいなふうに呼ばれている。

bss（宣言データ）とdata（データ） の違いは、bssは宣言されているだけで初期化されていないデータ、後者は初期化がなされているデータ。Cとかだと、

```
int i, j, k;  // bss

int i = 0; // data
```

のようなかんじだ。

で話が脇道にそれてしまったけれど、結局アセンブリ言語をより知っていくとハードウェアの仕組みや考え方がよりしっくりわかるというのが一つ（そしてハードウェアを理解すればするほど、いざという時の応用がきく。。。と思っている）

また、いわゆるリバースエンジニアリングみたいなのができる可能性が高まる。もちろん一般的にマルウェアとかは難読化が施されている場合もあるけど、それでもそれを打開するツールとかはあるし。

例えば会社から強制的に入れられているツールがどういう悪さをしているか。スクリーンキャプチャとかとって送っているのか。だとしたら、マルウェアじゃん。。。みたいな判断もおそらくは、基本バイナリを解析しなければ、すなわちそれはバイナリファイルに対して例えば otool かましてその結果吐かれたインストラクションを追っかけていくことになるんじゃないか。と。

まあ能書きはこれくらいにして。

簡単なサンプルを。

```
extern print16b
extern prinf
section .data
string1 db "xxxxxxxxxxxxxxx"
        db "yyyyyyyyyyyyyyy"
        db "zzzzzzzzzzzz", 10, 0
string2 db "zzz", -
NL      db 10, 0
fmt     dn "qqqqqqqqqqqqq", 10,0
section .bss
section .text
    global main
main:
push rbp
mov rbp, rsp
mov rdi, fmt
mov rsi, string2
xor rax, rax
call prinf
....
```

今回はさわりだけ紹介したいのでここまでにするけれど、extern print16b というのはこれは外部モジュールのインポートで（.asmか.c）これは他の言語と変わらない。

その後 section .data みたいに書かれているところで今から下のエリアが変数の定義ですよ、と述べている。

すなわち、

```
string1 db "xxxxxxxxxxxxxxx"
        db "yyyyyyyyyyyyyyy"
        db "zzzzzzzzzzzz", 10, 0
string2 db "zzz", 10, 0
```

この場合 string1 という名前の byte長（8bit）(b) の データ(d) （この二つの頭文字をとって db)は、"xxxxxxxxxxxxxxx" 、"yyyyyyyyyyyyy"、”zzzzzzzzzz” という文字列の配列ですよ、と。(たしか....)

そして、string2 は　zzz という文字列変数ですよ、と。

NLは10進数で10でこの箇所がnullに相当する、ということを示している　(10進数だと 0xa）、

そして、section .bss では初期化をしない変数が今回は定義されていないのでブランク、

section .text 以下はコードセクションとなる（ここらへんの書き方は COBOLっぽい）

```
push rbp
mov rbp, rsp
```

これは、rbp(ベースポインタ）をまずスタック（メモリ上の自由に使えるように定義されているカゴ）にpushして、その後rsp(スタックポインタ）のアドレスをrbpにコピーしている。これは直前までのセーブデータを今あるカーソルにロードするイメージだろうか（間違ってたらごめんなさい！！！）

これは例えば一つの関数の呼び出しから別の関数に移動する場合などに、それぞれ今自分（カーソル）がどこにいるんだっけ、というのを引き継ぐ必要があって、いわゆる普通のプログラミング言語のエラーとかのスタックでどこのモジュールでどこの関数のどこの行でエラーになったか過去のスタックが全部追えるのはこれのおかげ.... (これをスタックに保存しているおかげ...） だったはず。だがちょっとうろおぼえなのであやしい

さて、著者のにわかっぷりが露呈したところで最後の部分だが、

```
mov rdi, fmt
mov rsi, string2
xor rax, rax
call prinf
```

これは　(1) rdiレジスタに fmtと定義された変数をコピー。(2) string2と定義された変数を　rsiレジスタにコピー。(3) raxを０に初期化（xor演算子は 0-1, 1-0 以外の組み合わせ、すなわち 0-0, 1-1 は　０にするので、値の高速な０初期化としてよく使われる）

その後　call printf は　prinf という関数を呼び出すかんじである、ちなみに注意すべきは、これ、直前の rdi, rsi, rax レジスタというのが暗黙に引数になっているんで、

Cで考えると

```
printf(rsi, rdi, rax) ;
```

みたいなイメージである。（そしてこの関数の中身でrsi, rdi
, raxが登場する）

他にも ZF(zet flag) PFなどのフラグを、プリセットのmnemonic(関数）がそれぞれどんな条件でどう変えるかというのが厳密に定義されていて、その隠れた（明示されていない）暗黙の変数の値をもとに条件式が組まれ、いろんなところに飛ぶ。たとえば、

```
pcmpistrm xmm1, xmm2, 01001100b
setz cl
cmp cl, 0
je .gotoprint
```


このようなくだりは、

1. xmm1レジスタ（浮動小数点とか（配列とか）大きな量を要する場合に使う）の中にxmm2 レジスタに格納されている値(substring)がないかどうかみてね、で、この01-00-11-00 という最後の引数がこの pcmpistrmにどういう挙動をしてほしいか、関数の詳細を定義させている。（詳細はここでは省くが、部分一致か、全体一致か、一致した場合に何をしてほしい、など）

2. setz は、直前のpcmpistrm　でZF（ゼットフラグ）がセットされていた場合、この引数に当たる cl (rcxの下位8bit）に１をセットしてね、ZFがセットされてなかったら clは０にしてね、みたいな条件による代入のdispatchである。

3. そして、cmpは　cmp <引数１> <引数２>　で引数１と２を比較し、等しければZFを１、そうでなければ０（だったはず。。。）にする。

で、最後に je というのはこのZFが１の場合はその引数である　.gotoprint という関数にジャンプ（飛んで）ね、そうでなければ無視して下いってね、という支持である。

なんか昔ドラクエの本ゲームみたいなのがあったけどあれに感覚が近いか。。。




いずれにせよこんなかんじでしちめんどうくさく、冗長にもほどがあるだろっていう言語だけれども、バイナリの解析にとって不可欠といって差し支えないし（少なくとも当面は）高級言語では絶対に身につかない考え方を取得することができる、







そんなはなしでした。