上一篇【爲拆炸彈實驗做的預習與準備】講述了一些必須的知識
這個實驗是給出可執行文件,要求用gdb反編譯出彙編代碼,一共有6個關卡,要求玩家輸入6個輸入,要通過分析彙編代碼來找到何種輸入不會觸發炸彈,然後輸入正確的輸入信息以拆解炸彈
第一關 字符串比對
彙編原碼及個人註釋
0000000000400e70 <phase_1>:
400e70: 48 83 ec 08 sub $0x8,%rsp // 開棧
400e74: be f8 1a 40 00 mov $0x401af8,%esi // 函數的第二個參數是$0x401af8,猜測是常量字符串
400e79: e8 bf 03 00 00 callq 40123d <strings_not_equal>
400e7e: 85 c0 test %eax,%eax // 返回值等於0,即兩個字符串相等,則結束否則bomb
400e80: 74 05 je 400e87 <phase_1+0x17>
400e82: e8 b6 07 00 00 callq 40163d <explode_bomb>
400e87: 48 83 c4 08 add $0x8,%rsp // 退棧
400e8b: c3
前三句是壓棧,調用一個strings_not_equal
函數,根據英文閱讀理解,判斷這個函數是輸入和一常量字符串比較判斷是否相同,如果不同則返回true(1),如果相同則返回false(0)
然後根據返回值,用je進行跳轉,如果eax即函數返回值爲0則跳轉成功,不會觸發<explode_bomb>,然後關注到它將0x401af8賦值給esi,函數string_not_equal
的第二個參數,而第一個參數仍然是phase1調用的第一個參數,應該是輸入值,所以我猜測這第二個參數是一個常量字符串的地址,於是gdb試一下,gdb查看對應內存地址的字符串
發現這個常量字符串是Science isn’t about why, it’s about why not? 結合上面的分析不難看出,輸入串必須與其相等,方可通關!
答案:
Science isn't about why, it's about why not?
第二關:數組與循環
彙編源碼及個人註釋
0000000000400e8c <phase_2>:
400e8c: 48 89 5c 24 e0 mov %rbx,-0x20(%rsp) // 保存父函數數據,壓棧
400e91: 48 89 6c 24 e8 mov %rbp,-0x18(%rsp)
400e96: 4c 89 64 24 f0 mov %r12,-0x10(%rsp)
400e9b: 4c 89 6c 24 f8 mov %r13,-0x8(%rsp)
400ea0: 48 83 ec 48 sub $0x48,%rsp // 開棧
400ea4: 48 89 e6 mov %rsp,%rsi // 棧頂指針給到第二個參數
400ea7: e8 97 08 00 00 callq 401743 <read_six_numbers> // 調用函數讀數據
400eac: 48 89 e5 mov %rsp,%rbp // 保存棧指針到rbp
400eaf: 4c 8d 6c 24 0c lea 0xc(%rsp),%r13 // 棧指針+12保存到r13
400eb4: 41 bc 00 00 00 00 mov $0x0,%r12d // r12低32位清零
// ----------------------------------------------------- 循環 -------------------------------------------- //
400eba: 48 89 eb mov %rbp,%rbx // rbp的值保存到rbx,【下文跳轉到這】
400ebd: 8b 45 0c mov 0xc(%rbp),%eax // M[rbp+12]保存到eax
400ec0: 39 45 00 cmp %eax,0x0(%rbp) // 看 M[rbp] 和 M[rbp+12] 是否相等
400ec3: 74 05 je 400eca <phase_2+0x3e> // 如果M[rbp]和M[rbp+12]不等則bomb
400ec5: e8 73 07 00 00 callq 40163d <explode_bomb>
400eca: 44 03 23 add (%rbx),%r12d // r12 += M[rbx]
400ecd: 48 83 c5 04 add $0x4,%rbp // rbp += 4,rbp爲迭代指針
400ed1: 4c 39 ed cmp %r13,%rbp // r13和rbp如果不等則跳轉
400ed4: 75 e4 jne 400eba <phase_2+0x2e>
// ---------------------------------------------------- 循環結束 ------------------------------------------ //
400ed6: 45 85 e4 test %r12d,%r12d // r12d是累加值,累加值爲0則bomb
400ed9: 75 05 jne 400ee0 <phase_2+0x54>
400edb: e8 5d 07 00 00 callq 40163d <explode_bomb>
400ee0: 48 8b 5c 24 28 mov 0x28(%rsp),%rbx // 退棧
400ee5: 48 8b 6c 24 30 mov 0x30(%rsp),%rbp
400eea: 4c 8b 64 24 38 mov 0x38(%rsp),%r12
400eef: 4c 8b 6c 24 40 mov 0x40(%rsp),%r13
400ef4: 48 83 c4 48 add $0x48,%rsp
400ef8: c3 retq
可以清晰的看到,一開始先讀取6個數(英文閱讀理解可知),然後使用rbp作爲迭代指針,rbp+12爲迭代終點,一共迭代三次,而每次我們都將M[rbp] 和 M[rbp+12] 處的數據比對,如果不等則bomb,而且一個int剛好是4字節,三個就是12!結合剛剛的讀取6個數字,可以大膽的猜測,這是在判斷 a[i] 和 a[i+3] 是否相等!
r12之前清零,但是每次又 += M[rbx],猜測 是在計算累加和,根據後文的test $r12d $r12d,可以知道,如果三個數累加起來是0,即使a[i] = a[i+3] 也會炸,所以可以拆彈了!
因爲1145141919810是好數字,不妨輸入 114 514 1919810 114 514 1919810,可以滿足條件!
答案:
114 514 1919810 114 514 1919810
a b c a b c 且 (a+b+c)!=0 即可
第三關switch
彙編源碼及個人註釋
0000000000400ef9 <phase_3>:
400ef9: 48 83 ec 18 sub $0x18,%rsp // 開棧
400efd: 48 8d 4c 24 08 lea 0x8(%rsp),%rcx // rcx = rsp+8 第四個參數
400f02: 48 8d 54 24 0c lea 0xc(%rsp),%rdx // rdx = rsp+12 第三個參數
400f07: be be 1e 40 00 mov $0x401ebe,%esi // 第二個參數 gdb查找這個字符串的值是 "%d %d"
400f0c: b8 00 00 00 00 mov $0x0,%eax // 返回值低32字節置0
400f11: e8 9a fb ff ff callq 400ab0 <__isoc99_sscanf@plt> // 讀數據
400f16: 83 f8 01 cmp $0x1,%eax // scanf返回不爲1則bomb
400f19: 7f 05 jg 400f20 <phase_3+0x27>
400f1b: e8 1d 07 00 00 callq 40163d <explode_bomb>
400f20: 83 7c 24 0c 07 cmpl $0x7,0xc(%rsp) // 7 < M[rsp+12](第一個%d) 則跳轉到bomb
400f25: 77 3c ja 400f63 <phase_3+0x6a>
400f27: 8b 44 24 0c mov 0xc(%rsp),%eax // M[rsp+12](第一個%d)存到eax
400f2b: ff 24 c5 60 1b 40 00 jmpq *0x401b60(,%rax,8) // 跳轉到 M[0x401b60+ 8*rax] 地址
400f32: b8 17 02 00 00 mov $0x217,%eax // if rax=0則到這裏,eax=535
400f37: eb 3b jmp 400f74 <phase_3+0x7b>
400f39: b8 d6 00 00 00 mov $0xd6,%eax // if rax=2則到這裏,eax=214
400f3e: eb 34 jmp 400f74 <phase_3+0x7b>
400f40: b8 53 01 00 00 mov $0x153,%eax // if rax=3則到這裏,eax=339
400f45: eb 2d jmp 400f74 <phase_3+0x7b>
400f47: b8 77 00 00 00 mov $0x77,%eax // if rax=4則到這裏,eax=119
400f4c: eb 26 jmp 400f74 <phase_3+0x7b>
400f4e: b8 60 01 00 00 mov $0x160,%eax // if rax=5則到這裏,eax=352
400f53: eb 1f jmp 400f74 <phase_3+0x7b>
400f55: b8 97 03 00 00 mov $0x397,%eax // if rax=6則到這裏,eax=919
400f5a: eb 18 jmp 400f74 <phase_3+0x7b>
400f5c: b8 9c 01 00 00 mov $0x19c,%eax // if rax=7則到這裏,eax=412
400f61: eb 11 jmp 400f74 <phase_3+0x7b>
400f63: e8 d5 06 00 00 callq 40163d <explode_bomb> // bomb
400f68: b8 00 00 00 00 mov $0x0,%eax
400f6d: eb 05 jmp 400f74 <phase_3+0x7b>
400f6f: b8 9e 03 00 00 mov $0x39e,%eax // if rax=1則到這裏,eax=926
400f74: 3b 44 24 08 cmp 0x8(%rsp),%eax // switch轉到這裏,如果第二個%d不等於eax,則bomb
400f78: 74 05 je 400f7f <phase_3+0x86>
400f7a: e8 be 06 00 00 callq 40163d <explode_bomb>
400f7f: 48 83 c4 18 add $0x18,%rsp // 退棧
400f83: c3 retq
先關注scanf調用前,傳入第三第四個參數了,他們存在rsp+8和rsp+12位置,從間距來看應該是int(4字節嘛),然後又向esi傳入常量,推測是scanf格式確定的字符串,查看,果然,是“%d %d”,基本可以確定輸入的是兩個整數
然後注意到返回後判斷了第一個數是否大於7,如果是則bomb,那麼可以確定第一個數取值爲0~7
然後有一個變址跳轉,目的地址是M[0x401b60 + rax*8]
,rax是第一個%d,然後看看跳轉之後的地址,在gdb中打印,分別對應第一個輸入爲0~7
時跳轉的目的地址
如圖,從上到下對應0~7的跳轉,見上面註釋部分
跳轉之後,爲第一個輸入的變量賦新值,然後判斷第二個%d輸入(rsp+8)和他是否相等,不等則bomb,那麼思路很明確了,就是第一個值決定switch,然後判斷第二個值是否對應,觀察switch可知,這裏有8個答案
答案(選一即可)
0 535
1 926
2 214
3 339
4 119
5 352
6 919
7 412
第四關遞歸(斐波那契第n項)
彙編源碼及個人註釋
0000000000400fc1 <phase_4>:
400fc1: 48 83 ec 18 sub $0x18,%rsp // 開棧
400fc5: 48 8d 54 24 0c lea 0xc(%rsp),%rdx // rdx=rsp+12,設置第三個參數爲rsp+12,即存放輸入
400fca: be c1 1e 40 00 mov $0x401ec1,%esi // 根據上面幾題的經驗應該是scanf的格式字串,爲%d
400fcf: b8 00 00 00 00 mov $0x0,%eax // eax置零
400fd4: e8 d7 fa ff ff callq 400ab0 <__isoc99_sscanf@plt>
400fd9: 83 f8 01 cmp $0x1,%eax // scanf返回值是否爲1?不爲1則bomb
400fdc: 75 07 jne 400fe5 <phase_4+0x24>
400fde: 83 7c 24 0c 00 cmpl $0x0,0xc(%rsp) // 進一步比較輸入的int是否大於0
400fe3: 7f 05 jg 400fea <phase_4+0x29>
400fe5: e8 53 06 00 00 callq 40163d <explode_bomb> // 輸入的int爲0也bomb
400fea: 8b 7c 24 0c mov 0xc(%rsp),%edi // 如果輸入int大於0則到這裏,設置fun4第一個參數爲輸入的int
400fee: e8 91 ff ff ff callq 400f84 <func4>
400ff3: 83 f8 37 cmp $0x37,%eax // 返回值是否爲55?
400ff6: 74 05 je 400ffd <phase_4+0x3c>
400ff8: e8 40 06 00 00 callq 40163d <explode_bomb> // 返回值不爲55則bomb
400ffd: 48 83 c4 18 add $0x18,%rsp // 返回值爲55則退棧
401001: c3 retq
同樣觀察參數,發現這次scanf只讀一個參數,根據前面的經驗不難看出,0x401ec1存儲的是scanf的常字符串,那麼gdb查看他,發現是一個int
然後往下看,讀取的int必須大於0,再看,使用我們輸入的int做了一個函數fun4的參數,如果fun4的返回值爲55則退棧,否則bomb,看來問題聚焦在fun4上了,查看fun4:
0000000000400f84 <func4>:
400f84: 48 89 5c 24 f0 mov %rbx,-0x10(%rsp)
400f89: 48 89 6c 24 f8 mov %rbp,-0x8(%rsp)
400f8e: 48 83 ec 18 sub $0x18,%rsp // 開棧
400f92: 89 fb mov %edi,%ebx
400f94: b8 01 00 00 00 mov $0x1,%eax // 返回值置1
400f99: 83 ff 01 cmp $0x1,%edi // 如果第一個參數爲1,直接返回(此時返回值是1)
400f9c: 7e 14 jle 400fb2 <func4+0x2e>
400f9e: 8d 7b ff lea -0x1(%rbx),%edi // 設置第一個參數 edi = rbx -1,再遞歸調用fun4
400fa1: e8 de ff ff ff callq 400f84 <func4>
400fa6: 89 c5 mov %eax,%ebp // 返回值保存到 ebp
400fa8: 8d 7b fe lea -0x2(%rbx),%edi // 設置第一個參數 edi = rbx -2,再遞歸調用fun4
400fab: e8 d4 ff ff ff callq 400f84 <func4>
400fb0: 01 e8 add %ebp,%eax // ebp += 返回值
400fb2: 48 8b 5c 24 08 mov 0x8(%rsp),%rbx // 退棧
400fb7: 48 8b 6c 24 10 mov 0x10(%rsp),%rbp
400fbc: 48 83 c4 18 add $0x18,%rsp
400fc0: c3 retq
Fun4一進來判斷輸入,如果是1返回1,如果不是,返回fun4(x-1)+fun4(x-2),顯然這是斐波那契數列,那麼fib的第幾項等於55呢?應該是9,看:[1,1,2,3,5,8,13,21,55]
答案:
9
第五關:跳轉數組
彙編源碼及個人註釋
0000000000401002 <phase_5>:
401002: 48 83 ec 18 sub $0x18,%rsp // 開棧
401006: 48 8d 4c 24 08 lea 0x8(%rsp),%rcx // 第四個參數 += M[rsp+8]
40100b: 48 8d 54 24 0c lea 0xc(%rsp),%rdx // 第三個參數 += M[rsp+12]
401010: be be 1e 40 00 mov $0x401ebe,%esi // 第二個參數,gdb查看內容爲"%d %d"
401015: b8 00 00 00 00 mov $0x0,%eax // eax清零
40101a: e8 91 fa ff ff callq 400ab0 <__isoc99_sscanf@plt>
40101f: 83 f8 01 cmp $0x1,%eax // 如果eax<=1那麼bomb
401022: 7f 05 jg 401029 <phase_5+0x27>
401024: e8 14 06 00 00 callq 40163d <explode_bomb>
401029: 8b 44 24 0c mov 0xc(%rsp),%eax // eax = M[rsp+12],即輸入的第一個int
40102d: 83 e0 0f and $0xf,%eax // eax &= f,即保留低4位
401030: 89 44 24 0c mov %eax,0xc(%rsp) // M[rsp+12] = eax ,即保留eax的低4位
401034: 83 f8 0f cmp $0xf,%eax // 如果eax = 15那麼bomb
401037: 74 2c je 401065 <phase_5+0x63>
401039: b9 00 00 00 00 mov $0x0,%ecx // ecx清零
40103e: ba 00 00 00 00 mov $0x0,%edx // edx清零
// -------------------------------------------------- 循環 ---------------------------------------------------------//
401043: 83 c2 01 add $0x1,%edx // edx += 1 ,記錄循環次數
401046: 48 98 cltq // 拓展字節
401048: 8b 04 85 a0 1b 40 00 mov 0x401ba0(,%rax,4),%eax // eax = M[0x401ba0+rax*4] (eax rax是一個寄存器)
40104f: 01 c1 add %eax,%ecx // ecx += eax,記錄累加值
401051: 83 f8 0f cmp $0xf,%eax // 如果eax不等於15則繼續
401054: 75 ed jne 401043 <phase_5+0x41>
// ------------------------------------------------ 循環結束 -------------------------------------------------------//
401056: 89 44 24 0c mov %eax,0xc(%rsp) // M[rsp+12] = eax,即=15
40105a: 83 fa 0c cmp $0xc,%edx // 如果edx(循環次數)不等於12則bomb
40105d: 75 06 jne 401065 <phase_5+0x63>
40105f: 3b 4c 24 08 cmp 0x8(%rsp),%ecx // M[rsp+8]即輸入的第二個int,不等於ecx則bomb
401063: 74 05 je 40106a <phase_5+0x68>
401065: e8 d3 05 00 00 callq 40163d <explode_bomb>
40106a: 48 83 c4 18 add $0x18,%rsp // 退棧
40106e: c3 retq
一開始還是觀察scanf的輸入,兩個lea語句將scanf的第三第四個參數確定,gdb esi的地址查看輸入格式,發現是%d%d兩個int
然後發現第一個輸出是會被截斷到0~15的,如果第一個輸入等於15那麼直接炸
關注之後的語句,發現有一個循環,edx每次++,eax每次指向內存中的一個地址,因爲eax和rax是同一個,相當於 k = next[k]
這種數組跳轉語句,而且偏移的單位是4字節,剛好是一個int,這更加堅定了這裏出現數組跳轉語句的判斷了,gdb查看這個數組,果然
那麼知道了跳轉數組之後,發現跳轉次數只能是12,而且,第二個輸入的int必須等於每次跳轉的目標下標的累加和,而且最後一次跳轉的結果是15,所以畫跳轉路徑:
要想跳轉12次纔到15,這裏需要從15反推路徑,推出了是從7下標開始,跳轉12次即可到達15,而將他們加和起來,累加和是
11+13+9+4+8+0+10+1+2+14+6+15 = 93
答案
7 93
第六關:
這題我沒看懂,但是最後有一個比較,如果不等則bomb,我是通過gdb讀取cmp的比較值,來猜輸入是哪個數字的,屬於投機取巧法
彙編源碼及個人註釋
00000000004010d9 <phase_6>:
4010d9: 48 83 ec 08 sub $0x8,%rsp // 開棧
4010dd: ba 0a 00 00 00 mov $0xa,%edx // 第三個參數=10,strtol轉換基數爲10
4010e2: be 00 00 00 00 mov $0x0,%esi // 第二個參數=0
4010e7: e8 94 fa ff ff callq 400b80 <strtol@plt> // 將字符串根據基數轉換爲長整型數
4010ec: 89 05 8e 16 20 00 mov %eax,0x20168e(%rip) # 602780 <node0> // M[20168e+rip] = eax(返回值)
4010f2: bf 80 27 60 00 mov $0x602780,%edi // edi爲第一個參數,這個位置應該是輸入的字符串
4010f7: e8 73 ff ff ff callq 40106f <fun6>
4010fc: 48 8b 40 08 mov 0x8(%rax),%rax // rax = M[rax+8] rax:返回值
401100: 48 8b 40 08 mov 0x8(%rax),%rax // rax = M[rax+8]
401104: 48 8b 40 08 mov 0x8(%rax),%rax // rax = M[rax+8]
401108: 8b 15 72 16 20 00 mov 0x201672(%rip),%edx # 602780 <node0> // edx = M[201672+rip]
40110e: 39 10 cmp %edx,(%rax) // 如果edx 不等於 rax則bomb
401110: 74 05 je 401117 <phase_6+0x3e>
401112: e8 26 05 00 00 callq 40163d <explode_bomb>
401117: 48 83 c4 08 add $0x8,%rsp // 退棧
40111b: c3 retq
這裏一開始調用strtol,同時傳入一個字符串,這個字符串的位置是0x602780
推測是讓我們輸入一個字符串,然後轉換爲long,然後這個long會傳入fun6,一頓操作之後,附帶幾次尋址,比較 rdx 和M[rax] 的值,如果不相等則炸,那麼關鍵點就在fun6了,查看fun6代碼:
000000000040106f <fun6>:
40106f: 4c 8b 47 08 mov 0x8(%rdi),%r8 // 第五個參數 = M[rdi(第一個參數)+8]
401073: 48 c7 47 08 00 00 00 movq $0x0,0x8(%rdi) // M[rdi+8] = 0
40107a: 00
40107b: 48 89 f8 mov %rdi,%rax // rax = rdi
40107e: 48 89 f9 mov %rdi,%rcx // rcx = rdi
401081: 4d 85 c0 test %r8,%r8 // 第五個參數不等於0則跳轉
401084: 75 40 jne 4010c6 <fun6+0x57>
401086: 48 89 f8 mov %rdi,%rax // rax = rdi(第一個參數)
401089: c3 retq // 退棧
// -------------------------------------------------- 循環 ---------------------------------------------------------//
40108a: 48 89 d1 mov %rdx,%rcx // rcx = rdx
40108d: 48 8b 51 08 mov 0x8(%rcx),%rdx // rdx = M[rcx+8],即rdx=M[rdx+8]
401091: 48 85 d2 test %rdx,%rdx // 如果rdx=0則跳轉
401094: 74 09 je 40109f <fun6+0x30>
401096: 39 32 cmp %esi,(%rdx) // M[rdx]<esi則跳轉,否則break
401098: 7f f0 jg 40108a <fun6+0x1b>
// ------------------------------------------------ 循環結束 -------------------------------------------------------//
40109a: 48 89 cf mov %rcx,%rdi // rdi = rcx
40109d: eb 03 jmp 4010a2 <fun6+0x33>
40109f: 48 89 cf mov %rcx,%rdi // 如果rdx=0則到這rdi = rcx
// -------------------------------------------------- 循環 ---------------------------------------------------------//
4010a2: 48 39 d7 cmp %rdx,%rdi // 如果rdi = rdx
4010a5: 74 06 je 4010ad <fun6+0x3e>
4010a7: 4c 89 47 08 mov %r8,0x8(%rdi)
4010ab: eb 03 jmp 4010b0 <fun6+0x41>
4010ad: 4c 89 c0 mov %r8,%rax // 如果rdi=rdx則到這,rax=第五個參數
4010b0: 49 8b 48 08 mov 0x8(%r8),%rcx // rcx = M[r8+8]
4010b4: 49 89 50 08 mov %rdx,0x8(%r8) // M[r8+8] = rdx
4010b8: 48 85 c9 test %rcx,%rcx // 如果rcx=0則跳至結束
4010bb: 74 1a je 4010d7 <fun6+0x68>
4010bd: 49 89 c8 mov %rcx,%r8 // r8 = cax
4010c0: 48 89 c1 mov %rax,%rcx // rcx = rax
4010c3: 48 89 c7 mov %rax,%rdi // rdi = rax
4010c6: 48 89 ca mov %rcx,%rdx // 如果第五個參數不等於0那麼到這 rdx=rcx
4010c9: 48 85 c9 test %rcx,%rcx
4010cc: 74 d4 je 4010a2 <fun6+0x33> // 如果rcx=0那麼跳轉到4010a2
// ------------------------------------------------ 循環結束 -------------------------------------------------------//
4010ce: 41 8b 30 mov (%r8),%esi // esi = M[r8]
4010d1: 39 31 cmp %esi,(%rcx)
4010d3: 7f b8 jg 40108d <fun6+0x1e> // 如果esi<M[rcx]則跳轉到40108d
4010d5: eb cb jmp 4010a2 <fun6+0x33>
4010d7: f3 c3 repz retq
看到fun6彙編的瞬間我雙手離開鍵盤,我發現寫完註釋我還是看不懂,於是打算還是從判斷語句反推
我通過在cmp語句設置斷點(如下圖),然後查看rdx 和 M[rax] 的值,發現rdx是我的輸入(1234567),M[rax]是673,站在上帝視角,我猜測要想避免炸彈,輸入必須等於673
於是直接投機取巧輸入673 。。。。。。過了
答案:
673
總結
複習到了很多知識,比如寄存器的功能,尋址方式,指令,gdb的使用等
X86 64位寄存器的功能:(借用書上圖片)
還了解了調用者保存和被調用者保存,知了曉遞歸調用時如何保存狀態,比如調用者保存就是父函數自己想辦法保存數據,而被調用者保存則是子函數幫忙保存父函數的數據
尋址方式(同樣借用書上圖片)
其中最常用的就是 imm(rb) 這種,翻譯過來就是 M[imm + R(rb)]
指令
還複習了各種指令,用的最多的當屬mov和add,jump指令
技巧總結:
- 在彙編中esi常常用作scanf格式常字符串存放的地方,而rax是返回值,通過觀察scanf的參數可以很快確定輸入的格式是啥,這樣才能做題
- 彙編中選擇語句的使用:使用cmp或者test判斷,然後jump
- 彙編中循環語句的使用:使用某個寄存器作爲迭代指針,然後不到一定條件,就一直跳轉到循環起始點,否則break。int數組迭代的循環有一個明顯的特徵,那就是每次指針前進4字節,剛好一個int,這個技巧使得我很快看出來第二題的循環結構
- 如果一個指針自己尋址自己,即 k = a[k] 這種,要很快想到是數組跳轉,在上學期數據結構課程,kmp算法也有類似語句 k = next[k],這使得我很快發現第五題的跳轉結構
Gdb使用技巧:
run 執行
si 單步執行
b 設置斷點,可以在函數調用時中斷,即
b func1
或者在指定地址處中斷,比如
b *0x12f3de
在指定位置設置斷點可以更好的判斷觸發bomb的條件,可以打印對應的寄存器看看值是多少,這樣能夠有效避免bomb,第六題我就是用這個技巧投機取巧
p 查看數據
p (char*)0x123fed 查看對應地址的字符串,在分析scanf的輸入格式時很有效
還可以查看某個地址對應的數組,比如
p *0x30fed4@7,查看0x30fed4往後對應7個數字,查看數組在第五題尤其重要
查看寄存器
p $rdx
查看尋址結果
p *(0x3014fd) 或者 p *($rdx)