1. 程式人生 > 其它 >【reverse】逆向7 堆疊圖

【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、總結

首先我們認清計算機中函式的概念:

計算機的函式,是一個固定的一個程式段,或稱其為一個子程式,它在可以實現固定運算功能的同時還帶有一入口和一個出口,所謂的入口,就是函式所帶的各個引數,我們可以通過這個入口,把函式的引數值代入子程式,然後根據出口返回

彙編中的函式:

來張好看點的

函式的入口

函式的出口

提醒:

  1. 這裡ebp+4是返回地址(在pwn中是要考的!!!)

  2. 函式雖然有入口和出口,但是入口不一定需要傳值,出口也不一定要返回(void)

  3. 傳參不一定是push,還可能是暫存器傳參等等...

  4. 返回值也不一定只通過暫存器返回,也可以通過記憶體返回

一張windows堆疊的補充圖: