iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 1
0
Software Development

深入淺出 Debugger系列 第 3

Day 3 - [LAB] Bomb lab

參考 Bomb Lab 實作紀錄,並在 x86 的電腦上進行簡易的實作

main

這題目設計的重點就是這兩個 phase ,要想辦法在 gdb 中繞過這兩個 condition,避免他觸發 exit(1)

  • day3Bomb/bomb.c
  • phase_1: 要修改掉 x 的數值,不然在 ubuntu 底下會被強制瀏覽 pornhub.com
void phase_1() {
    int x=12;
    if(x==12) {
      system("google-chrome --incognito pornhub.com");
      exit(1);
    } else {
      printf("pass phase_1\n");
    }
}
  • phase_2: 要輸入一串字串,原理是差不多的,但組語的程式碼會稍加複雜
void phase_2() {
  char text[] = "pornhub";
  char input[100];
  scanf("%s", input);
  if(strcmp(input, text)==0) {// match
    printf("pass phase_2\n");
  } else {
    exit(1);
  }
}

開始執行 gdb 後,記得把斷點設在 phase_1 / phase_2,至於怎麼執行,到底是要用 step 還是 stepi,請自行判斷,以下只會節錄重點

(gdb) r
Starting program: /home/demonic/gitPro/ithome2020/day3Bomb/bomb
Missing separate debuginfos, use: zypper install glibc-debuginfo-2.26-lp152.25.10.x86_64
[Detaching after fork from child process 18108]
sh: google-chrome: command not found
[Inferior 1 (process 18104) exited with code 01]
(gdb) b phase_2
Breakpoint 1 at 0x400695: file bomb.c, line 16.
(gdb) b phase_1
Breakpoint 2 at 0x40065f: file bomb.c, line 6.

phase_1

以下組語語法是 AT&T 系列的

Dump of assembler code for function phase_1:
   0x0000000000400657 <+0>:     push   %rbp
   0x0000000000400658 <+1>:     mov    %rsp,%rbp
   0x000000000040065b <+4>:     sub    $0x10,%rsp
=> 0x000000000040065f <+8>:     movl   $0xc,-0x4(%rbp)
   0x0000000000400666 <+15>:    cmpl   $0xc,-0x4(%rbp)
   0x000000000040066a <+19>:    jne    0x400680 <phase_1+41>
   0x000000000040066c <+21>:    mov    $0x400798,%edi
   0x0000000000400671 <+26>:    callq  0x400540 <system@plt>
   0x0000000000400676 <+31>:    mov    $0x1,%edi
   0x000000000040067b <+36>:    callq  0x400570 <exit@plt>
   0x0000000000400680 <+41>:    mov    $0x4007be,%edi
   0x0000000000400685 <+46>:    callq  0x400530 <puts@plt>
   0x000000000040068a <+51>:    nop
   0x000000000040068b <+52>:    leaveq
   0x000000000040068c <+53>:    retq

可以發現,重點是要去找 rbp 這個 register,然後對他 -0x4 的位置,進行操作,把數值從 0xc 改掉,改成任意其他數字都好

(gdb) p $rbp
$14 = (void *) 0x7fffffffe560
(gdb) p 0x7fffffffe560
$15 = 140737488348512
(gdb) p *0x7fffffffe560
$16 = -6800
(gdb) p *(0x7fffffffe560-0x4)
$17 = 12
(gdb) p *(0x7fffffffe560-0x4)=2
$18 = 2
(gdb) p *(0x7fffffffe560-0x4)
$19 = 2

phase_2

Dump of assembler code for function phase_2:
   0x000000000040068d <+0>:     push   %rbp
   0x000000000040068e <+1>:     mov    %rsp,%rbp
   0x0000000000400691 <+4>:     sub    $0x70,%rsp
=> 0x0000000000400695 <+8>:     movabs $0x6275686e726f70,%rax
   0x000000000040069f <+18>:    mov    %rax,-0x8(%rbp)
   0x00000000004006a3 <+22>:    lea    -0x70(%rbp),%rax
   0x00000000004006a7 <+26>:    mov    %rax,%rsi
   0x00000000004006aa <+29>:    mov    $0x4007cb,%edi
   0x00000000004006af <+34>:    mov    $0x0,%eax
   0x00000000004006b4 <+39>:    callq  0x400560 <__isoc99_scanf@plt>
   0x00000000004006b9 <+44>:    lea    -0x8(%rbp),%rdx
   0x00000000004006bd <+48>:    lea    -0x70(%rbp),%rax
   0x00000000004006c1 <+52>:    mov    %rdx,%rsi
   0x00000000004006c4 <+55>:    mov    %rax,%rdi
   0x00000000004006c7 <+58>:    callq  0x400550 <strcmp@plt>
   0x00000000004006cc <+63>:    test   %eax,%eax
   0x00000000004006ce <+65>:    jne    0x4006dc <phase_2+79>
   0x00000000004006d0 <+67>:    mov    $0x4007ce,%edi
   0x00000000004006d5 <+72>:    callq  0x400530 <puts@plt>
   0x00000000004006da <+77>:    jmp    0x4006e6 <phase_2+89>
   0x00000000004006dc <+79>:    mov    $0x1,%edi
   0x00000000004006e1 <+84>:    callq  0x400570 <exit@plt>
   0x00000000004006e6 <+89>:    leaveq
   0x00000000004006e7 <+90>:    retq

這邊的重點是要先 step 到 scanf,然後隨便輸入一組字串,接著 step 到 strcmp

這種東西都有很多改法,我覺得從 test %eax, %eax 下手也是行得通,不過這邊我打算去讀 "pornhub" 的字串到底存在哪裡,把那個字串讀出來,讓我知道要輸入什麼即可~~

其實從組語中,很輕易可以觀察到,scanf 所使用的記憶體位置是 -0x70(%rbp),而 pornhub 字串肯定存在 -0x8(%rbp),我們只需要把他打印出來,即可知道 scanf 要輸入什麼~~

(gdb) p $rbp-0x8
$4 = (void *) 0x7fffffffe558
(gdb) x $rbp-0x8
0x7fffffffe558: 0x6e726f70
(gdb) p (char*)$rbp-0x8
$5 = 0x7fffffffe558 "pornhub"

Next

從上面兩個簡單的範例,我們就可以感受到 gdb 的強大,可以任意修改數值,當然也可以修改程式碼,讓那一行直接變成另外一條指令,只是我懶得去查 opcode 在那邊修修改改

而且 GDB 可做到的可不只是這樣,甚至可以 reverse debugging,就是當你已經執行到下一步,仍舊可以返回,這部分可以參考 GDB and Reverse Debugging,但這種功能並不支援所有的平台,像我最近在開發的 RISC-V 就沒支援這東西,或許我吃飽太閒的時候,可以把他 porting 上去~~

下一篇會介紹 ptrace 要怎麼使用,並使用 ptrace 製作一個簡易的 breakpoint,這邊要注意一件事,ptrace 會使用到 parent/child process 的概念,可能會看得很問號

除此之外,接下來要寫的文章我要稍做一些調整,會加入 systemtap 以及 debuginfod 這兩個部分


上一篇
Day 2 - [INFO] GDB 基礎操作
系列文
深入淺出 Debugger3

尚未有邦友留言

立即登入留言