Skip to main content

Bomb Lab: Phase 3

Course WorkBomb LabComputer Organization and ArchitectureAbout 6 minAbout 1853 words

Assembly

00000000004014b1 <phase_3>:
b0:
  4014b1:	48 83 ec 18          	sub    $0x18,%rsp
  4014b5:	48 8d 4c 24 0c       	lea    0xc(%rsp),%rcx
  4014ba:	48 8d 54 24 08       	lea    0x8(%rsp),%rdx
  4014bf:	48 8d 35 6f 1f 00 00 	lea    0x1f6f(%rip),%rsi        # 403435 <array.3354+0x255>
  4014c6:	b8 00 00 00 00       	mov    $0x0,%eax
  4014cb:	e8 60 fc ff ff       	callq  401130 <__isoc99_sscanf@plt>
  4014d0:	83 f8 01             	cmp    $0x1,%eax
  4014d3:	7f 05                	jg     4014da <phase_3+0x29>
  4014d5:	e8 82 06 00 00       	callq  401b5c <explode_bomb>
b1:
  4014da:	83 7c 24 08 07       	cmpl   $0x7,0x8(%rsp)
  4014df:	77 6f                	ja     401550 <phase_3+0x9f>
  4014e1:	8b 54 24 08          	mov    0x8(%rsp),%edx
  4014e5:	48 8d 05 d4 1c 00 00 	lea    0x1cd4(%rip),%rax        # 4031c0 <_IO_stdin_used+0x1c0>
  4014ec:	48 63 14 90          	movslq (%rax,%rdx,4),%rdx
  4014f0:	48 01 d0             	add    %rdx,%rax
  4014f3:	ff e0                	jmpq   *%rax
  4014f5:	b8 00 00 00 00       	mov    $0x0,%eax
  4014fa:	eb 05                	jmp    401501 <phase_3+0x50>
  4014fc:	b8 cb 02 00 00       	mov    $0x2cb,%eax
b2:
  401501:	2d 4c 02 00 00       	sub    $0x24c,%eax
  401506:	eb 05                	jmp    40150d <phase_3+0x5c>
  401508:	b8 00 00 00 00       	mov    $0x0,%eax
b3:
  40150d:	05 ba 03 00 00       	add    $0x3ba,%eax
  401512:	eb 05                	jmp    401519 <phase_3+0x68>
  401514:	b8 00 00 00 00       	mov    $0x0,%eax
b4:
  401519:	2d 79 03 00 00       	sub    $0x379,%eax
  40151e:	eb 05                	jmp    401525 <phase_3+0x74>
  401520:	b8 00 00 00 00       	mov    $0x0,%eax
b5:
  401525:	05 79 03 00 00       	add    $0x379,%eax
  40152a:	eb 05                	jmp    401531 <phase_3+0x80>
  40152c:	b8 00 00 00 00       	mov    $0x0,%eax
b6:
  401531:	2d 79 03 00 00       	sub    $0x379,%eax
  401536:	eb 05                	jmp    40153d <phase_3+0x8c>
  401538:	b8 00 00 00 00       	mov    $0x0,%eax
b7:
  40153d:	05 79 03 00 00       	add    $0x379,%eax
  401542:	eb 05                	jmp    401549 <phase_3+0x98>
  401544:	b8 00 00 00 00       	mov    $0x0,%eax
b8:
  401549:	2d 79 03 00 00       	sub    $0x379,%eax
  40154e:	eb 0a                	jmp    40155a <phase_3+0xa9>
b9:
  401550:	e8 07 06 00 00       	callq  401b5c <explode_bomb>
  401555:	b8 00 00 00 00       	mov    $0x0,%eax
b10:
  40155a:	83 7c 24 08 05       	cmpl   $0x5,0x8(%rsp)
  40155f:	7f 06                	jg     401567 <phase_3+0xb6>
  401561:	3b 44 24 0c          	cmp    0xc(%rsp),%eax
  401565:	74 05                	je     40156c <phase_3+0xbb>
b11:
  401567:	e8 f0 05 00 00       	callq  401b5c <explode_bomb>
b12:
  40156c:	48 83 c4 18          	add    $0x18,%rsp
  401570:	c3                   	retq

翻译为 C

void phase_3(char* rdi) {
b0:
  int rsp[6];
  int* rcx = rsp + 3;
  int* rdx = rsp + 2;
  char* rsi = 0x403435;  // 403435 <array.3354+0x255>
  int rax = 0;           // 32-bit
  rax = __isoc99_sscanf(rdi, rsi, rdx, rcx);
  if (rax > 1)  // 32-bit
    goto b1;
  explode_bomb();
b1:
  if (rsp[2] > 7) goto b9;
  int rdx = rsp[2];     // 32-bit
  int* rax = 0x4031c0;  // 4031c0 <_IO_stdin_used+0x1c0>
  rdx = rax[rdx];
  rax += rdx;
  jmpq(rax);
  rax = 0;  // 32-bit
  goto b2;
  rax = 0x2cb;  // 32-bit
b2:
  rax -= 0x24c;  // 32-bit
  goto b3;
  rax = 0;  // 32-bit
b3:
  rax += 0x3ba;  // 32-bit
  goto b4;
  rax = 0;  // 32-bit
b4:
  rax -= 0x379;  // 32-bit
  goto b5;
  rax = 0;  // 32-bit
b5:
  rax += 0x379;  // 32-bit
  goto b6;
  rax = 0;  // 32-bit
b6:
  rax -= 0x379;  // 32-bit
  goto b7;
  rax = 0;  // 32-bit
b7:
  rax += 0x379;  // 32-bit
  goto b8;
  rax = 0;  // 32-bit
b8:
  rax -= 0x379;  // 32-bit
  goto b10;
b9:
  explode_bomb();
  rax = 0;  // 32-bit
b10:
  if (rsp[2] > 5) goto b11;
  if (rax == rsp[3])  // 32-bit
    goto b12;
b11:
  explode_bomb();
b12:
  return;
}

Hack

(gdb) x/s 0x403435
0x403435:       "%d %d"
(gdb) x/8xw 0x4031c0
0x4031c0:       0xffffe33c      0xffffe335      0xffffe348      0xffffe354
0x4031d0:       0xffffe360      0xffffe36c      0xffffe378      0xffffe384
i*(0x4031c0 + i * sizeof(int))0x4031c0 + *(0x4031c0 + i * sizeof(int))BasicBlock
00xffffe33c0x004014fcbb0
10xffffe3350x004014f5bb1
20xffffe3480x00401508bb2
30xffffe3540x00401514bb3
40xffffe3600x00401520bb4
50xffffe36c0x0040152cbb5
60xffffe3780x00401538bb6
70xffffe3840x00401544bb7

重新分割 BasicBlock

00000000004014b1 <phase_3>:
b0:
  4014b1:	48 83 ec 18          	sub    $0x18,%rsp
  4014b5:	48 8d 4c 24 0c       	lea    0xc(%rsp),%rcx
  4014ba:	48 8d 54 24 08       	lea    0x8(%rsp),%rdx
  4014bf:	48 8d 35 6f 1f 00 00 	lea    0x1f6f(%rip),%rsi        # 403435 <array.3354+0x255>
  4014c6:	b8 00 00 00 00       	mov    $0x0,%eax
  4014cb:	e8 60 fc ff ff       	callq  401130 <__isoc99_sscanf@plt>
  4014d0:	83 f8 01             	cmp    $0x1,%eax
  4014d3:	7f 05                	jg     4014da <phase_3+0x29>
  4014d5:	e8 82 06 00 00       	callq  401b5c <explode_bomb>
b1:
  4014da:	83 7c 24 08 07       	cmpl   $0x7,0x8(%rsp)
  4014df:	77 6f                	ja     401550 <phase_3+0x9f>
  4014e1:	8b 54 24 08          	mov    0x8(%rsp),%edx
  4014e5:	48 8d 05 d4 1c 00 00 	lea    0x1cd4(%rip),%rax        # 4031c0 <_IO_stdin_used+0x1c0>
  4014ec:	48 63 14 90          	movslq (%rax,%rdx,4),%rdx
  4014f0:	48 01 d0             	add    %rdx,%rax
  4014f3:	ff e0                	jmpq   *%rax
bb1:
  4014f5:	b8 00 00 00 00       	mov    $0x0,%eax
  4014fa:	eb 05                	jmp    401501 <phase_3+0x50>
bb0:
  4014fc:	b8 cb 02 00 00       	mov    $0x2cb,%eax
b2:
  401501:	2d 4c 02 00 00       	sub    $0x24c,%eax
  401506:	eb 05                	jmp    40150d <phase_3+0x5c>
bb2:
  401508:	b8 00 00 00 00       	mov    $0x0,%eax
b3:
  40150d:	05 ba 03 00 00       	add    $0x3ba,%eax
  401512:	eb 05                	jmp    401519 <phase_3+0x68>
bb3:
  401514:	b8 00 00 00 00       	mov    $0x0,%eax
b4:
  401519:	2d 79 03 00 00       	sub    $0x379,%eax
  40151e:	eb 05                	jmp    401525 <phase_3+0x74>
bb4:
  401520:	b8 00 00 00 00       	mov    $0x0,%eax
b5:
  401525:	05 79 03 00 00       	add    $0x379,%eax
  40152a:	eb 05                	jmp    401531 <phase_3+0x80>
bb5:
  40152c:	b8 00 00 00 00       	mov    $0x0,%eax
b6:
  401531:	2d 79 03 00 00       	sub    $0x379,%eax
  401536:	eb 05                	jmp    40153d <phase_3+0x8c>
bb6:
  401538:	b8 00 00 00 00       	mov    $0x0,%eax
b7:
  40153d:	05 79 03 00 00       	add    $0x379,%eax
  401542:	eb 05                	jmp    401549 <phase_3+0x98>
bb7:
  401544:	b8 00 00 00 00       	mov    $0x0,%eax
b8:
  401549:	2d 79 03 00 00       	sub    $0x379,%eax
  40154e:	eb 0a                	jmp    40155a <phase_3+0xa9>
b9:
  401550:	e8 07 06 00 00       	callq  401b5c <explode_bomb>
  401555:	b8 00 00 00 00       	mov    $0x0,%eax
b10:
  40155a:	83 7c 24 08 05       	cmpl   $0x5,0x8(%rsp)
  40155f:	7f 06                	jg     401567 <phase_3+0xb6>
  401561:	3b 44 24 0c          	cmp    0xc(%rsp),%eax
  401565:	74 05                	je     40156c <phase_3+0xbb>
b11:
  401567:	e8 f0 05 00 00       	callq  401b5c <explode_bomb>
b12:
  40156c:	48 83 c4 18          	add    $0x18,%rsp
  401570:	c3                   	retq

重新翻译为 C

void phase_3(char* rdi) {
b0:
  int rsp[6];
  int rax = 0; // 32-bit
  rax = __isoc99_sscanf(rdi, "%d %d", rsp + 2, rsp + 3);
  if (rax > 1)  // 32-bit
    goto b1;
  explode_bomb();
b1:
  if (rsp[2] > 7) goto b9;
  int rdx = rsp[2];     // 32-bit
  int* rax = 0x4031c0;  // 4031c0 <_IO_stdin_used+0x1c0>
  rdx = rax[rdx];
  rax += rdx;
  jmpq(rax);
bb1:
  rax = 0;  // 32-bit
  goto b2;
bb0:
  rax = 0x2cb;  // 32-bit
b2:
  rax -= 0x24c;  // 32-bit
  goto b3;
bb2:
  rax = 0;  // 32-bit
b3:
  rax += 0x3ba;  // 32-bit
  goto b4;
bb3:
  rax = 0;  // 32-bit
b4:
  rax -= 0x379;  // 32-bit
  goto b5;
bb4:
  rax = 0;  // 32-bit
b5:
  rax += 0x379;  // 32-bit
  goto b6;
bb5:
  rax = 0;  // 32-bit
b6:
  rax -= 0x379;  // 32-bit
  goto b7;
bb6:
  rax = 0;  // 32-bit
b7:
  rax += 0x379;  // 32-bit
  goto b8;
bb7:
  rax = 0;  // 32-bit
b8:
  rax -= 0x379;  // 32-bit
  goto b10;
b9:
  explode_bomb();
  rax = 0;  // 32-bit
b10:
  if (rsp[2] > 5) goto b11;
  if (rax == rsp[3])  // 32-bit
    goto b12;
b11:
  explode_bomb();
b12:
  return;
}

Reverse analysis

逆向推导. 整个函数只有一处 return 位于 b12 中, 因此必须寻找到一条不会引发 explode_bomb() 的路径. 由于 b11 必然触发 explode_bomb(), 因此不能经过 b11, 而应通过 jmp 绕过 b11 到达 b12. 可通过 jmp 到达 b12BasicBlock 有且仅有 b10, 且必须满足 (rsp[2] <= 5) && (rax == rsp[3]). 这意味着, 只有 bb0, bb1, bb2, bb3, bb4, bb5 是可以通过 jmpq *%rax 安全到达.

删去无效的跳转点翻译为 C

void phase_3(char* rdi) {
b0:
  int rsp[6];
  int rax = 0;  // 32-bit
  rax = __isoc99_sscanf(rdi, "%d %d", rsp + 2, rsp + 3);
  if (rax > 1)  // 32-bit
    goto b1;
  explode_bomb();
b1:
  if (rsp[2] > 7) goto b9;
  int rdx = rsp[2];     // 32-bit
  int* rax = 0x4031c0;  // 4031c0 <_IO_stdin_used+0x1c0>
  rdx = rax[rdx];
  rax += rdx;
  jmpq(rax);
bb1:
  rax = 0;  // 32-bit
  goto b2;
bb0:
  rax = 0x2cb;  // 32-bit
b2:
  rax -= 0x24c;  // 32-bit
  goto b3;
bb2:
  rax = 0;  // 32-bit
b3:
  rax += 0x3ba;  // 32-bit
  goto b4;
bb3:
  rax = 0;  // 32-bit
b4:
  rax -= 0x379;  // 32-bit
  goto b5;
bb4:
  rax = 0;  // 32-bit
b5:
  rax += 0x379;  // 32-bit
  goto b6;
bb5:
  rax = 0;  // 32-bit
b6:
  rax -= 0x379;  // 32-bit
  goto b7;
  rax = 0;  // 32-bit
b7:
  rax += 0x379;  // 32-bit
  goto b8;
  rax = 0;  // 32-bit
b8:
  rax -= 0x379;  // 32-bit
  goto b10;
b9:
  explode_bomb();
  rax = 0;  // 32-bit
b10:
  if (rsp[2] > 5) goto b11;
  if (rax == rsp[3])  // 32-bit
    goto b12;
b11:
  explode_bomb();
b12:
  return;
}

跳转图

去除必然触发 explode_bombBasicBlock, 可得如下跳转图:

Solution

稍加分析不难发现, 沿着 b0 --> b1 --> bb4 --> b5 --> b6 --> b7 --> b8 --> b10 恰好能够得到 %rax == 0.

4 0