標籤:color length run 資料 否則 文章 迴圈 ase 一個
這一個lab拖了好久才開始慢慢完成,花的時間比較多,我也是沒想到會需要這麼多時間來折騰。考慮到如果把所有關卡的內容都一次發出來,太長了。所以分開操作吧。
然後,有一點是,在開始解題前的確該好好認識一下GDB,因為要使用這個工具。雖然我也感覺有些東西是可以等需要的時候再查的,但是後來找到了一篇介紹gdb命令的,寫的比較詳細,就下載了列印出來,佔用了幾節課的時間好好看了一下,就感覺特別有用,比之前更加熟悉了GDB。大概是在網頁上看的時候比較急躁,所以吸收不好吧23333。還有,在解題過程中參考了不少網上前輩的資料,向每位分享知識的前輩致敬。
我的操作方法是把程式反組譯碼到一個文本中,反組譯碼了兩個版本,一個是objdump -d bomb > bomb_disas.s (反組譯碼bomb中需要執行指令的那些section),另一個是 objdump -D bomb > bomb_disas2.s (反組譯碼bomb中所有的section). 這個放在Windows系統中,便於查看,分析,主要是感覺notepad++看著舒服啦。然後,調試是在虛擬機器中進行的。
關於GDB命令的東西,如果你還沒有接觸過,那還是先瞭解一下的好,或者可以在閱讀途中碰上了再百度。
在Linux中,gdb bomb用GDB開啟bomb,輸入list可以查看代碼。不過bomb lab 檔案夾中也有源碼。通過這個可以看到代碼中每個關卡的通用格式,比如:
input = read_line(); /* Get input */ phase_1(input); /* Run the phase */ phase_defused(); /* Drat! They figured it out! * Let me know how they did it. */
每一關的函數是phase_x,這裡x是關卡數。看第一關的彙編函數phase_1,發現其中調用了兩個函數。
0000000000400ee0 <phase_1>: 400ee0: 48 83 ec 08 sub $0x8,%rsp 400ee4: be 00 24 40 00 mov $0x402400,%esi 400ee9: e8 4a 04 00 00 callq 401338 <strings_not_equal> 400eee: 85 c0 test %eax,%eax
400ef0: 74 05 je 400ef7 <phase_1+0x17>
400ef2: e8 43 05 00 00 callq 40143a <explode_bomb>
400ef7: 48 83 c4 08 add $0x8,%rsp 400efb: c3 retq
一個是 strings_not_eaqual ,一個是 explode_bomb .這裡先說這個explode_bomb是解密失敗後引發爆炸(bomb)的函數。具體可以自行去調用查看,在bomb_disas.s中尋找該函數即可查看其執行過程,不予細說了。然後,這裡另一個函數是 strings_not_eaqual .從字面上也可以理解,這個函數是檢查兩個字串是否一樣。應用就是你輸入的字串如果跟他指向的另一串字串不一樣,就bomb了,請看查看這個函數的代碼。
0000000000401338 <strings_not_equal>: 401338: 41 54 push %r12 40133a: 55 push %rbp 40133b: 53 push %rbx 40133c: 48 89 fb mov %rdi,%rbx ;%rdi是儲存輸入的字串首地址 40133f: 48 89 f5 mov %rsi,%rbp ;由phase(1)知道;;%rsi是儲存拆彈密碼字串的首地址. 401342: e8 d4 ff ff ff callq 40131b <string_length> ;計算字串長度, 401347: 41 89 c4 mov %eax,%r12d 40134a: 48 89 ef mov %rbp,%rdi 40134d: e8 c9 ff ff ff callq 40131b <string_length> 401352: ba 01 00 00 00 mov $0x1,%edx 401357: 41 39 c4 cmp %eax,%r12d ;字串長度不一樣的話,就bomb. 40135a: 75 3f jne 40139b <strings_not_equal+0x63> 40135c: 0f b6 03 movzbl (%rbx),%eax ;零擴充傳遞第一個字元到%eax. 40135f: 84 c0 test %al,%al ;第一個為0就ret,以0作為傳回值。 401361: 74 25 je 401388 <strings_not_equal+0x50> ;但是要考慮字串長度,所以0不是正確答案 401363: 3a 45 00 cmp 0x0(%rbp),%al ;對比第一個字串,相同則進入迴圈,否則bomb 401366: 74 0a je 401372 <strings_not_equal+0x3a> ;0x401372進入迴圈。 401368: eb 25 jmp 40138f <strings_not_equal+0x57> 40136a: 3a 45 00 cmp 0x0(%rbp),%al ;迴圈的起始地址 40136d: 0f 1f 00 nopl (%rax) 401370: 75 24 jne 401396 <strings_not_equal+0x5e> ;第N個字元不相同則bomb. 401372: 48 83 c3 01 add $0x1,%rbx ;所輸入字串向後移一位,為了向後檢查 401376: 48 83 c5 01 add $0x1,%rbp ;密碼字串後移,為了向後檢查 40137a: 0f b6 03 movzbl (%rbx),%eax ;零擴充傳遞第N個字元到%eax 40137d: 84 c0 test %al,%al 40137f: 75 e9 jne 40136a <strings_not_equal+0x32> ;第N個字元不是%0,即字串未結束,則繼續迴圈 401381: ba 00 00 00 00 mov $0x0,%edx 401386: eb 13 jmp 40139b <strings_not_equal+0x63> 401388: ba 00 00 00 00 mov $0x0,%edx 40138d: eb 0c jmp 40139b <strings_not_equal+0x63> 40138f: ba 01 00 00 00 mov $0x1,%edx 401394: eb 05 jmp 40139b <strings_not_equal+0x63> 401396: ba 01 00 00 00 mov $0x1,%edx 40139b: 89 d0 mov %edx,%eax 40139d: 5b pop %rbx 40139e: 5d pop %rbp 40139f: 41 5c pop %r12 4013a1: c3 retq
這裡重點就是%rdi儲存輸入所輸入的字串的首地址,%rsi儲存拆彈密碼字串的首地址。
再回過來查看phase_1, 第二行將0x402400賦值給了寄存器%esi。
0000000000400ee0 <phase_1>: 400ee0: 48 83 ec 08 sub $0x8,%rsp 400ee4: be 00 24 40 00 mov $0x402400,%esi 400ee9: e8 4a 04 00 00 callq 401338 <strings_not_equal> 400eee: 85 c0 test %eax,%eax ;%eax傳回值為1就bomb 400ef0: 74 05 je 400ef7 <phase_1+0x17> ;通過查看strings_not_equal函數知道 400ef2: e8 43 05 00 00 callq 40143a <explode_bomb> ;0x402400位置的字串即為第一關答案. 400ef7: 48 83 c4 08 add $0x8,%rsp ;在gdb中用 x/s 0x402400查看記憶體即可看到答案。 400efb: c3 retq
在gdb中用 x/s 0x402400查看記憶體中的字串就得到了答案。
輸入該字串即可通過第一關。
至此,第一關結束。加油挑戰!
對我來說,感覺這bomb lab拖了好久才完成的原因,主要還是在於對GDB工具的不瞭解,所以弄得是無從下手。所以如果有後來者看到這篇文章,希望你先好好熟悉一下GDB,這樣才可以事半功倍。
CSAPP 3e: Bomb lab (phase_1)