Skip to main content

Bomb Lab: Phase 6

Course WorkBomb LabComputer Organization and ArchitectureAbout 6 minAbout 1882 words

Assembly

0000000000401641 <phase_6>:
b0:
  401641:	41 56                	push   %r14
  401643:	41 55                	push   %r13
  401645:	41 54                	push   %r12
  401647:	55                   	push   %rbp
  401648:	53                   	push   %rbx
  401649:	48 83 ec 50          	sub    $0x50,%rsp
  40164d:	49 89 e5             	mov    %rsp,%r13
  401650:	48 89 e6             	mov    %rsp,%rsi
  401653:	e8 40 05 00 00       	callq  401b98 <read_six_numbers>
  401658:	49 89 e6             	mov    %rsp,%r14
  40165b:	41 bc 00 00 00 00    	mov    $0x0,%r12d
b1:
  401661:	4c 89 ed             	mov    %r13,%rbp
  401664:	41 8b 45 00          	mov    0x0(%r13),%eax
  401668:	83 e8 01             	sub    $0x1,%eax
  40166b:	83 f8 05             	cmp    $0x5,%eax
  40166e:	76 05                	jbe    401675 <phase_6+0x34>
b2:
  401670:	e8 e7 04 00 00       	callq  401b5c <explode_bomb>
b3:
  401675:	41 83 c4 01          	add    $0x1,%r12d
  401679:	41 83 fc 06          	cmp    $0x6,%r12d
  40167d:	74 21                	je     4016a0 <phase_6+0x5f>
b4:
  40167f:	44 89 e3             	mov    %r12d,%ebx
b5:
  401682:	48 63 c3             	movslq %ebx,%rax
  401685:	8b 04 84             	mov    (%rsp,%rax,4),%eax
  401688:	39 45 00             	cmp    %eax,0x0(%rbp)
  40168b:	75 05                	jne    401692 <phase_6+0x51>
b6:
  40168d:	e8 ca 04 00 00       	callq  401b5c <explode_bomb>
b7:
  401692:	83 c3 01             	add    $0x1,%ebx
  401695:	83 fb 05             	cmp    $0x5,%ebx
  401698:	7e e8                	jle    401682 <phase_6+0x41>
b8:
  40169a:	49 83 c5 04          	add    $0x4,%r13
  40169e:	eb c1                	jmp    401661 <phase_6+0x20>
b9:
  4016a0:	48 8d 74 24 18       	lea    0x18(%rsp),%rsi
  4016a5:	4c 89 f0             	mov    %r14,%rax
  4016a8:	b9 07 00 00 00       	mov    $0x7,%ecx
b10:
  4016ad:	89 ca                	mov    %ecx,%edx
  4016af:	2b 10                	sub    (%rax),%edx
  4016b1:	89 10                	mov    %edx,(%rax)
  4016b3:	48 83 c0 04          	add    $0x4,%rax
  4016b7:	48 39 f0             	cmp    %rsi,%rax
  4016ba:	75 f1                	jne    4016ad <phase_6+0x6c>
b11:
  4016bc:	be 00 00 00 00       	mov    $0x0,%esi
  4016c1:	eb 23                	jmp    4016e6 <phase_6+0xa5>
b12:
  4016c3:	48 8b 52 08          	mov    0x8(%rdx),%rdx
  4016c7:	83 c0 01             	add    $0x1,%eax
  4016ca:	39 c8                	cmp    %ecx,%eax
  4016cc:	75 f5                	jne    4016c3 <phase_6+0x82>
b13:
  4016ce:	eb 07                	jmp    4016d7 <phase_6+0x96>
b14:
  4016d0:	48 c7 c2 20 53 40 00 	mov    $0x405320,%rdx
b15:
  4016d7:	48 89 54 74 20       	mov    %rdx,0x20(%rsp,%rsi,2)
  4016dc:	48 83 c6 04          	add    $0x4,%rsi
  4016e0:	48 83 fe 18          	cmp    $0x18,%rsi
  4016e4:	74 16                	je     4016fc <phase_6+0xbb>
b16:
  4016e6:	8b 0c 34             	mov    (%rsp,%rsi,1),%ecx
  4016e9:	83 f9 01             	cmp    $0x1,%ecx
  4016ec:	7e e2                	jle    4016d0 <phase_6+0x8f>
b17:
  4016ee:	b8 01 00 00 00       	mov    $0x1,%eax
  4016f3:	48 c7 c2 20 53 40 00 	mov    $0x405320,%rdx
  4016fa:	eb c7                	jmp    4016c3 <phase_6+0x82>
b18:
  4016fc:	48 8b 5c 24 20       	mov    0x20(%rsp),%rbx
  401701:	48 8d 44 24 28       	lea    0x28(%rsp),%rax
  401706:	48 8d 74 24 50       	lea    0x50(%rsp),%rsi
  40170b:	48 89 d9             	mov    %rbx,%rcx
b19:
  40170e:	48 8b 10             	mov    (%rax),%rdx
  401711:	48 89 51 08          	mov    %rdx,0x8(%rcx)
  401715:	48 83 c0 08          	add    $0x8,%rax
  401719:	48 39 f0             	cmp    %rsi,%rax
  40171c:	74 05                	je     401723 <phase_6+0xe2>
b20:
  40171e:	48 89 d1             	mov    %rdx,%rcx
  401721:	eb eb                	jmp    40170e <phase_6+0xcd>
b21:
  401723:	48 c7 42 08 00 00 00 	movq   $0x0,0x8(%rdx)
  40172a:	00
  40172b:	bd 05 00 00 00       	mov    $0x5,%ebp
b22:
  401730:	48 8b 43 08          	mov    0x8(%rbx),%rax
  401734:	8b 00                	mov    (%rax),%eax
  401736:	39 03                	cmp    %eax,(%rbx)
  401738:	7d 05                	jge    40173f <phase_6+0xfe>
b23:
  40173a:	e8 1d 04 00 00       	callq  401b5c <explode_bomb>
b24:
  40173f:	48 8b 5b 08          	mov    0x8(%rbx),%rbx
  401743:	83 ed 01             	sub    $0x1,%ebp
  401746:	75 e8                	jne    401730 <phase_6+0xef>
b25:
  401748:	48 83 c4 50          	add    $0x50,%rsp
  40174c:	5b                   	pop    %rbx
  40174d:	5d                   	pop    %rbp
  40174e:	41 5c                	pop    %r12
  401750:	41 5d                	pop    %r13
  401752:	41 5e                	pop    %r14
  401754:	c3                   	retq

翻译为 C

void phase_6(char* rdi) {
b0:
  rsp -= 0x50;
  int* r13 = rsp;
  int* rsi = rsp;
  read_six_numbers(rdi, rsi);
  int* r14 = rsp;
  int r12 = 0;
b1:
  int* rbp = r13;
  int rax = *r13;
  if (--rax <= 5) goto b3;
b2:
  explode_bomb();
b3:
  if (++r12 == 6) goto b9;
b4:
  int rbx = r12;
b5:
  rax = rsp[rbx];
  if (*rbp != rax) goto b7;
b6:
  explode_bomb();
b7:
  if (++rbx <= 0x5) goto b5;
b8:
  r13 += 0x4;
  goto b1;
b9:
  rsi = rsp + 0x18;
  rax = r14;
  int rcx = 7;
b10:
  int rdx = rcx;
  rdx -= *rax;
  *rax = rdx;
  rax += 0x4;
  if (rax != rsi) goto b10;
b11:
  int rsi = 0;
  goto b16;
b12:
  rdx = *(rdx + 0x8);
  if (++rax != rcx) goto b12;
b13:
  goto b15;
b14:
  rdx = 0x405320;
b15:
  *(rsp + rsi * 2 + 0x20) = rdx;
  rsi += 0x4;
  if (rsi == 0x18) goto b18;
b16:
  int rcx = *(rsp + rsi * 1);
  if (rcx <= 1) goto b14;
b17:
  int rax = 1;
  rdx = 0x405320;
  goto b12;
b18:
  rbx = *(rsp + 0x20);
  rax = rsp + 0x28;
  rsi = rsp + 0x50;
  rcx = rbx;
b19:
  rdx = *rax;
  *(rcx + 0x8) = rdx;
  rax += 0x8;
  if (rax == rsi) goto b21;
b20:
  rcx = rdx;
  goto b19;
b21:
  *(rdx + 0x8) = 0;
  int rbp = 0x5;
b22:
  rax = *(rbx + 0x8);
  int rax = *rax;   // 32-bit
  if (*rbx >= rax)  // 32-bit
    goto b24;
b23:
  explode_bomb();
b24:
  rbx = *(rbx + 0x8);
  if (--rbp != 0)  // 32-bit
    goto b22;
b25:
  rsp += 0x50;
  return;
}

State Graph

Optimize

void phase_6(char* rdi) {
  b0;
  while (1) {
    b1;
    if (--rax > 5) b2;
    b3;
    if (++r12 == 6) break;
    b4;
    do {
      b5;
      if (*rbp == rax) b6;
      b7;
    } while (++rbx <= 5);
    b8;
  }
  b9;
  do {
    b10;
  } while (rax != rsi);
  b11;
  do {
    b16;
    if (rcx <= 1) {
      b14;
    } else {
      b17;
      do {
        b12;
      } while (++rax != rcx);
      b13;
    }
    b15;
  } while (rsi != 0x18);
  b18;
  while (1) {
    b19;
    if (rax == rsi) break;
    b20;
  }
  b21;
  do {
    b22;
    if (*rbx < rax) b23;
    b24;
  } while (--rbp != 0);
  b25;
}

Optimize

void phase_6(char* rdi) {
  rsp -= 0x50;
  r13 = rsp;
  rsi = rsp;
  read_six_numbers(rdi, rsi);
  r14 = rsp;
  r12 = 0;
  while (1) {
    rbp = r13;
    rax = r13;
    if (--rax > 5) explode_bomb();
    if (++r12 == 6) break;
    rbx = r12;
    do {
      if (*rbp == rax) explode_bomb();
    } while (++rbx <= 5);
    r13 += 4;
  }
  rsi = rsp + 0x18;
  rax = r14;
  rcx = 7;
  do {
    rdx = rcx;
    rdx -= *rax;
    *rax = rdx;
    rax += 4;
  } while (rax != rsi);
  rsi = 0;
  do {
    rcx = *(rsp + rsi * 1);
    if (rcx <= 1) {
      rdx = 0x405320;
    } else {
      rax = 1;
      rdx = 0x405320;
      do {
        rdx = *(rdx + 8);
      } while (++rax != rcx);
    }
    *(rsp + rsi * 2 + 0x20) = rdx;
    rsi += 4;
  } while (rsi != 0x18);
  rbx = *(rsp + 0x20);
  rax = rsp + 0x28;
  rsi = rsp + 0x50;
  rcx = rbx;
  while (1) {
    rdx = *rax;
    *(rcx + 8) = rdx;
    rax += 8;
    if (rax == rsi) break;
    rcx = rdx;
  }
  *(rdx + 8) = 0;
  rbp = 5;
  do {
    rax = *(rbx + 8);
    rax = *rax;
    if (*rbx < rax) explode_bomb();
    rbx = *(rbx + 8);
  } while (--rbp != 0);
  rsp += 0x50;
}

Hack

(gdb) x/16xg 0x405320
0x405320 <node1>:       0x00000001000002f5      0x0000000000000000
0x405330 <node2>:       0x00000002000002c7      0x0000000000405340
0x405340 <node3>:       0x0000000300000374      0x0000000000405350
0x405350 <node4>:       0x000000040000029a      0x0000000000405360
0x405360 <node5>:       0x00000005000002c2      0x0000000000405200
0x405370:       0x0000000000000000      0x0000000000000000
0x405380 <completed.7098>:      0x0000000000000000      0x0000000000000000
0x405390:       0x0000000000000000      0x0000000000000000
(gdb) x/32xw 0x405320
0x405320 <node1>:       0x000002f5      0x00000001      0x00000000      0x00000000
0x405330 <node2>:       0x000002c7      0x00000002      0x00405340      0x00000000
0x405340 <node3>:       0x00000374      0x00000003      0x00405350      0x00000000
0x405350 <node4>:       0x0000029a      0x00000004      0x00405360      0x00000000
0x405360 <node5>:       0x000002c2      0x00000005      0x00405200      0x00000000
0x405370:       0x00000000      0x00000000      0x00000000      0x00000000
0x405380 <completed.7098>:      0x00000000      0x00000000      0x00000000      0x00000000
0x405390:       0x00000000      0x00000000      0x00000000      0x00000000
(gdb) x/4xg 0x405200
0x405200 <node6>:       0x00000006000000a1      0x0000000000000000
0x405210 <user_password>:       0x64496d4a50745575      0x4c75456b5a5a4744
(gdb) x/8xw 0x405200
0x405200 <node6>:       0x000000a1      0x00000006      0x00405320      0x00000000
0x405210 <user_password>:       0x50745575      0x64496d4a      0x5a5a4744      0x4c75456b
Addressabnext
0x405320 <node1>0x2f510x0000000000405330 <node2>
0x405330 <node2>0x2c720x0000000000405340 <node3>
0x405340 <node3>0x37430x0000000000405350 <node4>
0x405350 <node4>0x29a40x0000000000405360 <node5>
0x405360 <node5>0x2c250x0000000000405200 <node6>
0x405200 <node6>0x0a100x0000000000000000 <NULL>

Optimize

struct Node {
  int a, b;
  struct Node* next;
};

void phase_6(char* rdi) {
  int rsp[6];            // rsp + 0x00 -- rsp + 0x18
  struct Node* rsp1[6];  // rsp + 0x20 -- rsp + 0x50
  read_six_numbers(rdi, rsp);
  for (int r12 = 0; r12 != 6; ++r12) {
    if (rsp[r12] - 1 > 5) explode_bomb();
    for (int rbx = r12; rbx <= 5; ++rbx) {
      if (rsp[r12] == rsp[rbx]) explode_bomb();
    }
  }
  for (int* rax = rsp; rax != rsp + 6; ++rax) *rax = 7 - *rax;
  for (int rsi = 0; rsi != 6; ++rsi) {
    struct Node* rdx = 0x405320;
    for (int rax = 1; rax < rsp[rsi]; ++rax) rdx = rdx->next;
    rsp1[rsi] = rdx;
  }
  struct Node* rcx = rsp1[0];
  for (struct Node** rax = rsp1; rax != rsp1 + 6; ++rax) {
    rcx->next = *rax;
    rcx = *rax;
  }
  rsp1[5]->next = 0;
  struct Node* rbx = rsp1[0];
  for (int rbp = 5; rbp != 0; --rbp) {
    if (rbx->a < rbx->next->a) explode_bomb();
    rbx = rbx->next;
  }
}

Analysis

从地址中可以分析出, phase_6 使用到了结构体, 猜想其结构如 struct Node 所示, 表示链表.

  read_six_numbers(rdi, rsp);

不难发现, phase_6 需要输入 6 个 int, 记为 rsp[i].

  for (int r12 = 0; r12 != 6; ++r12) {
    if (rsp[r12] - 1 > 5) explode_bomb();
    for (int rbx = r12; rbx <= 5; ++rbx) {
      if (rsp[r12] == rsp[rbx]) explode_bomb();
    }
  }

检查输入的 6 个数均 < 7, 且不重复.

  for (int* rax = rsp; rax != rsp + 6; ++rax) *rax = 7 - *rax;

将输入的 6 个数用 7 减去, 得到新的 6 个数 rsp[i] = 7 - rsp[i].

  for (int rsi = 0; rsi != 6; ++rsi) {
    struct Node* rdx = 0x405320;
    for (int rax = 1; rax < rsp[rsi]; ++rax) rdx = rdx->next;
    rsp1[rsi] = rdx;
  }

将链表的第 rsp[i] 个结点的指针存入 rsp1 内.

  struct Node* rcx = rsp1[0];
  for (struct Node** rax = rsp1; rax != rsp1 + 6; ++rax) {
    rcx->next = *rax;
    rcx = *rax;
  }
  rsp1[5]->next = 0;

对链表进行重排序, 按照 rsp[i] 指定的顺序排序.

  int rbp = 5;
  for (struct Node* rbx = rsp1[0]; rbp != 0; --rbp) {
    if (rbx->a < rbx->next->a) explode_bomb();
    rbx = rbx->next;
  }

检查排序后的链表是否满足非升序.

Solution

基于前文 Hack 中得到的数据, 我们可以给出初始时列表元素的值为

[0x2f5, 0x2c7, 0x374, 0x29a, 0x2c2, 0x0a1]

为保证列表按非升序排列, 正确的排列为

3 1 2 5 4 6

又因为过程中进行了 rsp[i] = 7 - rsp[i] 的变换, 因此正确的输入为

4 6 5 2 3 1