反彙編測試
任務詳情
1 通過輸入gcc -S -o main.s main.c 將下面c程式”week0303學號.c“編譯成彙編程式碼
int g(int x){
return x+3;
}
int f(int x){
int i = 學號後兩位;
return g(x)+i;
}
int main(void){
return f(8)+1;
}
2. 參考http://www.cnblogs.com/lxm20145215----/p/5982554.html,使用gdb跟蹤彙編程式碼,在紙上畫出f中每一條語句引起的eip(rip),ebp(rbp),esp(rsb),eax(rax)的值和棧的變化情況。提交照片,要有學號資訊。
完成過程
1.編譯情況
2.發現在樹莓派arm64架構下無法完成,便轉到kali上做了。
使用gcc - g example.c -o example -m32
指令在64位的機器上產生32位彙編,然後使用gdb example
指令進入gdb偵錯程式:
進入之後先在main函式處設定一個斷點,再run一下,使用disassemble
指令獲取彙編程式碼,用i(info) r(registers)
指令檢視各暫存器的值:
用x mian檢視主函式的記憶體地址:
首先,結合display命令和暫存器或pc內部變數,做如下設定:display /i $pc
,這樣在每次執行下一條彙編語句時,都會顯示出當前執行的語句。
call指令將下一條指令的地址入棧,此時%esp,%ebp和堆疊的值為:
將上一個函式的基址入棧,從當前%esp開始作為新基址:
先為傳參做準備:
f函式的彙編程式碼:
實參入棧:
主函式彙編程式碼:
知識點
跟著部落格做完整個人還是很暈,於是想梳理一下知識點。
1.暫存器
參考部落格:https://www.cnblogs.com/lihaozy/archive/2011/08/01/2124315.html
(1)ESP:棧指標暫存器(extended stack pointer),其記憶體放著一個指標,該指標永遠指向系統棧最上面一個棧幀的棧頂。
(2)EBP:基址指標暫存器(extended base pointer),其記憶體放著一個指標,該指標永遠指向系統棧最上面一個棧幀的底部。
(3)Eax用來儲存所有API函式的返回值。
(4)暫存器AX和AL通常稱為累加器(Accumulator),用累加器進行的操作可能需要更少時間。累加器可用於乘、除、輸入/輸出等操作,它們的使用頻率很高;
(5)暫存器BX稱為基地址暫存器(Base Register)。它可作為儲存器指標來使用;
(6)暫存器CX稱為計數暫存器(Count Register)。在迴圈和字串操作時,要用它來控制迴圈次數;在位操作中,當移多位時,要用CL來指明移位的位數;
(7)暫存器DX稱為資料暫存器(Data Register)。在進行乘、除運算時,它可作為預設的運算元參與運算,也可用於存放I/O的埠地址。
(8)暫存器ESI、EDI、SI和DI稱為變址暫存器(Index Register),它們主要用於存放儲存單元在段內的偏移量,用它們可實現多種儲存器運算元的定址方式,為以不同的地址形式訪問儲存單元提供方便。變址暫存器不可分割成8位暫存器。作為通用暫存器,也可儲存算術邏輯運算的運算元和運算結果。它們可作一般的儲存器指標使用。在字串操作指令的執行過程中,對它們有特定的要求,而且還具有特殊的功能。
2.gdb指令
參考部落格:https://blog.csdn.net/moonsheep_liu/article/details/39099969
3.學習組合語言
參考部落格:https://www.ruanyifeng.com/blog/2018/01/assembly-language-primer.html
重新嘗試反彙編
試圖理解反彙編
1.首先在main函式設定斷點 b main
2.使用display設定顯示內容。
display /x $esp
display /x $ebp
display /x $eax
display /i $pc
3.使用run指令跳到main函式開始處,使用x(examine) /nfu + 記憶體地址
檢視堆疊內容。
push 命令將$0x8放入stack,因為是int型佔用4個位元組,所以esp暫存器減去4。
這時可以看到棧底地址是0xffffd168。
4.使用si
步入下一條指令,使用x(examine) /nfu + 記憶體地址
檢視堆疊內容(之後每一步都要用到,不重複說明)。
call指令呼叫f函式,f函式的地址在0x5655619e。
5.push命令將ebp裡的值寫入f函式這個幀,內容為0x565561bd,這是因為後面要用到這個暫存器,就先把裡面的值取出來,用完後再寫回去。這時,push
指令會再將 ESP 暫存器裡面的地址減去4個位元組(累計減去8)。
6.mov指令用於將一個值寫入某個暫存器。這一行程式碼表示,從ebp暫存器存的地址在 Stack 取出資料。根據前面的步驟,可以推算出這裡取出的是8
,再將8
寫入ESP暫存器。
這裡沒有使用push指令,但是esp減去了4(累計減去12),堆疊中也存入了ebp的地址0xffffd168,參照阮一峰的理解是
7.sub指令代表第一個暫存器中的值減去第二個暫存器中的值,將結果存入第一個暫存器中。這裡就是用10(我的學號)減去esp中的值(此處應該是8),得到了2,存入?
(此處不理解)將我的學號傳入f函式中,堆疊中存入了0xf7de2fd6。
此處因為進入了f函式中,所以ebp指向了f函式的棧底0xffffd15c。
8.call指令呼叫(此處應該是一個奇奇怪怪的函式,估計是某個庫函式,用來初始化函式呼叫的?),建立該函式的幀。
esp減去了16,說明存入了4個東西(為什麼呢)
9.mov指令將esp的地址存入了eax暫存器中,地址為0x565561a9,存入了堆疊中,esp中的值減去4。
10.ret指令用於終止當前函式的執行,將執行權交還給上層函式。也就是,當前函式的幀將被回收。
隨著函式的終止,系統就回到剛才f函式中斷的地方,繼續往下執行。
11.add指令是將0x2e57與eax暫存器中的值相加,存到?
此處應該發生了pop指令,esp暫存器的值加上4。
12.movl指令將0xa(10,我的學號)傳入地址(ebp的地址減去4,這裡應該是i
的地址)中,此處movl中的l為長位元組的意思(雖然感覺用mov也可以)。
13.push將地址(ebp的值0+8,就是8)中的值取出來寫入f函式這個幀,esp減去4。
14.call指令呼叫g函式,建立g函式的幀。
15.push命令將ebp中的值(地址0xffffd15c的值,此處應是0xa)寫入g函式幀裡,esp的地址減去4。
16.mov將esp中的值寫入ebp中(為傳回上層函式做準備)。
17.call指令呼叫不知名函式。
18.mov指令將暫存器eax中的值存入地址(暫存器esp的值)中。
19.ret指令終止函式,返回上層函式的幀。
20.add指令將0x2e6f
與暫存器eax中的值(0x56556191)相加,存入eax中。
21.mov指令將暫存器ebp中的值(此處為0)加8,存入eax暫存器中。
22.add指令將3加上eax中的值存入eax中(3+8=11)。
23.pop指令
24.ret指令終止當前函式。
25.add指令將4與esp暫存器中的值(此處為8)相加,存入esp暫存器中。
25.mov指令將地址(暫存器ebp的值減去4)中的值存入暫存器edx中。
26.add指令將edx中的值與eax中的值相加(11+8=21),存入eax中。
27.leave指令用於釋放當前堆疊中的內容。
28.ret指令用於終止函式。
29.add指令將4與暫存器esp中的值相加,存到esp中(4+8 = 12)
30.add指令將1與暫存器eax中的值相加,存到eax中(21+1 = 22)。
31.leave指令釋放當前堆疊的內容。
32.ret指令結束當前函式呼叫,之後就是系統呼叫,很多看不完。
總結
看了一整天,看麻了!