【reverse】逆向7 堆疊圖
【reverse】逆向7 堆疊圖
前言
本章就是開始畫堆疊圖來打基礎拉,堆疊熟悉了之後就可以開始C語言的逆向了。
這一章使用的exe檔案,我已經上傳到了我的個人網盤中,點選下載
1、準備工作
先看這張內容
我們首先開啟OD,使用F3開啟helloworld.exe程式
然後在任意位置,ctrl+G開啟視窗,輸入0x401168地址,然後點選OK,自動跳轉到這裡
然後在這個地址上打一個斷點(F2)
然後我們F9執行,讓程式執行到這裡
然後就是我們畫堆疊圖的時候了
2、畫堆疊圖
我們先在OD上看esp棧頂和ebp棧底的記憶體地址
根據這個記憶體地址我們可以畫出開始時候的堆疊圖(這裡的黃色表示中間有一定距離,不是每格4位元組)
然後我們執行push 0x2 和 push 0x1的彙編指令
執行之後的堆疊圖變成了這樣
然後下一步的彙編指令是call 0040100A,是我們剛剛學習的call指令,會讓我們eip指向0040100A,也就是跳轉到這裡,並且將這個00401171地址push進堆疊中
我們這裡按F7步入
所以堆疊圖如下圖
然後我們發現我們進入的地址0040100A的語句是jmp 00401040,也就是跳轉到00401040,這裡沒有堆疊操作,我們直接F8步過
接下來我們jmp到了一段比較長的地方,這裡我們逐步分析
首先是push ebp,這個操作讓堆疊存入ebp的地址,而此時我們的ebp的地址為0019FF30,所以堆疊圖如下
這一步執行完了之後,就是mov ebp,esp
這一步的的作用就是將esp的值傳給ebp,讓ebp = esp,堆疊圖如下
然後是sub esp,0x40
這一步是讓esp棧頂上升0x40個單位,也就是16個4位元組,也就是在堆疊上升16位,堆疊圖如下
然後就是push ebp,esi,edi,將ebp、esi、edi這些暫存器存放的東西放入堆疊中,起到保護現場的作用
堆疊圖如下
下一步lea edi,dword ptr ss:[ebp-0x40],這句彙編就是讓edi儲存ebp-0x40之後的記憶體地址
當然,lea指令是不會影響堆疊的
這裡的ebp-0x40是不是非常熟悉?就在剛才,esp也是減去了0x40
所以這個時候的堆疊圖如下,edi是儲存了0019FE94這個地址的
然後就是
mov ecx.0x10
mov eax,0xcccccccc
rep stos dword ptr es:[edi]
這三句話其實要一起說明
首先ecx是儲存迴圈次數的暫存器,可以看出來這裡迴圈0x10,也就是16次
然後執行mov eax,0xcccccccc,就是讓eax這個暫存器儲存0xcccccccc這個值
最關鍵的rep stos dword ptr es:[edi],就是讓edi儲存eax的值,每次存完的數都會根據DF標誌暫存器來決定儲存地址+-4,DF=0就是加,DF=1就是減
這上面三句就是重複16次,也就是讓堆疊中儲存16個緩衝,組成緩衝區
堆疊圖如下
然後就是mov eax,dword ptr ss:[ebp+0x8],這句話就是讓eax儲存ebp+0x8地址中的資料,也就是我們最開始儲存的1
add eax,dword ptr ss:[ebp+0xC],這句話就是讓eax中原有的資料加上ebp+0xC地址中的資料,也就是我們最開始儲存的2,所以eax中是1+2,現在eax=0x3
這一步,堆疊圖沒有發生改變,但是這兩句話卻是函式核心,就是兩引數相加
int func(int a, int b) {
return a+b;
}
然後就是pop edi,pip esi,pop ebx
這三句就是為了還原現場。
還記得我們在剛剛開始的時候push了這三個暫存器嗎,現在我們把他們pop出來,還原到最開始的狀態。
堆疊圖如下
然後就是mov esp,ebp
這句話就是把ebp的值賦給esp,這樣就是esp = ebp了
堆疊圖如下
然後就是pop ebp,這句話就是把現在棧頂指向的返回地址pop給ebp
我們其實也記得,剛剛在call執行完,存完了紫色的返回地址之後,我們push了ebp
這個時候也就是讓我們的ebp返回到原來的地址上去
堆疊圖如下
然後就是函式的最後 retn
retn就相當於指令 pop eip,就是把返回地址給eip,而eip就是當前指向地址,這就是最後的返回地址
堆疊圖如下
當我們執行完retn之後,發現我們的esp並沒有回到函式開始前的模樣,現在還在綠色的位置
而我們要知道,每個程式都保證了堆疊平衡,也就是,函式執行完了之後,esp和ebp的位置要和執行之前是保持一致的。
我們來看看retn完了之後,OD的頁面
eip = 00401171
這裡的add esp,0x8就是讓esp的地址加8
這樣我們的esp就回到了原來的位置,實現了堆疊平衡
這種在函式執行完了之後實現的堆疊平衡,叫做外平棧
即——誰呼叫函式,誰平衡堆疊
堆疊圖如下
3、總結
首先我們認清計算機中函式的概念:
計算機的函式,是一個固定的一個程式段,或稱其為一個子程式,它在可以實現固定運算功能的同時還帶有一入口和一個出口,所謂的入口,就是函式所帶的各個引數,我們可以通過這個入口,把函式的引數值代入子程式,然後根據出口返回
彙編中的函式:
來張好看點的
函式的入口
函式的出口
提醒:
-
這裡ebp+4是返回地址(在pwn中是要考的!!!)
-
函式雖然有入口和出口,但是入口不一定需要傳值,出口也不一定要返回(void)
-
傳參不一定是push,還可能是暫存器傳參等等...
-
返回值也不一定只通過暫存器返回,也可以通過記憶體返回
一張windows堆疊的補充圖: