CSAPP: Bomb Lab Phase1- Phase3

Get to know there're 6 phase from bomb.c and get to know the bomb will be trigged via explode_bomb.

Phase 1

  • run debugger : gdb bomb
  • set breakpoints: b explode_bomb
  • disassmble phase_1: disas phase_1
Dump of assembler code for function phase_1:
   0x0000000000400ee0 <+0>: sub    $0x8,%rsp
   0x0000000000400ee4 <+4>: mov    $0x402400,%esi
   0x0000000000400ee9 <+9>: callq  0x401338 
   0x0000000000400eee <+14>:    test   %eax,%eax
   0x0000000000400ef0 <+16>:    je     0x400ef7 
   0x0000000000400ef2 <+18>:    callq  0x40143a 
   0x0000000000400ef7 <+23>:    add    $0x8,%rsp
   0x0000000000400efb <+27>:    retq   
End of assembler dump.
  • we can see something stored in esi: mov $0x402400,%esi, since %rsi/%esi is the second argument.
  • check the value in location 0x402400: x/s 0x402400

0x402400: "Border relations with Canada have never been better."

  • run the program: run
  • type the key: "Border relations with Canada have never been better."

实际上这里的 %rsp - 0x8 是生成 stack grow, 相当于 push. 后面的 %rsp + 0x8 是 pop from stack.

然后常见的register %esi 相当于 %rsi 第二个参数。

这里的 0x0000000000400ee9 <+9>: callq 0x401338 也就是 procedure 的进行。

Phase 2

The key to solve phase 2 is understand the difference between mov and lea

lea是“load effective address”的缩写,简单的说,lea指令可以用来将一个内存地址直接赋给目的操作数,

例如:lea eax,[ebx+8]就是将ebx+8这个值直接赋给eax,而不是把ebx+8处的内存地址里的数据赋给eax。
而mov指令则恰恰相反,例如:mov eax,[ebx+8]则是把内存地址为ebx+8处的数据赋给eax。

  • run debugger : gdb bomb
  • set breakpoints: b explode_bomb
  • disassmble phase_1: disas phase_2
0000000000400efc :
  400efc:   55                      push   %rbp
  400efd:   53                      push   %rbx
  400efe:   48 83 ec 28             sub    $0x28,%rsp
  400f02:   48 89 e6                mov    %rsp,%rsi
  400f05:   e8 52 05 00 00          callq  40145c 
  400f0a:   83 3c 24 01             cmpl   $0x1,(%rsp)
  400f0e:   74 20                   je     400f30 
  400f10:   e8 25 05 00 00          callq  40143a 
  400f15:   eb 19                   jmp    400f30 
  400f17:   8b 43 fc                mov    -0x4(%rbx),%eax
  400f1a:   01 c0                   add    %eax,%eax
  400f1c:   39 03                   cmp    %eax,(%rbx)
  400f1e:   74 05                   je     400f25 
  400f20:   e8 15 05 00 00          callq  40143a 
  400f25:   48 83 c3 04             add    $0x4,%rbx
  400f29:   48 39 eb                cmp    %rbp,%rbx
  400f2c:   75 e9                   jne    400f17 
  400f2e:   eb 0c                   jmp    400f3c 
  400f30:   48 8d 5c 24 04          lea    0x4(%rsp),%rbx
  400f35:   48 8d 6c 24 18          lea    0x18(%rsp),%rbp
  400f3a:   eb db                   jmp    400f17 
  400f3c:   48 83 c4 28             add    $0x28,%rsp
  400f40:   5b                      pop    %rbx
  400f41:   5d                      pop    %rbp
  400f42:   c3                      retq   

we can tell by the name we have a function called read_six_numbers.

000000000040145c :
  40145c:   48 83 ec 18             sub    $0x18,%rsp
  401460:   48 89 f2                mov    %rsi,%rdx
  401463:   48 8d 4e 04             lea    0x4(%rsi),%rcx
  401467:   48 8d 46 14             lea    0x14(%rsi),%rax
  40146b:   48 89 44 24 08          mov    %rax,0x8(%rsp)
  401470:   48 8d 46 10             lea    0x10(%rsi),%rax
  401474:   48 89 04 24             mov    %rax,(%rsp)
  401478:   4c 8d 4e 0c             lea    0xc(%rsi),%r9
  40147c:   4c 8d 46 08             lea    0x8(%rsi),%r8
  401480:   be c3 25 40 00          mov    $0x4025c3,%esi
  401485:   b8 00 00 00 00          mov    $0x0,%eax
  40148a:   e8 61 f7 ff ff          callq  400bf0 <__isoc99_sscanf@plt>
  40148f:   83 f8 05                cmp    $0x5,%eax
  401492:   7f 05                   jg     401499 
  401494:   e8 a1 ff ff ff          callq  40143a 
  401499:   48 83 c4 18             add    $0x18,%rsp
  40149d:   c3                      retq   

we called sscanf inside this function. we do a man sscanf

sscanf(const char *restrict s, const char *restrict format, ...);

Actually we can tell by its name we try to read six numbers in.

Try to decode this line:

401480: be c3 25 40 00 mov $0x4025c3,%esi

x/s 0x4025c3

0x4025c3 :"%d %d %d %d %d %d"

We know first it will try to read the input as string, maybe something like input2.
then we do sscanf from the input2.

Decode these line:

400f0a: 83 3c 24 01 cmpl $0x1,(%rsp)
400f0e: 74 20 je 400f30

register value
%rsp some meory address at rsp

and we know the value at some meory address at rsp have to be 1, otherwise it will not je, it'll go to next line and explode_bomb.

memory adress value
memory address at rsp 1

Guess the first number is 1.

Then we jump, decode these lines:

400f30: 48 8d 5c 24 04          lea    0x4(%rsp),%rbx
400f35: 48 8d 6c 24 18          lea    0x18(%rsp),%rbp
400f3a: eb db                   jmp    400f17 

register value
%rbx memory address at rsp + 0x4
%rbp memory address at rsp + 0x18

if we have format like this:

int int int int int int

int take 2 byte, blank space take 1 byte: 这里纯粹都是错误的分析啊||||

6 * 4 + 5 + 1 = 18

try to guess rbp = '\0'

rbx is we try to read next number?

Then we jump again, decode these lines:

400f17: 8b 43 fc mov -0x4(%rbx),%eax
400f1a: 01 c0 add %eax,%eax
400f1c: 39 03 cmp %eax,(%rbx)

action register value
mov -0x4(%rbx),%eax %eax memory address at rbx - 0x4 = memory adress at rsp
add %eax,%eax %eax 2

400f1c: 39 03 cmp %eax,(%rbx)

This line requires value at %rbx, that is the value at emory address at rsp + 0x4 equal to 2. double value of %eax.

Guess the second number 2.

Accroding to the format, int takes 2 bytes, char takes 1 byte. Guess the input is:

01 02 04 08 16 32

Type in. phase 2 solved.

然后阅读了这篇文章 : CSAPP: Bomb Lab 实验解析,发现

  • 并不一定需要 type in 01 02 04 08 16 32 , 直接写入 1 2 4 8 16 32 也一样,sscanf 会自动读入int 占4位。0x18 也不是 18啊, 是 1 *16 + 8 = 24
  • 画出数据存储和写出对应的类C代码更帮助解题
  • 这里还有一些推断,比如 %rsp 中存的内存中的值是第一个input number,这里是否也说明了 stack pointer作用?

位置 & 内存

% rsp %rsp + 0x4 %rsp + 0x8 %rsp + 0xc %rsp + 0x10 %rsp + 0x14 %rbp = %rsp + 0x18
num[0] num[1] num[2] num[3] num[4] num[5] edge

对应的类C代码:

void phase_2(){
  if (%rsp) == 0x1 { // 保证第一个数是1,不jump则会 
    goto label_400f30;
  }
label_400f17:
  %rax = (%rbx - 0x4);
  %eax = %eax + %rax;
  if %rax != (%rbx){  // 保证后一个数为前一个数的两倍,否则会 
    explode_bomb();
  }
  %rbx = %rbx + 0x4;
  if (%rbp != %rbx) {
    goto label_400f17;
  } else {
    return ;  //jump out of phase_2;
  }
label_400f30:
  %rbx = (%rsp + 0x4);
  %rbp = (%rsp + 0x18);
  goto label_400f17;
    
}

Phase 3

disas phase_3

Dump of assembler code for function phase_3:
   0x0000000000400f43 <+0>: sub    $0x18,%rsp
   0x0000000000400f47 <+4>: lea    0xc(%rsp),%rcx
   0x0000000000400f4c <+9>: lea    0x8(%rsp),%rdx
   0x0000000000400f51 <+14>:    mov    $0x4025cf,%esi
   0x0000000000400f56 <+19>:    mov    $0x0,%eax
   0x0000000000400f5b <+24>:    callq  0x400bf0 <__isoc99_sscanf@plt>
   0x0000000000400f60 <+29>:    cmp    $0x1,%eax
   0x0000000000400f63 <+32>:    jg     0x400f6a 
   0x0000000000400f65 <+34>:    callq  0x40143a 
   0x0000000000400f6a <+39>:    cmpl   $0x7,0x8(%rsp)
   0x0000000000400f6f <+44>:    ja     0x400fad 
   0x0000000000400f71 <+46>:    mov    0x8(%rsp),%eax
   0x0000000000400f75 <+50>:    jmpq   *0x402470(,%rax,8)
   0x0000000000400f7c <+57>:    mov    $0xcf,%eax
   0x0000000000400f81 <+62>:    jmp    0x400fbe 
   0x0000000000400f83 <+64>:    mov    $0x2c3,%eax
   0x0000000000400f88 <+69>:    jmp    0x400fbe 
   0x0000000000400f8a <+71>:    mov    $0x100,%eax
   0x0000000000400f8f <+76>:    jmp    0x400fbe 
   0x0000000000400f91 <+78>:    mov    $0x185,%eax
   0x0000000000400f96 <+83>:    jmp    0x400fbe 
   0x0000000000400f98 <+85>:    mov    $0xce,%eax
   0x0000000000400f9d <+90>:    jmp    0x400fbe 
   0x0000000000400f9f <+92>:    mov    $0x2aa,%eax
   0x0000000000400fa4 <+97>:    jmp    0x400fbe 
   0x0000000000400fa6 <+99>:    mov    $0x147,%eax
   0x0000000000400fab <+104>:   jmp    0x400fbe 
   0x0000000000400fad <+106>:   callq  0x40143a 
   0x0000000000400fb2 <+111>:   mov    $0x0,%eax
   0x0000000000400fb7 <+116>:   jmp    0x400fbe 
   0x0000000000400fb9 <+118>:   mov    $0x137,%eax
   0x0000000000400fbe <+123>:   cmp    0xc(%rsp),%eax
   0x0000000000400fc2 <+127>:   je     0x400fc9 
   0x0000000000400fc4 <+129>:   callq  0x40143a 
   0x0000000000400fc9 <+134>:   add    $0x18,%rsp
   0x0000000000400fcd <+138>:   retq   
End of assembler dump.

Decode these two lines:

400f47: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx
400f4c: 48 8d 54 24 08 lea 0x8(%rsp),%rdx

register value
%rcx memory address at rsp + 0xc
%rdx memory address at rsp + 0x8

400f51: be cf 25 40 00 mov $0x4025cf,%esi

x/w 0x4025cf
0x4025cf: "%d %d"

So we need two ints for this phase.

400f60: 83 f8 01 cmp $0x1,%eax

if return value is greater than 0x1, and it should, since we read two numbers in:

400f63: 7f 05 jg 400f6a

We jump to 400f6a

400f6a: 83 7c 24 08 07 cmpl $0x7,0x8(%rsp)

compare the value %rsp + 0x8 with $0x7, if above:

400f6f: 77 3c ja 400fad

jump to 400fad

400fad: e8 88 04 00 00 callq 40143a

So the value %rsp + 0x8 should be smaller than $0x7. also here we use ja, so the value should be >= 0 and <7.

400f71: 8b 44 24 08 mov 0x8(%rsp),%eax
400f75: ff 24 c5 70 24 40 00 jmpq *0x402470(,%rax,8)
400f7c: b8 cf 00 00 00 mov $0xcf,%eax

mov the vluae of %rsp + 0x8 to %eax, sth smaller than $0x7。

for this line: 400f75: ff 24 c5 70 24 40 00 jmpq *0x402470(,%rax,8)

This operation jmpq *0x402390(,%rax,8) is for jumping directly to the absolute address stored at
8 * %rax + 0x402390

If you do x/16gx 0x402390 in gdb (inspect 16 "giant words" in hexadecimal starting at 0x402390) you will find an address table looks like the following:(i have a different lab so it's not the same as yours)

0x402880: 0x0000000000400fee 0x000000000040102b
0x402890: 0x0000000000400ff5 0x0000000000400ffc
0x4028a0: 0x0000000000401003 0x000000000040100a
0x4028b0: 0x0000000000401011 0x0000000000401018

Where all these addresses all point back to the a single mov operation immediately after jmpq *0x402390(,%rax,8)

https://stackoverflow.com/a/50978155/3608824

We have the instruction jump = 0x402470 + 8 *i (i <= 7)

If I do x/16gx 0x402470:

(gdb) x/16gx 0x402470
0x402470:   0x0000000000400f7c  0x0000000000400fb9
0x402480:   0x0000000000400f83  0x0000000000400f8a
0x402490:   0x0000000000400f91  0x0000000000400f98
0x4024a0:   0x0000000000400f9f  0x0000000000400fa6
0x4024b0 :  0x737265697564616d  0x6c796276746f666e
0x4024c0:   0x7420756f79206f53  0x756f79206b6e6968
0x4024d0:   0x6f7473206e616320  0x6f62206568742070
0x4024e0:   0x206874697720626d  0x202c632d6c727463

For the first 0 - 7 locations, we have all those lines:

   0x0000000000400f7c <+57>:    mov    $0xcf,%eax

   0x0000000000400fb9 <+118>:   mov    $0x137,%eax

   0x0000000000400f83 <+64>:    mov    $0x2c3,%eax

   0x0000000000400f8a <+71>:    mov    $0x100,%eax

   0x0000000000400f91 <+78>:    mov    $0x185,%eax

   0x0000000000400f98 <+85>:    mov    $0xce,%eax

   0x0000000000400f9f <+92>:    mov    $0x2aa,%eax

   0x0000000000400fa6 <+99>:    mov    $0x147,%eax

try i = 0, we jump to 0x0000000000400f7c.

0x0000000000400f7c <+57>: mov $0xcf,%eax
0x0000000000400f81 <+62>: jmp 0x400fbe

the %eax number is 0xcf, and we jump to 0x400fbe.

0x0000000000400fbe <+123>: cmp 0xc(%rsp),%eax
0x0000000000400fc2 <+127>: je 0x400fc9
0x0000000000400fc4 <+129>: callq 0x40143a
0x0000000000400fc9 <+134>: add $0x18,%rsp

The value at memory address at rsp + 0xc should equal to value in eax. and then we jump out of the function.

And we have rsp + 0x8 and rsp + 0xc, so we should count the 0s, tried type in

0000 0207 solved.

I can also try other values: 0001 0311 can also solve phase_3.

这一关的思路基本上和文章一致,值得注意的是 x 的用法:

x /[Length][Format] [Address expression]
以给定的参数查看内存中的内容。
x commnad

(Note: the format string for the ‘x’ command has the general form
   x/[NUM][SIZE][FORMAT] where
  NUM  = number of objects to display
  SIZE = size of each object (b=byte, h=half-word, w=word,
                              g=giant (quad-word))
  FORMAT = how to display each object (d=decimal, x=hex, o=octal, etc.)
  If you don’t specify SIZE or FORMAT, either a default value, or the last
  value you specified in a previous ‘print’ or ‘x’ command is used.
)

如果我们直接

(gdb) x 0x402470
0x402470:   0x0000000000400f7c

但是我们知道 第一个数 < 7 ,所以尝试 x/8gx 0x402470

x/8gx 0x402470
0x402470:   0x0000000000400f7c  0x0000000000400fb9
0x402480:   0x0000000000400f83  0x0000000000400f8a
0x402490:   0x0000000000400f91  0x0000000000400f98
0x4024a0:   0x0000000000400f9f  0x0000000000400fa6

这一句还是这样理解:

400f75: ff 24 c5 70 24 40 00 jmpq *0x402470(,%rax,8)

0x400f75处的跳转指令依据第一个数的值做间接跳转,还是相当于去去存在此处的内存中的地址。这个 * 有点取(地址)内容的意思。

所以phase_3的答案是7组。

你可能感兴趣的:(CSAPP: Bomb Lab Phase1- Phase3)