最も簡単な逆アセンブル(構造体)

最も簡単な逆アセンブル(ポインタ) - あしのあしあと」の続き。今回は(小さな)構造体を扱ってみる。

typedef struct {
    int price; int number; int tax;
} payment;

int totalAmount(payment *p)
{
    return p->price * p->number + p->tax;
}

int main(void)
{
    payment pc;
    pc.price = 2000;
    pc.number = 3;
    pc.tax = 100;

    return totalAmount(&pc);
}

アセンブルして出力されたコードは、次の通り。さすがに、いっつも同じである「前処理」と「後処理」は飽きた。重要な箇所だけ抜粋する。余計な情報は、だんだん削っていこう。
まずは、main 関数。前処理が終わって、totalAmount 関数を呼び出すところまで。(11) 〜 (13) 行目で、構造体に値を入れている。(14) 行目で、構造体の先頭のアドレス(ポインタ)を取得して、(15) 行目でスタックにのっける。

(11) mov         dword ptr [ebp-10h],7D0h
(12) mov         dword ptr [ebp-0Ch],3
(13) mov         dword ptr [ebp-8],64h
(14) lea         eax,[ebp-10h]
(15) push        eax
(16) call        00151361

次に、totalAmount 関数。main 関数でスタックしてくれた構造体のポインタを用いて、(14) 行目でかけ算、(15) 行目で足し算を行っている。

(11) mov         eax,dword ptr [ebp+8] ; EAX ← 00D7FE98
(12) mov         ecx,dword ptr [ebp+8] ; ECX ← 00D7FE98
(13) mov         eax,dword ptr [eax]   ; EAX ← 000007D0
(14) imul        eax,dword ptr [ecx+4] ; [ECX+4] = 7D0h
(15) mov         edx,dword ptr [ebp+8] ; EDX ← 00D7FE98
(16) add         eax,dword ptr [edx+8]

一応、スタックの状態を図示しておくか。最近、物忘れがはげしいから。

左が、main 関数が終わるときのスタックの様子。右は、totalAmount 関数の前処理が終わったときのスタックの様子。