給出對應於7個階段的7篇博客
phase_1 https://www.cnblogs.com/wkfvawl/p/10632044.html
phase_2 https://www.cnblogs.com/wkfvawl/p/10636214.html
phase_3 https://www.cnblogs.com/wkfvawl/p/10651205.html
phase_4 https://www.cnblogs.com/wkfvawl/p/10672680.html
phase_5 https://www.cnblogs.com/wkfvawl/p/10703941.html
phase_6 https://www.cnblogs.com/wkfvawl/p/10742405.html
secret_phase https://www.cnblogs.com/wkfvawl/p/10745307.html
phase_2
phase_2要求輸入包含6個整數的字符串。phase_2函數從中讀取6個整數,並判斷其正確性,如果不正確,則炸彈爆炸。phase_2主要考察學生對C語言循環的機器級表示的掌握程度。
觀察框架源文件bomb.c:
從上可以看出:
1、首先調用了read_line()函數,用於輸入炸彈秘鑰,輸入放置在char* input中。
2、調用phase_2函數,輸入參數即為input,可以初步判斷,phase_2函數將輸入的input字符串作為參數。
因此下一步的主要任務是從asm.txt中查找在哪個地方調用了readline函數以及phase_2函數。
1.1 尋找並分析調用phase_2函數的代碼
打開asm.txt,尋找phase_2函數。
和phase_1類似分析:
1、當前棧的位置存放的是read_line函數讀入的一串輸入;
2、phase_2的函數入口地址為0x8048c24。
此時的函數棧為:
1.2 phase_2函數分析
尋找8048c24,或者繼續尋找phase_2,可以尋找到phase_2函數,如下圖所示:
分析上面的代碼:
1、390 ~ 392行:進行一些壓棧,並擴展了函數棧幀。
2、第394-395行:lea 0x18(%esp) %eax、mov %eax 4(%esp),將esp + 18指向的棧的內容的地址放置到esp+4指向的地方。簡單的說,當前esp + 4指針指向的空間的內容為esp + 18。(實際上,根據后面的分析,可以知道esp + 4的內容,放的是num[0]的地址esp + 18)
3、第396行:將0x40(%esp)的內容放置到esp指向的棧。0x40(%esp)里面的內容實際上就是input字符串首地址。
4、第397行:調用了read_six_numbers函數(顧名思義,從字符串中解析出六個整數),可以猜測實際上第394行到第396行,是在為read_six_numbers函數准備參數。
5、在調用read_six_numbers之前,函數棧幀為:
7、上圖所示的函數棧幀中,從esp + 18 ~ esp+2c,共6個棧空間,標記為保存6個整數,實際上從當前的地方並不能完全看出來,可以有些猜測,到后來閱讀read_six_numbers時,證實了當前的猜測是正確的。
8、依據以上的分析,read_six_numbers函數的定義:void read_six_numbers(char* input, num);其中第二個參數,是num數組的地址。在后面,會剖析read_six_numbers函數,來證實以上的猜測,下面的分析以以上的棧幀圖為基礎。
9、第399行:cmp $0x1, 0x18(%esp),0x18(%esp)中是num[0],該語句判斷num[0]是否應等於1,如果等,則跳轉到phase_2 + 0x3e(第400行),如果不等,則call explode_bomb(第401行),從此處,可以猜測:num[0] = 1。
10、第412行(8048c62(phase_2 + 0x3e)),將0x1c + esp --> ebx寄存器,即將num[1]的地址送入到ebx寄存器,第413行,將0x30 + esp -->esi,0x30(%esp)是num[5]上面的棧空間,將該棧空間的地址送入到esi。
11、第415行:跳轉到8048c4b(即第403行)。
12、第403行:將-0x4(%ebx)的內容送入到eax,-0x4(%ebx)的內容實際上指的是0x18(%esp),也即num[0]送入到eax。
13、第404行:eax = eax + eax,即: 2 * num[0];
14、第405行:比較ebx所指的地址的內容和eax的內容,據前面分析,當前ebx的內容即為num[1]的地址。
15、第406行:如果相等,則跳轉到8048c59。
16、第408行(8048c59):ebx += 4,當前ebx為num[1]的地址,加4之后,正好是num[2]的地址。
17、第409行:ebx與esi(num[5]之上的地址)比較,如果不等則跳轉到8048c4b(第403行),繼續從前面第11繼續開始。如果相等,則跳轉到8048c6c(第415行),退出函數。實際上如果ebx與esi相等,說明前面已經處理完了num[5],也即處理完了第6個數。如果不等,則說明num[5]沒有處理,繼續循環。
18、總結前面的分析,以上顯然是一個循環表示的機器級表示的處理過程,從上面的分析來看:
1)num[0] = 1;
2)num[i] = 2 * num[i-1]。(i > 0)
因此,phase_2炸彈秘鑰應該是:1 2 4 8 16 32。
以上所有的分析是建立在六個輸入數字是放置在esp + 0x18開始的地址中的前提下的。為確認這一個問題,下面對read_six_numbers函數進行詳細分析。
1.3 read_six_numbers分析
根據前面分析,read_six_numbers的入口地址為80493da,如下圖所示:
1、第996行:擴展棧幀,增加了44。
2、第997行:將0x34(%esp)的內容送到eax,0x34(%esp)的內容正好是num[0]的地址,也即num的首地址,也即eax內容為num[0]的地址。(參見后面的棧幀圖)
3、第998行:將eax + 0x14的地址(即為eax + 0x14)送到edx,eax+0x14正好是num[5]的地址。(參見后面棧幀圖)
4、第999行:將edx的內容送到esp + 0x1c的地方,即將num[5]的地址送到esp+0x1c的地方;
5、第1000行 ~1008行:
1)num[4]地址,送到esp + 0x18
2)num[3]地址,送到esp + 0x14
3)num[2]地址,送到esp + 0x10
4)num[1]地址,送到esp + 0xc
6、第1009行:num[0]地址,送到esp + 8
7、第1010行:0x804a725送入到esp + 4的地方
8、第1011/1012行:0x30(%esp)內容送入到esp,0x30(%esp)內容為input輸入首地址。
9、第1013行:調用scanf函數,用於從input中讀入6個整數。可以認為前面都是在為scanf函數調用准備參數,包括第1009行,0x804a67d實際上是指向一個字符串的首地址,這個字符串為“%d %d %d %d %d %d”(這點將在后面分析),因此,我們可以判斷scanf的函數定義/使用為:scanf(input, "%d %d %d %d %d %d", &num[0], &num[1], &num[2], &num[3], &num[4], &num[5],); 返回的是讀取的整數的個數。
10、此時的棧幀為:
11、第1014行:將eax的值與5比較,eax應該是scanf函數返回的輸入數字的個數;
12、第1015行:如果大於5,則函數正確返回;
13、第1016行:如果小於等於5,則引爆炸彈。
14.為了查看0x804a67d地址的內容,可以使用objdump --start-address= 0x804a67d -s bomb命令查看,如下圖所示: