2015年12月31日
main関数を覗いてみる
アセンブラの勉強の続き
前回、逆アセンブラしたC++で書いたコードのexeファイル。
もともとのC++のコードは下記のような感じ。
#include
void swapptr(char **x, char **y)
{
char *temp = *x;
*x = *y;
*y = temp;
}
int main(void)
{
char *a = "ABC";
char *b = "123";
printf("a = %s\n", a);
printf("&a = %p\n", *a);
printf("b = %s\n", b);
printf("&b = %p\n", *b);
swapptr(&a, &b);
printf("a = %s\n", a);
printf("&a = %p\n", *a);
printf("b = %s\n", b);
printf("&b = %p\n", *b);
return (0);
}
swapptr関数部分は下記のサイトの内容を基にしている。
>二つのポインタ値を交換する関数はどのように実現すればよいでしょうか。
>http://www.bohyoh.com/CandCPP/FAQ/FAQ00024.html
printf関数部分の*aとか&aとかよくよく見ると「ポインタのポインタ」を使ってから
どれが何だか分からなくなってきたのでたぶん表示が間違っているかも。
(そこらへんはご容赦)
前回の記事でswapptr関数部分の逆アセンブラしたコードは載せたが、
それだけじゃぜんぜんVBでポインタの付け替えができるようになる気がしない。
もう少しアセンブリ言語に詳しくならなくては!
main関数部分を逆アセンブラした結果を下記に示す。
push rbp
push rdi
sub rsp,128h
lea rbp,[rsp+20h]
mov rdi,rsp
mov ecx,4Ah
mov eax,0CCCCCCCCh
rep stos dword ptr [rdi]
mov rax,qword ptr [__security_cookie]
xor rax,rbp
mov qword ptr [rbp+0F8h],rax
lea rax,[??_C@_03FFFJFKND@ABC?$AA@]
mov qword ptr [rbp+8],rax
lea rax,[??_C@_03EFKIOLOJ@123?$AA@]
mov qword ptr [rbp+28h],rax
mov rdx,qword ptr [rbp+8]
lea rcx,[??_C@_07LLAODNH@a?5?$DN?5?$CFs?6?$AA@] ; メモリからrcxレジスタに移動
call @ILT+460(printf) ; printf関数の呼び出し
mov rax,qword ptr [rbp+8]
movsx eax,byte ptr [rax]
mov edx,eax
lea rcx,[??_C@_08HLDGGNGA@?$CGa?5?$DN?5?$CFp?6?$AA@] ; メモリからrcxレジスタに移動
call @ILT+460(printf) ; printf関数の呼び出し
mov rdx,qword ptr [rbp+28h]
lea rcx,[??_C@_07IFDPOEDE@b?5?$DN?5?$CFs?6?$AA@] ; メモリからrcxレジスタに移動
call @ILT+460(printf) ; printf関数の呼び出し
mov rax,qword ptr [rbp+28h]
movsx eax,byte ptr [rax]
mov edx,eax
lea rcx,[??_C@_08PFLJGKID@?$CGb?5?$DN?5?$CFp?6?$AA@] ; メモリからrcxレジスタに移動
call @ILT+460(printf) ; printf関数の呼び出し
lea rdx,[rbp+28h]
lea rcx,[rbp+8]
call @ILT+10(?swapptr@@YAXPEAPEAD0@Z) ; swapptr関数の呼び出し
mov rdx,qword ptr [rbp+8]
lea rcx,[??_C@_07LLAODNH@a?5?$DN?5?$CFs?6?$AA@] ; メモリからrcxレジスタに移動
call @ILT+460(printf) ; printf関数の呼び出し
mov rax,qword ptr [rbp+8]
movsx eax,byte ptr [rax]
mov edx,eax
lea rcx,[??_C@_08HLDGGNGA@?$CGa?5?$DN?5?$CFp?6?$AA@] ; メモリからrcxレジスタに移動
call @ILT+460(printf) ; printf関数の呼び出し
mov rdx,qword ptr [rbp+28h]
lea rcx,[??_C@_07IFDPOEDE@b?5?$DN?5?$CFs?6?$AA@] ; メモリからrcxレジスタに移動
call @ILT+460(printf) ; printf関数の呼び出し
mov rax,qword ptr [rbp+28h]
movsx eax,byte ptr [rax]
mov edx,eax
lea rcx,[??_C@_08PFLJGKID@?$CGb?5?$DN?5?$CFp?6?$AA@] ; メモリからrcxレジスタに移動
call @ILT+460(printf) ; printf関数の呼び出し
xor eax,eax
mov edi,eax
lea rcx,[rbp-20h]
lea rdx,[140019CC0h]
call @ILT+310(_RTC_CheckStackVars) ; _RTC_CheckStackVars関数の呼び出し
mov eax,edi
mov rcx,qword ptr [rbp+0F8h]
xor rcx,rbp
call @ILT+730(__security_check_cookie) ; __security_check_cookie関数の呼び出し
lea rsp,[rbp+108h]
pop rdi
pop rbp
ret
callコマンドで関数を呼び出しているのか、、
後半、printf関数が4回使われて、swapptr関数が使われて
再度、printf関数が4回使われていることが分かる。
あと、最後に知らん関数が2つ使われている。
printf関数の1つ前にいつもleaコマンドがある。
leaはmovに似ているらしい。
>むむむ雑記 MOVとLEAを比較
>http://mumumu-pg.hatenablog.com/entry/2014/07/20/204952
メモリからレジスタへの移動。
何を移動しているんだろう。
最後のpopはスタックからデータを読み込むコマンド。
>IT pro【5分で覚えるIT基礎の基礎】だれでも一度はアセンブラを学んでおこう! 第2回
>http://itpro.nikkeibp.co.jp/members/ITPro/ITBASIC/20021220/1/?rt=nocnt
スタックとは調べると
「最後に入力したデータが先に出力されるという特徴をもつ、データ構造の一種」
後入れ先出しの構造。
よくわからん。
下記のサイトによると
メモリの中の一部らしい。それもメモリの一番後半部分らしい。
>アセンブリ言語の基礎知識 Part 4
>http://ings.sakura.ne.jp/prog/asm4.html
さて、コードの一番最初に戻ると、
前半部分はchar変数の宣言をしているだけのはずなのに
なんでこんなに長いんだろう。
pushはスタックにデータを書き出すコマンドらしい。
push rbp ; RBPレジスタは5番目の汎用レジスタ。pushでスタックに書き出し。
(退避か?)
push rdi ; RDIレジスタは7番目の汎用レジスタ。pushでスタックに書き出し。
(退避か?)
sub rsp,128h
; RSPレジスタは8番目の汎用レジスタ。
128hは16進数。(16^2×1+16^1×2+16^0×8)=256+32+8=296
RSPレジスタの値から296を引き算するということ。
lea rbp,[rsp+20h] ;RSPレジスタの示す位置+32bit位置の値をRBPレジスタに移動
mov rdi,rsp ;RSPレジスタの値をRDIレジスタに代入。
mov ecx,4Ah ;ECXレジスタに4Ah=16^1×4+16^0×10=74を代入。
mov eax,0CCCCCCCCh
;EAXレジスタに
0CCCCCCCCh
=16^7×12+16^6×12+16^5×12+16^4×12+16^3×12+16^2×12+16^1×12++16^0×12
=3435973836を代入。
rep stos dword ptr [rdi]
;rep命令はecxレジスタの値が0でなければ
後続のストリング操作命令を実行してecxレジスタの値を1減らし、
ecxレジスタの値が0になるまで繰り返す。(下記サイトより)
>T.T Land 6.ストリング操作命令による文字列の操作
>http://hp.vector.co.jp/authors/VA014520/asmhsp/chap6.html
現在ecx=74なので74回次のコードを繰り返すのだろう。
mov rax,qword ptr [__security_cookie]
;qwordは64bit。下記のサイトより
__security_cookieはバッファオーバフローチェックを
する関数らしい。その結果か何かがRAXレジスタに
代入されるのかな?
>ここのことはなかったことにするかも
>http://d.hatena.ne.jp/yellow_73/20070905
xor rax,rbp
;XORコマンドは「排他的論理和」。
両方とも同じなら0、異なる 場合は1らしい。
RBPレジスタの値はもともとRSPレジスタの示す位置+32bit位置
に入っていた値が格納されているはず。
RAXレジスタにはバッファーオーバーフローのチェック結果が
格納されているはず。
mov qword ptr [rbp+0F8h],rax XORコマンドの結果の0か1がRBPレジスタ+248bitの位置に代入。
、、、と1個1個見ていっても
なにかの値を移動していることくらいしか分からない。
char *a = "ABC";
char *b = "123";
はどこ?
→12行目〜16行目
lea rax,[??_C@_03FFFJFKND@ABC?$AA@]
mov qword ptr [rbp+8],rax
lea rax,[??_C@_03EFKIOLOJ@123?$AA@]
mov qword ptr [rbp+28h],rax
mov rdx,qword ptr [rbp+8]
ここらへんに相当するのかな?
ABCの前にある「@_03FFFJFKND」
と123の前にある「@_03EFKIOLOJ」は何だろう。検索しても出てこない、、
とまあ、だらだら書いてしまった。
結局何をしているのかわからなかったが
色々コマンドは勉強になった。
次はもっと簡単なコードを逆アセンブラしてみよう。
あと新年からは下記のサイトのVBからアセンブラ実行も
少しチャレンジしたい。
>t-hom’s diary
>http://thom.hateblo.jp/entry/2015/08/03/014648
>Programming Field - プログラミング Tips
>http://pf-j.sakura.ne.jp/program/tips/vbasm.htm
とりあえず上記のサイトのコードをそのままコピペして
Sub Test()
Debug.Print MyWPrintF("Result: %d, %1.3lf", 12, CDbl(1.245))
End Sub
を実行してみた。
動かなかった。。。ん?Debug.Printとはなんぞや?
イミディエイトウインドウに出力されるらしい。
あ、できてるー!
C言語のswprintf関数と同じ結果を実行できるらしい。
他のコードもできるようにしたいなあ。
前回、逆アセンブラしたC++で書いたコードのexeファイル。
もともとのC++のコードは下記のような感じ。
#include
void swapptr(char **x, char **y)
{
char *temp = *x;
*x = *y;
*y = temp;
}
int main(void)
{
char *a = "ABC";
char *b = "123";
printf("a = %s\n", a);
printf("&a = %p\n", *a);
printf("b = %s\n", b);
printf("&b = %p\n", *b);
swapptr(&a, &b);
printf("a = %s\n", a);
printf("&a = %p\n", *a);
printf("b = %s\n", b);
printf("&b = %p\n", *b);
return (0);
}
swapptr関数部分は下記のサイトの内容を基にしている。
>二つのポインタ値を交換する関数はどのように実現すればよいでしょうか。
>http://www.bohyoh.com/CandCPP/FAQ/FAQ00024.html
printf関数部分の*aとか&aとかよくよく見ると「ポインタのポインタ」を使ってから
どれが何だか分からなくなってきたのでたぶん表示が間違っているかも。
(そこらへんはご容赦)
前回の記事でswapptr関数部分の逆アセンブラしたコードは載せたが、
それだけじゃぜんぜんVBでポインタの付け替えができるようになる気がしない。
もう少しアセンブリ言語に詳しくならなくては!
main関数部分を逆アセンブラした結果を下記に示す。
push rbp
push rdi
sub rsp,128h
lea rbp,[rsp+20h]
mov rdi,rsp
mov ecx,4Ah
mov eax,0CCCCCCCCh
rep stos dword ptr [rdi]
mov rax,qword ptr [__security_cookie]
xor rax,rbp
mov qword ptr [rbp+0F8h],rax
lea rax,[??_C@_03FFFJFKND@ABC?$AA@]
mov qword ptr [rbp+8],rax
lea rax,[??_C@_03EFKIOLOJ@123?$AA@]
mov qword ptr [rbp+28h],rax
mov rdx,qword ptr [rbp+8]
lea rcx,[??_C@_07LLAODNH@a?5?$DN?5?$CFs?6?$AA@] ; メモリからrcxレジスタに移動
call @ILT+460(printf) ; printf関数の呼び出し
mov rax,qword ptr [rbp+8]
movsx eax,byte ptr [rax]
mov edx,eax
lea rcx,[??_C@_08HLDGGNGA@?$CGa?5?$DN?5?$CFp?6?$AA@] ; メモリからrcxレジスタに移動
call @ILT+460(printf) ; printf関数の呼び出し
mov rdx,qword ptr [rbp+28h]
lea rcx,[??_C@_07IFDPOEDE@b?5?$DN?5?$CFs?6?$AA@] ; メモリからrcxレジスタに移動
call @ILT+460(printf) ; printf関数の呼び出し
mov rax,qword ptr [rbp+28h]
movsx eax,byte ptr [rax]
mov edx,eax
lea rcx,[??_C@_08PFLJGKID@?$CGb?5?$DN?5?$CFp?6?$AA@] ; メモリからrcxレジスタに移動
call @ILT+460(printf) ; printf関数の呼び出し
lea rdx,[rbp+28h]
lea rcx,[rbp+8]
call @ILT+10(?swapptr@@YAXPEAPEAD0@Z) ; swapptr関数の呼び出し
mov rdx,qword ptr [rbp+8]
lea rcx,[??_C@_07LLAODNH@a?5?$DN?5?$CFs?6?$AA@] ; メモリからrcxレジスタに移動
call @ILT+460(printf) ; printf関数の呼び出し
mov rax,qword ptr [rbp+8]
movsx eax,byte ptr [rax]
mov edx,eax
lea rcx,[??_C@_08HLDGGNGA@?$CGa?5?$DN?5?$CFp?6?$AA@] ; メモリからrcxレジスタに移動
call @ILT+460(printf) ; printf関数の呼び出し
mov rdx,qword ptr [rbp+28h]
lea rcx,[??_C@_07IFDPOEDE@b?5?$DN?5?$CFs?6?$AA@] ; メモリからrcxレジスタに移動
call @ILT+460(printf) ; printf関数の呼び出し
mov rax,qword ptr [rbp+28h]
movsx eax,byte ptr [rax]
mov edx,eax
lea rcx,[??_C@_08PFLJGKID@?$CGb?5?$DN?5?$CFp?6?$AA@] ; メモリからrcxレジスタに移動
call @ILT+460(printf) ; printf関数の呼び出し
xor eax,eax
mov edi,eax
lea rcx,[rbp-20h]
lea rdx,[140019CC0h]
call @ILT+310(_RTC_CheckStackVars) ; _RTC_CheckStackVars関数の呼び出し
mov eax,edi
mov rcx,qword ptr [rbp+0F8h]
xor rcx,rbp
call @ILT+730(__security_check_cookie) ; __security_check_cookie関数の呼び出し
lea rsp,[rbp+108h]
pop rdi
pop rbp
ret
callコマンドで関数を呼び出しているのか、、
後半、printf関数が4回使われて、swapptr関数が使われて
再度、printf関数が4回使われていることが分かる。
あと、最後に知らん関数が2つ使われている。
printf関数の1つ前にいつもleaコマンドがある。
leaはmovに似ているらしい。
>むむむ雑記 MOVとLEAを比較
>http://mumumu-pg.hatenablog.com/entry/2014/07/20/204952
メモリからレジスタへの移動。
何を移動しているんだろう。
最後のpopはスタックからデータを読み込むコマンド。
>IT pro【5分で覚えるIT基礎の基礎】だれでも一度はアセンブラを学んでおこう! 第2回
>http://itpro.nikkeibp.co.jp/members/ITPro/ITBASIC/20021220/1/?rt=nocnt
スタックとは調べると
「最後に入力したデータが先に出力されるという特徴をもつ、データ構造の一種」
後入れ先出しの構造。
よくわからん。
下記のサイトによると
メモリの中の一部らしい。それもメモリの一番後半部分らしい。
>アセンブリ言語の基礎知識 Part 4
>http://ings.sakura.ne.jp/prog/asm4.html
さて、コードの一番最初に戻ると、
前半部分はchar変数の宣言をしているだけのはずなのに
なんでこんなに長いんだろう。
pushはスタックにデータを書き出すコマンドらしい。
push rbp ; RBPレジスタは5番目の汎用レジスタ。pushでスタックに書き出し。
(退避か?)
push rdi ; RDIレジスタは7番目の汎用レジスタ。pushでスタックに書き出し。
(退避か?)
sub rsp,128h
; RSPレジスタは8番目の汎用レジスタ。
128hは16進数。(16^2×1+16^1×2+16^0×8)=256+32+8=296
RSPレジスタの値から296を引き算するということ。
lea rbp,[rsp+20h] ;RSPレジスタの示す位置+32bit位置の値をRBPレジスタに移動
mov rdi,rsp ;RSPレジスタの値をRDIレジスタに代入。
mov ecx,4Ah ;ECXレジスタに4Ah=16^1×4+16^0×10=74を代入。
mov eax,0CCCCCCCCh
;EAXレジスタに
0CCCCCCCCh
=16^7×12+16^6×12+16^5×12+16^4×12+16^3×12+16^2×12+16^1×12++16^0×12
=3435973836を代入。
rep stos dword ptr [rdi]
;rep命令はecxレジスタの値が0でなければ
後続のストリング操作命令を実行してecxレジスタの値を1減らし、
ecxレジスタの値が0になるまで繰り返す。(下記サイトより)
>T.T Land 6.ストリング操作命令による文字列の操作
>http://hp.vector.co.jp/authors/VA014520/asmhsp/chap6.html
現在ecx=74なので74回次のコードを繰り返すのだろう。
mov rax,qword ptr [__security_cookie]
;qwordは64bit。下記のサイトより
__security_cookieはバッファオーバフローチェックを
する関数らしい。その結果か何かがRAXレジスタに
代入されるのかな?
>ここのことはなかったことにするかも
>http://d.hatena.ne.jp/yellow_73/20070905
xor rax,rbp
;XORコマンドは「排他的論理和」。
両方とも同じなら0、異なる 場合は1らしい。
RBPレジスタの値はもともとRSPレジスタの示す位置+32bit位置
に入っていた値が格納されているはず。
RAXレジスタにはバッファーオーバーフローのチェック結果が
格納されているはず。
mov qword ptr [rbp+0F8h],rax XORコマンドの結果の0か1がRBPレジスタ+248bitの位置に代入。
、、、と1個1個見ていっても
なにかの値を移動していることくらいしか分からない。
char *a = "ABC";
char *b = "123";
はどこ?
→12行目〜16行目
lea rax,[??_C@_03FFFJFKND@ABC?$AA@]
mov qword ptr [rbp+8],rax
lea rax,[??_C@_03EFKIOLOJ@123?$AA@]
mov qword ptr [rbp+28h],rax
mov rdx,qword ptr [rbp+8]
ここらへんに相当するのかな?
ABCの前にある「@_03FFFJFKND」
と123の前にある「@_03EFKIOLOJ」は何だろう。検索しても出てこない、、
とまあ、だらだら書いてしまった。
結局何をしているのかわからなかったが
色々コマンドは勉強になった。
次はもっと簡単なコードを逆アセンブラしてみよう。
あと新年からは下記のサイトのVBからアセンブラ実行も
少しチャレンジしたい。
>t-hom’s diary
>http://thom.hateblo.jp/entry/2015/08/03/014648
>Programming Field - プログラミング Tips
>http://pf-j.sakura.ne.jp/program/tips/vbasm.htm
とりあえず上記のサイトのコードをそのままコピペして
Sub Test()
Debug.Print MyWPrintF("Result: %d, %1.3lf", 12, CDbl(1.245))
End Sub
を実行してみた。
動かなかった。。。ん?Debug.Printとはなんぞや?
イミディエイトウインドウに出力されるらしい。
あ、できてるー!
C言語のswprintf関数と同じ結果を実行できるらしい。
他のコードもできるようにしたいなあ。
この記事へのコメント
コメントを書く
この記事へのトラックバックURL
https://fanblogs.jp/tb/4576480
※ブログオーナーが承認したトラックバックのみ表示されます。
この記事へのトラックバック