逆向工程實驗---二進位制炸彈(CSAPP Project)
本實驗設計為一個黑客拆解二進位制炸彈的遊戲。我們僅給黑客(同學)提供一個二進位制可執行檔案bomb和主函式所在的源程式bomb.c,不提供每個關卡的原始碼。程式執行中有6個關卡(6個phase),每個關卡需要使用者輸入正確的字串或數字才能通關,否則會引爆炸彈(打印出一條錯誤資訊,並導致評分下降)!
要求同學運用GDB除錯工具和objdump反彙編工具,通過分析彙編程式碼,找到在每個phase程式段中,載入程式跳轉到“explode_bomb”程式段的地方,並分析其成功跳轉的條件,以此為突破口尋找應該在命令列輸入何種字串來通關。
本實驗要求解決Phase_1(15分)、Phase_2(10分)、Phase_3(10分)、Phase_4(10分)、Phase_5(10分)。通過截圖把結果寫在實驗報告上。
#思路、#程式碼分析及最後的成績截圖
首先,先 cd 到bomb的檔案裡面,
- 輸入反彙編命令檢視彙編程式碼(儲存在1.txt檔案中)
$ objdump -d bomb > 1.txt - 首先找到main函式,發現它呼叫了從phase1到phase6這六個函式。再找到phase1,程式碼如下:(舉例分析)
3. 利用gdb除錯工具來破解Phase1中的神祕字串
$ gdb bomb
在0x8048b22處設定斷點,執行並列印0x8049678地址的值
(gdb) b *0x8048b22
(gdb) r
(gdb) p (char*)0x8049678記錄答案,對下一關進行破解。
(gdb) c
第一關:
知識點:string,函式呼叫,棧
可以看到0x8048b2c和0x8048b31指令中分別放入了兩個字串,一個在地址0x80497c0中,另一個在%eax中。而%eax是函式phase_1的mov 0x8(%ebp),%eax 傳遞過來的引數,所以依此可以判斷0x8(%ebp)的記憶體地址中的值是我們輸入的字串,而0x80497c0則可能是程式中已經儲存在程式碼中的一個字串。
那麼,找到這個記憶體地址中的字串便能解決問題了。那麼如何去尋找呢,
所以,密碼就是:Public speaking is very easy.
關鍵點在於,找到 退出函式 的地方和 引爆炸彈的地方。
第二關:
這樣,就發現了第一個數字必須為1。
初始時,A[1]=1。所以,A[2] = A[1] * 2 = 2,A[3] = A[2] * 3 = 6,A[4] = A[3] * 4 = 24,A[5] = A[4] * 5 = 120,A[6] = A[5] * 6 = 720。
if ([0] != 1) explode_bomb();
for (int i = 1; i <= 5; i++) {
if ( (i+1) * A[i-1] != A[i])
explode_bomb();
}
第三關:
爆炸了。
sscanf() - 是C語言中從一個字串中讀進與指定格式相符的資料的函式。
sscanf傳入的引數為:ebp-0x4,ebp-0x5, ebp-0xc地址;格式字串地址;輸入的字元引數地址。
ebp-0xc存第一個數, ebp-0x5存第二數,ebp-0x4第三個數。
從這就可以看出,要輸入的是一個整數,一個字元,一個整數。
第一個數字要小於7。
<sscanf@plt>,猜測sscanf可能是C語言的內部函式,於是查到其定義為:int sscanf(const char *str, const char *format,…),給出一個使用例項:sscanf(“s 1”, “%s %d”, str, &a),函式返回2(因為接收了2個引數),str為char*型別,儲存”s”;a為int型別,儲存1。
我們試試倒推
我們看到,只要是標註了 int 的語句,最後跳轉到 8048c8f 都有希望結束!!!!
希望來了!!!
求第一個數要小於等於7,那麼使用最簡單0進行測試,這樣不用計算就可以跳轉到明顯的位置 ,就是 0x80497eb儲存的內容—0x8048be0;
ebp-0x4儲存的為第三個數,大小為0x309, 轉10進製為:777。 同時,設定了bl 為 0x71。並跳轉到0x8048c8f。
bl 為 0x71。第二個輸入的又是 字元型 ,對照ASC碼錶:
字串值為0x71,換算成字元為 ‘q’。
所以其中一個答案為: 0 q 777。
這道題的答案不為一,根據第一個引數的選擇不同而不同。
第四關:
這段程式碼還有一個 func4 的函式,有不祥的預感…..
首先,又是 sscanf,老套路,我們先看一下 0x8049808字串內容。
看來是一個整數!
這麼看來,成功的關鍵就是,輸入一個大於0的數字,這個數字作為引數,使得返回值為 55。
接下來就看看函式內容了:
當引數為1的時候,在8048cd0行,mov $0x1,%eax,將1放入了 eax裡面,然後退棧,所以,當引數為1時候,返回值為1;
程式碼應該是這樣的:
int func4(int a) {
if (a <= 1)
return 1;
else
return func4(a-1) + func4(a-2);
}
演算法相當於:
f0=1
f1=1
f2=f1+f0
f3=f2+f1
......
fn=f(n-1)+f(n-2)
寫程式碼算一下:
#include<iostream>
using namespace std;
int func4(int a) {
if (a <= 1)
return 1;
else
return func4(a - 1) + func4(a - 2);
}
int main()
{
int i;
for (i = 0;i < 1000;i++)
{
if (func4(i) == 55)
{
cout << i << endl;
break;
}
}
return 0;
}
得出結果是9。
所以,答案是9!!!
第五關
第五關的程式碼如下:
在之間出現了兩個字串的地址,一個是0x804b220,另一個是0x804980b ,那麼,我們先看看那是什麼字串:
看來是”isrveawhobpnutfg\260\001”和”giants”。
因為,這個迴圈做了6次,而且,匹配的字串”giants”也是六個字元,所以,一定是和”giants”比較,但是怎麼比較呢?
要在”isrveawhobpnutfg\260\001”中間取到”giants”的字元順序是 15 0 5 11 13 1,這樣是不是說明直接輸入”giants”就可以了呢?
所以,很明顯,不是,為什麼呢?
因為,輸入的是 字元ASC碼二進位制後四位的數字為這六個數字,所以,還是翻翻ASC碼錶吧!
我們就選擇第二列吧,第二列比較好玩,哈哈哈哈,?05;=1(記得一定要是英文,半形的符號),或者是0O5KM1等等都給可以…..
第六關
這是第六關的整個彙編的程式碼:
- 明顯是要輸入6個數字。讀取6個數,存放在ebp-18的地方,所以,ebp-18應該是一個數組首地址。
- 我們看看這一句線索是什麼東西!!
8048da4: c7 45 cc 6c b2 04 08 movl $0x804b26c,-0x34(%ebp)
原來是一個地址。
程式碼大概是這樣的:
for (int i =0; i<=5; i++){
for (int j = i+1; j<=5; j++){
if (A[i]<= 6&&(A[i]!=A[j]))
{
continue;
}
else
explode_bomb();
}
}
所以,這一關輸入的元素就只有 1,2,3,4,5,6;
但是,不是按照這個順序輸入的!!!!(不會告訴你,我為什麼知道的,哈哈哈哈哈)
按照排列組合,A(6,6)=6*5*4*3*2*1=720 種 答案。所以範圍已經縮小了。
8048e02: 31 ff xor %edi,%edi // i清零
8048e04: 8d4d e8 lea -0x18(%ebp),%ecx //陣列首地址A
8048e07: 8d45 d0 lea -0x30(%ebp),%eax //ebp-0x30的地址
8048e0a: 8945 c4 mov %eax,-0x3c(%ebp) //存放於ebp-0x3c中
8048e0d: 8d76 00 lea 0x0(%esi),%esi
8048e10: 8b75 cc mov -0x34(%ebp),%esi //取ebp-34中值
8048e13: bb01 00 00 00 mov $0x1,%ebx // j = 1
8048e18: 8d04 bd 00 00 00 00 lea 0x0(,%edi,4),%eax //eax = edi * 4
8048e1f: 89c2 mov %eax,%edx
8048e21: 3b1c 08 cmp (%eax,%ecx,1),%ebx //A[i] 與 j比較
8048e24: 7d12 jge 8048e38 <phase_6+0xa0> //小於的話,進入迴圈
8048e26: 8b04 0a mov (%edx,%ecx,1),%eax //eax = A[i]
8048e29: 8db4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
8048e30: 8b76 08 mov 0x8(%esi),%esi //esi+0x8的值給esi
8048e33: 43 inc %ebx //j++
8048e34: 39c3 cmp %eax,%ebx //A[i] == j 停止迴圈
8048e36: 7cf8 jl 8048e30 <phase_6+0x98>
8048e38: 8b55 c4 mov -0x3c(%ebp),%edx //獲得ebp-0x30地址
8048e3b: 8934 ba mov %esi,(%edx,%edi,4) //esi存入新陣列中
8048e3e: 47 inc %edi
8048e3f: 83ff 05 cmp $0x5,%edi
8048e42: 7ecc jle 8048e10 <phase_6+0x78>
記得剛剛我們看到那個節點是一個地址,從程式碼可以看出每次移動了0x8,然後傳遞,現在,呼叫:
gdb) x /3x 0x804b26c ,這個指令的意思為:以16進位制格式顯示地址0x804b26c處3個單位,預設每個單位四位元組的內容。
這說明是6個節點的內容,尾部是一個指標指向下一個節點的內容。
for (int i =0; i<=5; i++){
for (int j =0; A[i]> j; j++){
node = node.next;
}
P[i]= node;
}
所以,P[i]這個陣列所放的節點順序,就是輸入數字的順序!!比如:輸入 4,2,5,3,1,那就是 node[4],node[2],node[5],node[3],node[1],的排列順序!!
這段程式碼就只是起連線作用:
8048e44: 8b 75 d0 mov -0x30(%ebp),%esi //取ptr地址
8048e47: 8975 cc mov %esi,-0x34(%ebp) //存於ebp – 0x34中
8048e4a: bf01 00 00 00 mov $0x1,%edi // i = 1
8048e4f: 8d55 d0 lea -0x30(%ebp),%edx //ebp-0x30地址
8048e52: 8b04 ba mov (%edx,%edi,4),%eax //ptr[i] => eax
8048e55: 8946 08 mov %eax,0x8(%esi) //ptr[i-1]->next = ptr[i]
8048e58: 89c6 mov %eax,%esi //esi = ptr[i]
8048e5a: 47 inc %edi
8048e5b: 83ff 05 cmp $0x5,%edi
8048e5e: 7ef2 jle 8048e52 <phase_6+0xba>
8048e60: c746 08 00 00 00 00 movl $0x0,0x8(%esi)
8048e67: 8b75 cc mov -0x34(%ebp),%esi //最後一個結點next 賦0
那麼,看看這樣子排列究竟有什麼用呢?
最後,連結串列的判斷:
原來,是想把按照節點中 數字大小的順序輸入數字!!!
節點的數字是什麼呢?我們再看看:
原來分別是
0x0fd
0x2d5
0x12d
0x3e5
0x0d4
0x1b0
所以,大小順序就是,4,2,6,3,1,5。
所以答案就是:4 2 6 3 1 5 !!!!!!!
整個花了大概25個小時才做完。非常不容易,很多組合語言在百度上解釋是有錯誤的。
附上答案:
Public speaking is very easy.
1 2 6 24 120 720
0 q 777(答案不唯一)
9
?05;=1或者0O5KM1等等(答案不唯一)
4 2 6 3 1 5
反編譯後的程式碼:
bomb: file format elf32-i386
Disassembly of section .init:
080486e0 <_init>:
80486e0: 55 push %ebp
80486e1: 89 e5 mov %esp,%ebp
80486e3: 53 push %ebx
80486e4: e8 00 00 00 00 call 80486e9 <_init+0x9>
80486e9: 5b pop %ebx
80486ea: 81 c3 2f 2e 00 00 add $0x2e2f,%ebx
80486f0: 83 bb 7c 00 00 00 00 cmpl $0x0,0x7c(%ebx)
80486f7: 74 05 je 80486fe <_init+0x1e>
80486f9: e8 02 79 fb f7 call 0 <_init-0x80486e0>
80486fe: 89 f6 mov %esi,%esi
8048700: e8 6b 02 00 00 call 8048970 <frame_dummy>
8048705: e8 a6 0e 00 00 call 80495b0 <__do_global_ctors_aux>
804870a: 8b 5d fc mov -0x4(%ebp),%ebx
804870d: c9 leave
804870e: c3 ret
Disassembly of section .plt:
08048710 <__register_frame_info@plt-0x10>:
8048710: ff 35 1c b5 04 08 pushl 0x804b51c
8048716: ff 25 20 b5 04 08 jmp *0x804b520
804871c: 00 00 add %al,(%eax)
...
08048720 <__register_frame_info@plt>:
8048720: ff 25 24 b5 04 08 jmp *0x804b524
8048726: 68 00 00 00 00 push $0x0
804872b: e9 e0 ff ff ff jmp 8048710 <_init+0x30>
08048730 <close@plt>:
8048730: ff 25 28 b5 04 08 jmp *0x804b528
8048736: 68 08 00 00 00 push $0x8
804873b: e9 d0 ff ff ff jmp 8048710 <_init+0x30>
08048740 <fprintf@plt>:
8048740: ff 25 2c b5 04 08 jmp *0x804b52c
8048746: 68 10 00 00 00 push $0x10
804874b: e9 c0 ff ff ff jmp 8048710 <_init+0x30>
08048750 <tmpfile@plt>:
8048750: ff 25 30 b5 04 08 jmp *0x804b530
8048756: 68 18 00 00 00 push $0x18
804875b: e9 b0 ff ff ff jmp 8048710 <_init+0x30>
08048760 <getenv@plt>:
8048760: ff 25 34 b5 04 08 jmp *0x804b534
8048766: 68 20 00 00 00 push $0x20
804876b: e9 a0 ff ff ff jmp 8048710 <_init+0x30>
08048770 <signal@plt>:
8048770: ff 25 38 b5 04 08 jmp *0x804b538
8048776: 68 28 00 00 00 push $0x28
804877b: e9 90 ff ff ff jmp 8048710 <_init+0x30>
08048780 <fflush@plt>:
8048780: ff 25 3c b5 04 08 jmp *0x804b53c
8048786: 68 30 00 00 00 push $0x30
804878b: e9 80 ff ff ff jmp 8048710 <_init+0x30>
08048790 <bcopy@plt>:
8048790: ff 25 40 b5 04 08 jmp *0x804b540
8048796: 68 38 00 00 00 push $0x38
804879b: e9 70 ff ff ff jmp 8048710 <_init+0x30>
080487a0 <rewind@plt>:
80487a0: ff 25 44 b5 04 08 jmp *0x804b544
80487a6: 68 40 00 00 00 push $0x40
80487ab: e9 60 ff ff ff jmp 8048710 <_init+0x30>
080487b0 <system@plt>:
80487b0: ff 25 48 b5 04 08 jmp *0x804b548
80487b6: 68 48 00 00 00 push $0x48
80487bb: e9 50 ff ff ff jmp 8048710 <_init+0x30>
080487c0 <__deregister_frame_info@plt>:
80487c0: ff 25 4c b5 04 08 jmp *0x804b54c
80487c6: 68 50 00 00 00 push $0x50
80487cb: e9 40 ff ff ff jmp 8048710 <_init+0x30>
080487d0 <fgets@plt>:
80487d0: ff 25 50 b5 04 08 jmp *0x804b550
80487d6: 68 58 00 00 00 push $0x58
80487db: e9 30 ff ff ff jmp 8048710 <_init+0x30>
080487e0 <sleep@plt>:
80487e0: ff 25 54 b5 04 08 jmp *0x804b554
80487e6: 68 60 00 00 00 push $0x60
80487eb: e9 20 ff ff ff jmp 8048710 <_init+0x30>
080487f0 <__strtol_internal@plt>:
80487f0: ff 25 58 b5 04 08 jmp *0x804b558
80487f6: 68 68 00 00 00 push $0x68
80487fb: e9 10 ff ff ff jmp 8048710 <_init+0x30>
08048800 <__libc_start_main@plt>:
8048800: ff 25 5c b5 04 08 jmp *0x804b55c
8048806: 68 70 00 00 00 push $0x70
804880b: e9 00 ff ff ff jmp 8048710 <_init+0x30>
08048810 <printf@plt>:
8048810: ff 25 60 b5 04 08 jmp *0x804b560
8048816: 68 78 00 00 00 push $0x78
804881b: e9 f0 fe ff ff jmp 8048710 <_init+0x30>
08048820 <fclose@plt>:
8048820: ff 25 64 b5 04 08 jmp *0x804b564
8048826: 68 80 00 00 00 push $0x80
804882b: e9 e0 fe ff ff jmp 8048710 <_init+0x30>
08048830 <gethostbyname@plt>:
8048830: ff 25 68 b5 04 08 jmp *0x804b568
8048836: 68 88 00 00 00 push $0x88
804883b: e9 d0 fe ff ff jmp 8048710 <_init+0x30>
08048840 <bzero@plt>:
8048840: ff 25 6c b5 04 08 jmp *0x804b56c
8048846: 68 90 00 00 00 push $0x90
804884b: e9 c0 fe ff ff jmp 8048710 <_init+0x30>
08048850 <exit@plt>:
8048850: ff 25 70 b5 04 08 jmp *0x804b570
8048856: 68 98 00 00 00 push $0x98
804885b: e9 b0 fe ff ff jmp 8048710 <_init+0x30>
08048860 <sscanf@plt>:
8048860: ff 25 74 b5 04 08 jmp *0x804b574
8048866: 68 a0 00 00 00 push $0xa0
804886b: e9 a0 fe ff ff jmp 8048710 <_init+0x30>
08048870 <connect@plt>:
8048870: ff 25 78 b5 04 08 jmp *0x804b578
8048876: 68 a8 00 00 00 push $0xa8
804887b: e9 90 fe ff ff jmp 8048710 <_init+0x30>
08048880 <fopen@plt>:
8048880: ff 25 7c b5 04 08 jmp *0x804b57c
8048886: 68 b0 00 00 00 push $0xb0
804888b: e9 80 fe ff ff jmp 8048710 <_init+0x30>
08048890 <dup@plt>:
8048890: ff 25 80 b5 04 08 jmp *0x804b580
8048896: 68 b8 00 00 00 push $0xb8
804889b: e9 70 fe ff ff jmp 8048710 <_init+0x30>
080488a0 <sprintf@plt>:
80488a0: ff 25 84 b5 04 08 jmp *0x804b584
80488a6: 68 c0 00 00 00 push $0xc0
80488ab: e9 60 fe ff ff jmp 8048710 <_init+0x30>
080488b0 <socket@plt>:
80488b0: ff 25 88 b5 04 08 jmp *0x804b588
80488b6: 68 c8 00 00 00 push $0xc8
80488bb: e9 50 fe ff ff jmp 8048710 <_init+0x30>
080488c0 <cuserid@plt>:
80488c0: ff 25 8c b5 04 08 jmp *0x804b58c
80488c6: 68 d0 00 00 00 push $0xd0
80488cb: e9 40 fe ff ff jmp 8048710 <_init+0x30>
080488d0 <strcpy@plt>:
80488d0: ff 25 90 b5 04 08 jmp *0x804b590
80488d6: 68 d8 00 00 00 push $0xd8
80488db: e9 30 fe ff ff jmp 8048710 <_init+0x30>
Disassembly of section .text:
080488e0 <_start>:
80488e0: 31 ed xor %ebp,%ebp
80488e2: 5e pop %esi
80488e3: 89 e1 mov %esp,%ecx
80488e5: 83 e4 f8 and $0xfffffff8,%esp
80488e8: 50 push %eax
80488e9: 54 push %esp
80488ea: 52 push %edx
80488eb: 68 e4 95 04 08 push $0x80495e4
80488f0: 68 e0 86 04 08 push $0x80486e0
80488f5: 51 push %ecx
80488f6: 56 push %esi
80488f7: 68 b0 89 04 08 push $0x80489b0
80488fc: e8 ff fe ff ff call 8048800 <__libc_start_main@plt>
8048901: f4 hlt
8048902: 90 nop
8048903: 90 nop
08048904 <gcc2_compiled.>:
8048904: 90 90 90 90 90 90 90 90 90 90 90 90 ............
08048910 <__do_global_dtors_aux>:
8048910: 55 push %ebp
8048911: 89 e5 mov %esp,%ebp
8048913: 83 ec 08 sub $0x8,%esp
8048916: 83 3d e8 ad 04 08 00 cmpl $0x0,0x804ade8
804891d: 75 3e jne 804895d <__do_global_dtors_aux+0x4d>
804891f: eb 12 jmp 8048933 <__do_global_dtors_aux+0x23>
8048921: a1 e4 ad 04 08 mov 0x804ade4,%eax
8048926: 8d 50 04 lea 0x4(%eax),%edx
8048929: 89 15 e4 ad 04 08 mov %edx,0x804ade4
804892f: 8b 00 mov (%eax),%eax
8048931: ff d0 call *%eax
8048933: a1 e4 ad 04 08 mov 0x804ade4,%eax
8048938: 83 38 00 cmpl $0x0,(%eax)
804893b: 75 e4 jne 8048921 <__do_global_dtors_aux+0x11>
804893d: b8 c0 87 04 08 mov $0x80487c0,%eax
8048942: 85 c0 test %eax,%eax
8048944: 74 0d je 8048953 <__do_global_dtors_aux+0x43>
8048946: 83 c4 f4 add $0xfffffff4,%esp
8048949: 68 84 b4 04 08 push $0x804b484
804894e: e8 6d fe ff ff call 80487c0 <__deregister_frame_info@plt>
8048953: c7 05 e8 ad 04 08 01 movl $0x1,0x804ade8
804895a: 00 00 00
804895d: 89 ec mov %ebp,%esp
804895f: 5d pop %ebp
8048960: c3 ret
8048961: 8d 76 00 lea 0x0(%esi),%esi
08048964 <fini_dummy>:
8048964: 55 push %ebp
8048965: 89 e5 mov %esp,%ebp
8048967: 83 ec 08 sub $0x8,%esp
804896a: 89 ec mov %ebp,%esp
804896c: 5d pop %ebp
804896d: c3 ret
804896e: 89 f6 mov %esi,%esi
08048970 <frame_dummy>:
8048970: 55 push %ebp
8048971: 89 e5 mov %esp,%ebp
8048973: 83 ec 08 sub $0x8,%esp
8048976: b8 20 87 04 08 mov $0x8048720,%eax
804897b: 85 c0 test %eax,%eax
804897d: 74 12 je 8048991 <frame_dummy+0x21>
804897f: 83 c4 f8 add $0xfffffff8,%esp
8048982: 68 4c b6 04 08 push $0x804b64c
8048987: 68 84 b4 04 08 push $0x804b484
804898c: e8 8f fd ff ff call 8048720 <__register_frame_info@plt>
8048991: 89 ec mov %ebp,%esp
8048993: 5d pop %ebp
8048994: c3 ret
8048995: 8d 76 00 lea 0x0(%esi),%esi
08048998 <init_dummy>:
8048998: 55 push %ebp
8048999: 89 e5 mov %esp,%ebp
804899b: 83 ec 08 sub $0x8,%esp
804899e: 89 ec mov %ebp,%esp
80489a0: 5d pop %ebp
80489a1: c3 ret
80489a2: 90 nop
80489a3: 90 nop
80489a4: 90 nop
80489a5: <