函式的開始和結束標誌
.text:00401010 ; void *__thiscall CtmpApp___vector deleting destructor_(CtmpApp *this, unsigned int)
.text:00401010 [email protected]@[email protected] proc near ; DATA XREF: .rdata:004034D8o
.text:00401010
.text:00401010 arg_0 = byte ptr 8
.text:00401010
.text:00401010 this = ecx
.text:00401010 push ebp
.text:00401011 mov ebp, esp
.text:00401013 push esi
.text:00401014 mov esi, this
.text:00401016 call ds: [email protected]@[email protected] ; CWinApp::~CWinApp(void)
.text:0040101C test [ebp+arg_0], 1
.text:00401020 jz short loc_40102C
.text:00401022 push esi
.text:00401023 call ds:[email protected]@Z ; operator delete(void *)
.text:00401029 add esp, 4
.text:0040102C
.text:0040102C loc_40102C: ; CODE XREF: CtmpApp::`vector deleting destructor'(uint)+10j
.text:0040102C mov eax, esi
.text:0040102E pop esi
.text:0040102F pop ebp
.text:00401030 retn 4
.text:00401030 [email protected]@[email protected] endp
先不說別的,隨便貼一段反彙編程式碼,然後進行分析:
可以看到,一般而言函式都是以
push ebp;
mov ebp,esp;
開始的因為在函式內部要使用區域性變數,而所有的變數都是要有地址記錄的,所以要使用ebp,而在新的函式使用ebp之前要壓入堆疊,否則會導致父函式崩潰,使用之前先將
其儲存到堆疊當中,同時因為esp是指向棧頂的,其次mov ebp,esp是要將之前的棧頂變棧底,因為之後根據函式內部的區域性變數的分配,esp不斷減小,所以要將函式呼叫之
前的內容儲存起來,也就是,當前函式的起始地址,之後的函式區域性變數要在esp之後,隨著函式內部變數的不斷分配,同時esp的值也會不斷減小,我們會看到,在該函式內
部,push和pop並不是成對出現的,但是在
.text:00401022 push esi;
.text:00401023 call ds:operator delete(void*);
這是一步函式呼叫,push esi為函式 delete提供引數,在該函式完成後,會自行彈出esi的值,
.text:00401013 push esi;壓入堆疊,使用完畢後,在
.text:0040102E pop esi; 彈出堆疊,恢復之前的現場
該函式執行完畢後,.text 將 在函式使用之前壓入堆疊的棧頂地址彈出到ebp當中,然後 retn 4說明函式執行完畢,4表示在該函式中彈出4個位元組,可能該函式中有佔據4個位元組
的引數。
所以 函式執行完畢有兩種:
pop ebp; mov esp,ebp;
add esp,64h;//將之前的壓入堆疊的空間收回 pop ebp;
retn retn
函式在執行完畢後通過將堆疊的指標向下移動,恢復ebp,而關閉堆疊,對應之前的mov ebp,esp;開啟堆疊,或者通過esp的增加實現關閉堆疊的同樣效果。