Upload
slankdev
View
45
Download
0
Embed Size (px)
Citation preview
アセンブラを入門した話
slank( すらんく )
以下のアセンブラを読み解きます
seccamp2015 の問題です
コードをいくつかのブロックに分割関数に入る初期作業
関数を出る作業
for 文の作業
for 文の中身
関数に入る初期作業push %esipush %ebxmov 0x0c(%esp), %ebxmov 0x10(%esp), %ecx
push 命令はスタックにレジスタを格納して、スタックポインタの値を減らす。esi 、 ebx の順にスタックにプッシュしている。
mov 命令は、値をコピーする。( スタックポインタのアドレス値 +0x0c) の中身 (function 関数の第 1 引数 array) を ebx にコピー( スタックポインタのアドレス値 +ox10) の中身 ( 関数の第 2 引数 n) を ecx にコピー
move
move
初期状態のスタック 処理後のスタック
( スタック=関数スタック ) とする
n
&array
for 文の作業test %ecx, %ecxjle 26 <function+26>
test 命令で ecx の値を調べる、 ecx and ecx の結果をフラグレジスタに反映させる。jle 命令で、 ecx!=0x0 だったら for 文に入らずループ後にジャンプする。
for(i=0; i<n; i++){} の赤字部分をチェックしている。
C 言語に直訳 すると for(i=0; i<n; i++){}
for 文の作業mov %ecx, %esimov $0x00, %edxmov $0x00, %eax
mov 命令で、 ecx を esi に、 0x00 を edx,eax に代入。eax は C 言語のコードでの変数 i に相当。 ecx はnに相当。esi は n のコピーとして、 edx は配列に値を代入するときに使用される。
C 言語に直訳 すると for(i=0; i<n; i++){}
0x00
i=0x00
nn
&array
for 文の中身mov %edx, (%ebx, %eax, 4)
0x00
i=0x00
nn
&array
スタックとレジスタ array の示すメモリ領域
(ebx, eax, 4)=(ebx の示すアドレス )+4*(eax の値 )なので、 array[i] のことである。array[i] に edx の値を代入する。現在は edx=0x00 だが、 for ループが回るにつれてこの後 edx が変化していく。
C 言語の array[i]=i*n に相当している。
0x00
for 文の作業add $0x01, %eaxadd %esi, %edx
n
i=0x01
nn
&array
スタックとレジスタ array の示すメモリ領域
0x00
add 命令で、eax = eax + 1 ( for(i=0; i<n; i++) に相当 )edx = edx + esi の処理をする。
edx には、 esi( n ) を追加する動作を行って、array[i] = edx にそなえる。
加算
for 文の作業
cmp %ecx, %eaxjne 1a <function+1a> 比べる
フラグレジスタcmp 命令で ecx と eax を比較して比較結果をフラグレジスタに入力jne 命令で、 ecx != eax (i != n) なら <function+1a> すなわち for 文内部の命令部にジャンプする。そうでない場合は、 for ループを抜けて次の命令に進む。
ni=0x01
関数を出る作業pop %ebxpop %esiret
pop 後のスタックpop 前のスタック
pop 命令で、スタックに格納されていたメモリ領域を解放します。
その後 ret 命令で、関数を抜け出します。ret 命令では、スタックに積まれたリターンアドレスを pop して、そのアドレスに jump をする。
push 命令にに対しての pop 命令のように、 ret 命令は、 call 命令と対になっている。
関数を呼び出すとき関数を呼び出すときに、 CPU は、関数スタックを用意して、関数実行前に引数、リターンアドレス、を格納する。という規約が存在するが、処理系によっては、関数の引数を直接レジスタに格納することもある。 (cdecl だったり、 Register だったり。。 )
関数の引数は、 call 命令の前に、レジスタに格納している。(どんな規則でレジスタを選んでいるかはわからなかった。)