CS:APP Bomb Lab Report

Name SUNCHAOYI

First use objdump -d bomb > bomb.asm to get its assmebly.

Phase_1

1
2
3
4
5
6
7
8
9
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 call 401338 <strings_not_equal>
400eee: 85 c0 test %eax,%eax
400ef0: 74 05 je 400ef7 <phase_1+0x17>
400ef2: e8 43 05 00 00 call 40143a <explode_bomb>
400ef7: 48 83 c4 08 add $0x8,%rsp
400efb: c3 ret
  • mov $0x402400,%esi

    0x402400 contains the password string. Use GDB’s x/s command to display the string at that memory address:

    1
    2
    gdb bomb
    (gdb) x/s 0x402400

The Phase_1 answer is Border relations with Canada have never been better.

Phase_2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
0000000000400efc <phase_2>:
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 call 40145c <read_six_numbers>
400f0a: 83 3c 24 01 cmpl $0x1,(%rsp)
400f0e: 74 20 je 400f30 <phase_2+0x34>
400f10: e8 25 05 00 00 call 40143a <explode_bomb>
400f15: eb 19 jmp 400f30 <phase_2+0x34>
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 <phase_2+0x29>
400f20: e8 15 05 00 00 call 40143a <explode_bomb>
400f25: 48 83 c3 04 add $0x4,%rbx
400f29: 48 39 eb cmp %rbp,%rbx
400f2c: 75 e9 jne 400f17 <phase_2+0x1b>
400f2e: eb 0c jmp 400f3c <phase_2+0x40>
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 <phase_2+0x1b>
400f3c: 48 83 c4 28 add $0x28,%rsp
400f40: 5b pop %rbx
400f41: 5d pop %rbp
400f42: c3 ret
  • cmpl $0x1,(%rsp) & je 400f30 <phase_2+0x34>

    If the value at the top of the stack is 1, jump to address 0x400f30.

  • lea 0x4(%rsp),%rbx & lea 0x18(%rsp),%rbp & jmp 400f17 <phase_2+0x1b>

    %rbx is set to point to the second element of the array (&numbers[1]).

    %rbp is set to point just past the last element (&numbers[6]), since 0x18 $= 6 \times 4 = 24$ bytes.

    Execution then jumps to the loop body at 400f17.

  • 400f17 $\sim$ 400f2c (loop body)

    Load the previous element (numbers[i-1]) into %eax, double it, and compare the result with the current element (numbers[i]).

    Only if numbers[i] == 2 * numbers[i-1] does the loop continue; otherwise the bomb explodes.

    After processing all six numbers, control jumps to 400f3c (loop exit).

The required sequence for Phase 2 is therefore 1 2 4 8 16 32.

Phase_3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
0000000000400f43 <phase_3>:
400f43: 48 83 ec 18 sub $0x18,%rsp
400f47: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx
400f4c: 48 8d 54 24 08 lea 0x8(%rsp),%rdx
400f51: be cf 25 40 00 mov $0x4025cf,%esi
400f56: b8 00 00 00 00 mov $0x0,%eax
400f5b: e8 90 fc ff ff call 400bf0 <__isoc99_sscanf@plt>
400f60: 83 f8 01 cmp $0x1,%eax
400f63: 7f 05 jg 400f6a <phase_3+0x27>
400f65: e8 d0 04 00 00 call 40143a <explode_bomb>
400f6a: 83 7c 24 08 07 cmpl $0x7,0x8(%rsp)
400f6f: 77 3c ja 400fad <phase_3+0x6a>
400f71: 8b 44 24 08 mov 0x8(%rsp),%eax
400f75: ff 24 c5 70 24 40 00 jmp *0x402470(,%rax,8)
400f7c: b8 cf 00 00 00 mov $0xcf,%eax
400f81: eb 3b jmp 400fbe <phase_3+0x7b>
400f83: b8 c3 02 00 00 mov $0x2c3,%eax
400f88: eb 34 jmp 400fbe <phase_3+0x7b>
400f8a: b8 00 01 00 00 mov $0x100,%eax
400f8f: eb 2d jmp 400fbe <phase_3+0x7b>
400f91: b8 85 01 00 00 mov $0x185,%eax
400f96: eb 26 jmp 400fbe <phase_3+0x7b>
400f98: b8 ce 00 00 00 mov $0xce,%eax
400f9d: eb 1f jmp 400fbe <phase_3+0x7b>
400f9f: b8 aa 02 00 00 mov $0x2aa,%eax
400fa4: eb 18 jmp 400fbe <phase_3+0x7b>
400fa6: b8 47 01 00 00 mov $0x147,%eax
400fab: eb 11 jmp 400fbe <phase_3+0x7b>
400fad: e8 88 04 00 00 call 40143a <explode_bomb>
400fb2: b8 00 00 00 00 mov $0x0,%eax
400fb7: eb 05 jmp 400fbe <phase_3+0x7b>
400fb9: b8 37 01 00 00 mov $0x137,%eax
400fbe: 3b 44 24 0c cmp 0xc(%rsp),%eax
400fc2: 74 05 je 400fc9 <phase_3+0x86>
400fc4: e8 71 04 00 00 call 40143a <explode_bomb>
400fc9: 48 83 c4 18 add $0x18,%rsp
400fcd: c3 ret
  • mov $0x4025cf,%esi & cmp $0x1,%eax & jg 400f6a <phase_3+0x27>

    Using (gdb) x/s 0x4025cf shows "%d %d", meaning the input must be two integers separated by a space.

    If sscanf returns a value $\le 1$, the bomb explodes.

  • lea 0xc(%rsp),%rcx & lea 0x8(%rsp),%rdx & cmpl $0x7,0x8(%rsp) & ja 400fad <phase_3+0x6a>

    %rdx points to where the first integer is stored (0x8(%rsp)), and %rcx points to the second integer (0xc(%rsp)).

    The first integer must be $\le 7$, otherwise the bomb explodes.

  • 400f7c $\sim$ 400fbe (switch body)

    Each case loads a specific immediate value into %eax, then jumps to a common check at 400fbe.

    There, the loaded value is compared with the second integer. Only if they are equal does the phase pass.

From the jump‑table cases we obtain the valid pairs:

1
0 207 / 1 311 / 2 707 / 3 256 / 4 389 / 5 206 / 6 682 / 7 327

Any one of these pairs is a correct solution.

Phase_4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
0000000000400fce <func4>:
400fce: 48 83 ec 08 sub $0x8,%rsp
400fd2: 89 d0 mov %edx,%eax
400fd4: 29 f0 sub %esi,%eax
400fd6: 89 c1 mov %eax,%ecx
400fd8: c1 e9 1f shr $0x1f,%ecx
400fdb: 01 c8 add %ecx,%eax
400fdd: d1 f8 sar $1,%eax
400fdf: 8d 0c 30 lea (%rax,%rsi,1),%ecx
400fe2: 39 f9 cmp %edi,%ecx
400fe4: 7e 0c jle 400ff2 <func4+0x24>
400fe6: 8d 51 ff lea -0x1(%rcx),%edx
400fe9: e8 e0 ff ff ff call 400fce <func4>
400fee: 01 c0 add %eax,%eax
400ff0: eb 15 jmp 401007 <func4+0x39>
400ff2: b8 00 00 00 00 mov $0x0,%eax
400ff7: 39 f9 cmp %edi,%ecx
400ff9: 7d 0c jge 401007 <func4+0x39>
400ffb: 8d 71 01 lea 0x1(%rcx),%esi
400ffe: e8 cb ff ff ff call 400fce <func4>
401003: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax
401007: 48 83 c4 08 add $0x8,%rsp
40100b: c3 ret
000000000040100c <phase_4>:
40100c: 48 83 ec 18 sub $0x18,%rsp
401010: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx
401015: 48 8d 54 24 08 lea 0x8(%rsp),%rdx
40101a: be cf 25 40 00 mov $0x4025cf,%esi
40101f: b8 00 00 00 00 mov $0x0,%eax
401024: e8 c7 fb ff ff call 400bf0 <__isoc99_sscanf@plt>
401029: 83 f8 02 cmp $0x2,%eax
40102c: 75 07 jne 401035 <phase_4+0x29>
40102e: 83 7c 24 08 0e cmpl $0xe,0x8(%rsp)
401033: 76 05 jbe 40103a <phase_4+0x2e>
401035: e8 00 04 00 00 call 40143a <explode_bomb>
40103a: ba 0e 00 00 00 mov $0xe,%edx
40103f: be 00 00 00 00 mov $0x0,%esi
401044: 8b 7c 24 08 mov 0x8(%rsp),%edi
401048: e8 81 ff ff ff call 400fce <func4>
40104d: 85 c0 test %eax,%eax
40104f: 75 07 jne 401058 <phase_4+0x4c>
401051: 83 7c 24 0c 00 cmpl $0x0,0xc(%rsp)
401056: 74 05 je 40105d <phase_4+0x51>
401058: e8 dd 03 00 00 call 40143a <explode_bomb>
40105d: 48 83 c4 18 add $0x18,%rsp
401061: c3 ret
  • mov $0x4025cf,%esi & cmp $0x2,%eax & jne 401035 <phase_4+0x29>

    Using (gdb) x/s 0x4025cf shows "%d %d", meaning the input must be two integers separated by a space.

    If sscanf returns a value $\neq 2$, the bomb explodes.

  • lea 0xc(%rsp),%rcx & lea 0x8(%rsp),%rdx & cmpl $0xe,0x8(%rsp) & cmpl $0x0,0xc(%rsp)

    %rdx points to where the first integer is stored (0x8(%rsp)), and %rcx points to the second integer (0xc(%rsp)).

    The first integer must be $\le 14$, the second integer must exactly $0$, otherwise the bomb explodes.

  • mov $0xe,%edx & mov $0x0,%esi & mov 0x8(%rsp),%edi & call 400fce &cmpl $0x0,0xc(%rsp)`

    Three arguments are passed to func4, i.e. func4(first_number,0,14).

    The function must return 0, otherwise the bomb explodes.

  • <func4> assembly translated to C language

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    int func4(int target, int low, int high)
    {
    int mid = low + (high - low) / 2;
    //since low = 0,high = 14 so the sign bit = 0, which can be ignored.
    if (mid <= target)
    {
    if (mid >= target) return 0; // i.e. target can be found
    else
    {
    low = mid + 1;
    return 2 * func4 (target,low,high) + 1;
    }
    }
    else
    {
    high = mid - 1;
    return 2 * func4 (target,low,high);
    }
    }

The function returns $0$ only when first_number lies on the “mid‑point path” of the binary search.The valid values for the first number are $0,1,3,7$.

Combining all conditions, the correct answers for Phase_4 are any of the following pairs:

1
0 0 / 1 0 / 3 0 / 7 0

Phase_5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
0000000000401062 <phase_5>:
401062: 53 push %rbx
401063: 48 83 ec 20 sub $0x20,%rsp
401067: 48 89 fb mov %rdi,%rbx
40106a: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
401071: 00 00
401073: 48 89 44 24 18 mov %rax,0x18(%rsp)
401078: 31 c0 xor %eax,%eax
40107a: e8 9c 02 00 00 call 40131b <string_length>
40107f: 83 f8 06 cmp $0x6,%eax
401082: 74 4e je 4010d2 <phase_5+0x70>
401084: e8 b1 03 00 00 call 40143a <explode_bomb>
401089: eb 47 jmp 4010d2 <phase_5+0x70>
40108b: 0f b6 0c 03 movzbl (%rbx,%rax,1),%ecx
40108f: 88 0c 24 mov %cl,(%rsp)
401092: 48 8b 14 24 mov (%rsp),%rdx
401096: 83 e2 0f and $0xf,%edx
401099: 0f b6 92 b0 24 40 00 movzbl 0x4024b0(%rdx),%edx
4010a0: 88 54 04 10 mov %dl,0x10(%rsp,%rax,1)
4010a4: 48 83 c0 01 add $0x1,%rax
4010a8: 48 83 f8 06 cmp $0x6,%rax
4010ac: 75 dd jne 40108b <phase_5+0x29>
4010ae: c6 44 24 16 00 movb $0x0,0x16(%rsp)
4010b3: be 5e 24 40 00 mov $0x40245e,%esi
4010b8: 48 8d 7c 24 10 lea 0x10(%rsp),%rdi
4010bd: e8 76 02 00 00 call 401338 <strings_not_equal>
4010c2: 85 c0 test %eax,%eax
4010c4: 74 13 je 4010d9 <phase_5+0x77>
4010c6: e8 6f 03 00 00 call 40143a <explode_bomb>
4010cb: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
4010d0: eb 07 jmp 4010d9 <phase_5+0x77>
4010d2: b8 00 00 00 00 mov $0x0,%eax
4010d7: eb b2 jmp 40108b <phase_5+0x29>
4010d9: 48 8b 44 24 18 mov 0x18(%rsp),%rax
4010de: 64 48 33 04 25 28 00 xor %fs:0x28,%rax
4010e5: 00 00
4010e7: 74 05 je 4010ee <phase_5+0x8c>
4010e9: e8 42 fa ff ff call 400b30 <__stack_chk_fail@plt>
4010ee: 48 83 c4 20 add $0x20,%rsp
4010f2: 5b pop %rbx
4010f3: c3 ret
  • call 40131b <string_length> & cmp $0x6,%eax

    The input must be a string of exactly six characters.

  • 40108b $\sim$ 4010ac (loop body)

    For each character input[i]:

    1. Take its low‑order 4 bits (input[i] & 0xF) as an index ($0 \sim 15$).
    2. Use that index to look up a character from a table stored at address 0x4024b0.
    3. Store the looked‑up character into an output buffer on the stack.

      Examining the table (gdb) x/s 0x4024b0, get maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?. The relevant part is the first 16 characters: maduiersnfotvbyl.

      The converted six‑character string must equal the string at 0x40245e. Checking (gdb) x/s 0x40245e, get flyers.

      Hence the condition for each position $i$ is: table[input[i] & 0xF] == "flyers"[i]

Therefore, the answer is ionefg.

Phase_6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
00000000004010f4 <phase_6>:
4010f4: 41 56 push %r14
4010f6: 41 55 push %r13
4010f8: 41 54 push %r12
4010fa: 55 push %rbp
4010fb: 53 push %rbx
4010fc: 48 83 ec 50 sub $0x50,%rsp
401100: 49 89 e5 mov %rsp,%r13
401103: 48 89 e6 mov %rsp,%rsi
401106: e8 51 03 00 00 call 40145c <read_six_numbers>
40110b: 49 89 e6 mov %rsp,%r14
40110e: 41 bc 00 00 00 00 mov $0x0,%r12d
401114: 4c 89 ed mov %r13,%rbp
401117: 41 8b 45 00 mov 0x0(%r13),%eax
40111b: 83 e8 01 sub $0x1,%eax
40111e: 83 f8 05 cmp $0x5,%eax
401121: 76 05 jbe 401128 <phase_6+0x34>
401123: e8 12 03 00 00 call 40143a <explode_bomb>
401128: 41 83 c4 01 add $0x1,%r12d
40112c: 41 83 fc 06 cmp $0x6,%r12d
401130: 74 21 je 401153 <phase_6+0x5f>
401132: 44 89 e3 mov %r12d,%ebx
401135: 48 63 c3 movslq %ebx,%rax
401138: 8b 04 84 mov (%rsp,%rax,4),%eax
40113b: 39 45 00 cmp %eax,0x0(%rbp)
40113e: 75 05 jne 401145 <phase_6+0x51>
401140: e8 f5 02 00 00 call 40143a <explode_bomb>
401145: 83 c3 01 add $0x1,%ebx
401148: 83 fb 05 cmp $0x5,%ebx
40114b: 7e e8 jle 401135 <phase_6+0x41>
40114d: 49 83 c5 04 add $0x4,%r13
401151: eb c1 jmp 401114 <phase_6+0x20>
401153: 48 8d 74 24 18 lea 0x18(%rsp),%rsi
401158: 4c 89 f0 mov %r14,%rax
40115b: b9 07 00 00 00 mov $0x7,%ecx
401160: 89 ca mov %ecx,%edx
401162: 2b 10 sub (%rax),%edx
401164: 89 10 mov %edx,(%rax)
401166: 48 83 c0 04 add $0x4,%rax
40116a: 48 39 f0 cmp %rsi,%rax
40116d: 75 f1 jne 401160 <phase_6+0x6c>
40116f: be 00 00 00 00 mov $0x0,%esi
401174: eb 21 jmp 401197 <phase_6+0xa3>
401176: 48 8b 52 08 mov 0x8(%rdx),%rdx
40117a: 83 c0 01 add $0x1,%eax
40117d: 39 c8 cmp %ecx,%eax
40117f: 75 f5 jne 401176 <phase_6+0x82>
401181: eb 05 jmp 401188 <phase_6+0x94>
401183: ba d0 32 60 00 mov $0x6032d0,%edx
401188: 48 89 54 74 20 mov %rdx,0x20(%rsp,%rsi,2)
40118d: 48 83 c6 04 add $0x4,%rsi
401191: 48 83 fe 18 cmp $0x18,%rsi
401195: 74 14 je 4011ab <phase_6+0xb7>
401197: 8b 0c 34 mov (%rsp,%rsi,1),%ecx
40119a: 83 f9 01 cmp $0x1,%ecx
40119d: 7e e4 jle 401183 <phase_6+0x8f>
40119f: b8 01 00 00 00 mov $0x1,%eax
4011a4: ba d0 32 60 00 mov $0x6032d0,%edx
4011a9: eb cb jmp 401176 <phase_6+0x82>
4011ab: 48 8b 5c 24 20 mov 0x20(%rsp),%rbx
4011b0: 48 8d 44 24 28 lea 0x28(%rsp),%rax
4011b5: 48 8d 74 24 50 lea 0x50(%rsp),%rsi
4011ba: 48 89 d9 mov %rbx,%rcx
4011bd: 48 8b 10 mov (%rax),%rdx
4011c0: 48 89 51 08 mov %rdx,0x8(%rcx)
4011c4: 48 83 c0 08 add $0x8,%rax
4011c8: 48 39 f0 cmp %rsi,%rax
4011cb: 74 05 je 4011d2 <phase_6+0xde>
4011cd: 48 89 d1 mov %rdx,%rcx
4011d0: eb eb jmp 4011bd <phase_6+0xc9>
4011d2: 48 c7 42 08 00 00 00 movq $0x0,0x8(%rdx)
4011d9: 00
4011da: bd 05 00 00 00 mov $0x5,%ebp
4011df: 48 8b 43 08 mov 0x8(%rbx),%rax
4011e3: 8b 00 mov (%rax),%eax
4011e5: 39 03 cmp %eax,(%rbx)
4011e7: 7d 05 jge 4011ee <phase_6+0xfa>
4011e9: e8 4c 02 00 00 call 40143a <explode_bomb>
4011ee: 48 8b 5b 08 mov 0x8(%rbx),%rbx
4011f2: 83 ed 01 sub $0x1,%ebp
4011f5: 75 e8 jne 4011df <phase_6+0xeb>
4011f7: 48 83 c4 50 add $0x50,%rsp
4011fb: 5b pop %rbx
4011fc: 5d pop %rbp
4011fd: 41 5c pop %r12
4011ff: 41 5d pop %r13
401201: 41 5e pop %r14
401203: c3 ret
  • 4010f4 $\sim$ 40110e

    Calls read_six_numbers to read six integers into an array on the stack.

  • 401114 $\sim$ 401151

    The double loop checks 1 <= number[i] <= 6 (subtracting 1 converts the range check into an unsigned comparison with 5) and ensures all six numbers are distinct.

  • 401153 $\sim$ 40116d

    Each number is transformed as number[i] = 7 - number[i]

  • 40116f $\sim$ 4011a9

    The starting address 0x6032d0 is examined. Inspection via (gdb) x/128x 0x6032d0 reveals a linked-list structure.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    0x6032d0 <node1>:       0x4c    0x01    0x00    0x00    0x01    0x00    0x00    0x00
    0x6032d8 <node1+8>: 0xe0 0x32 0x60 0x00 0x00 0x00 0x00 0x00
    0x6032e0 <node2>: 0xa8 0x00 0x00 0x00 0x02 0x00 0x00 0x00
    0x6032e8 <node2+8>: 0xf0 0x32 0x60 0x00 0x00 0x00 0x00 0x00
    0x6032f0 <node3>: 0x9c 0x03 0x00 0x00 0x03 0x00 0x00 0x00
    0x6032f8 <node3+8>: 0x00 0x33 0x60 0x00 0x00 0x00 0x00 0x00
    0x603300 <node4>: 0xb3 0x02 0x00 0x00 0x04 0x00 0x00 0x00
    0x603308 <node4+8>: 0x10 0x33 0x60 0x00 0x00 0x00 0x00 0x00
    0x603310 <node5>: 0xdd 0x01 0x00 0x00 0x05 0x00 0x00 0x00
    0x603318 <node5+8>: 0x20 0x33 0x60 0x00 0x00 0x00 0x00 0x00
    0x603320 <node6>: 0xbb 0x01 0x00 0x00 0x06 0x00 0x00 0x00
    0x603328 <node6+8>: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

    Each node occupies 16 bits (value (4 bits), id (4 bits) address (8 bits)) organized in Little-Endian format. This structure clearly defines a singly linked list.

    node $i$ value address next pointer
    1 0x14c 0x6032d0 0x6032e0
    2 0xa8 0x6032e0 0x6032f0
    3 0x39c 0x6032f0 0x603300
    4 0x2b3 0x603300 0x603310
    5 0x1dd 0x603310 0x603320
    6 0x1bb 0x603320 NULL

    For each transformed number[i], if number[i] <= 1, the head node is used directly; otherwise, a loop traverses the list to select the number[i]-th node.

  • 4011ab $\sim$ 4011d9

    The code rebuilds the linked list according to the order specified by the transformed number[i] values.

    • Register roles

      • %rbx Address of the new head node (read from node_ptrs[0] on the stack)

      • %rcx Address of the current node being processed

      • %rdx Address of the next node (read from the pointer array on the stack)

      • %rax Points to the storage location of the next node pointer in the stack array

    • Instructions

      • mov %rbx,%rcx Set the current node to the head node

      • mov (%rax),%rdx Read the address of the next node from the stack

      • mov %rdx,0x8(%rcx) Make the current node point to the next node

  • 4011da $\sim$ 4011f5

    cmp %eax,(%rbx) This ensures the final list is sorted in non‑increasing order by the integer values stored in the nodes.

The original values in the list are $[\texttt{0x14c},\texttt{0xa8},\texttt{0x39c},\texttt{0x2b3},\texttt{0x1dd},\texttt{0x1bb}]$. When sorted in descending order by value, the corresponding node IDs are $[3,4,5,6,1,2]$. This ID order represents the transformed input. Since the transformation is num[i] = 7 - original[i], we reverse it to obtain the original input 4,3,2,1,6,5.

secret_phase

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
00000000004015c4 <phase_defused>:
4015c4: 48 83 ec 78 sub $0x78,%rsp
4015c8: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
4015cf: 00 00
4015d1: 48 89 44 24 68 mov %rax,0x68(%rsp)
4015d6: 31 c0 xor %eax,%eax
4015d8: 83 3d 81 21 20 00 06 cmpl $0x6,0x202181(%rip) # 603760 <num_input_strings>
4015df: 75 5e jne 40163f <phase_defused+0x7b>
4015e1: 4c 8d 44 24 10 lea 0x10(%rsp),%r8
4015e6: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx
4015eb: 48 8d 54 24 08 lea 0x8(%rsp),%rdx
4015f0: be 19 26 40 00 mov $0x402619,%esi
4015f5: bf 70 38 60 00 mov $0x603870,%edi
4015fa: e8 f1 f5 ff ff call 400bf0 <__isoc99_sscanf@plt>
4015ff: 83 f8 03 cmp $0x3,%eax
401602: 75 31 jne 401635 <phase_defused+0x71>
401604: be 22 26 40 00 mov $0x402622,%esi
401609: 48 8d 7c 24 10 lea 0x10(%rsp),%rdi
40160e: e8 25 fd ff ff call 401338 <strings_not_equal>
401613: 85 c0 test %eax,%eax
401615: 75 1e jne 401635 <phase_defused+0x71>
401617: bf f8 24 40 00 mov $0x4024f8,%edi
40161c: e8 ef f4 ff ff call 400b10 <puts@plt>
401621: bf 20 25 40 00 mov $0x402520,%edi
401626: e8 e5 f4 ff ff call 400b10 <puts@plt>
40162b: b8 00 00 00 00 mov $0x0,%eax
401630: e8 0d fc ff ff call 401242 <secret_phase>
401635: bf 58 25 40 00 mov $0x402558,%edi
40163a: e8 d1 f4 ff ff call 400b10 <puts@plt>
40163f: 48 8b 44 24 68 mov 0x68(%rsp),%rax
401644: 64 48 33 04 25 28 00 xor %fs:0x28,%rax
40164b: 00 00
40164d: 74 05 je 401654 <phase_defused+0x90>
40164f: e8 dc f4 ff ff call 400b30 <__stack_chk_fail@plt>
401654: 48 83 c4 78 add $0x78,%rsp
401658: c3 ret
401659: 90 nop
40165a: 90 nop
40165b: 90 nop
40165c: 90 nop
40165d: 90 nop
40165e: 90 nop
40165f: 90 nop

The existence of a secret_phase can be identified by examining the <phase_defused> function. When inspecting at address 0x402619 with (gdb) x/s 0x402619, the format string "%d %d %s" is revealed.

To investigate further, set a breakpoint at 0x4015fa using (gdb) b *0x4015fa. After running the bomb executable and providing the correct solution for the earlier phases, we can examine the content at address 0x603870 with (gdb) x/s 0x603870 (since the breakpoint is triggered during phase_4). This reveals that the "%d %d %s" format corresponds to the fourth phase, and we need to determine the correct string to enter along with the two integers.

The code segment lea 0x10(%rsp),%rdi loads the address of the user-supplied string (the third argument) into %rdi, while mov $0x402622,%esi loads the address of the expected ciphertext into %esi. By examining memory with (gdb) x/s 0x402622, we obtain the string DrEvil. This is the secret password needed to unlock the hidden phase.

Thus, to pass phase_4 and activate the secret_phase, we must append DrEvil as a third input after the two integer answers. One complete input sequence for the entire bomb could be:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
Border relations with Canada have never been better.
1 2 4 8 16 32
0 207
0 0 DrEvil
ionefg
4 3 2 1 6 5
``

---

```assembly
0000000000401204 <fun7>:
401204: 48 83 ec 08 sub $0x8,%rsp
401208: 48 85 ff test %rdi,%rdi
40120b: 74 2b je 401238 <fun7+0x34>
40120d: 8b 17 mov (%rdi),%edx
40120f: 39 f2 cmp %esi,%edx
401211: 7e 0d jle 401220 <fun7+0x1c>
401213: 48 8b 7f 08 mov 0x8(%rdi),%rdi
401217: e8 e8 ff ff ff call 401204 <fun7>
40121c: 01 c0 add %eax,%eax
40121e: eb 1d jmp 40123d <fun7+0x39>
401220: b8 00 00 00 00 mov $0x0,%eax
401225: 39 f2 cmp %esi,%edx
401227: 74 14 je 40123d <fun7+0x39>
401229: 48 8b 7f 10 mov 0x10(%rdi),%rdi
40122d: e8 d2 ff ff ff call 401204 <fun7>
401232: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax
401236: eb 05 jmp 40123d <fun7+0x39>
401238: b8 ff ff ff ff mov $0xffffffff,%eax
40123d: 48 83 c4 08 add $0x8,%rsp
401241: c3 ret
0000000000401242 <secret_phase>:
401242: 53 push %rbx
401243: e8 56 02 00 00 call 40149e <read_line>
401248: ba 0a 00 00 00 mov $0xa,%edx
40124d: be 00 00 00 00 mov $0x0,%esi
401252: 48 89 c7 mov %rax,%rdi
401255: e8 76 f9 ff ff call 400bd0 <strtol@plt>
40125a: 48 89 c3 mov %rax,%rbx
40125d: 8d 40 ff lea -0x1(%rax),%eax
401260: 3d e8 03 00 00 cmp $0x3e8,%eax
401265: 76 05 jbe 40126c <secret_phase+0x2a>
401267: e8 ce 01 00 00 call 40143a <explode_bomb>
40126c: 89 de mov %ebx,%esi
40126e: bf f0 30 60 00 mov $0x6030f0,%edi
401273: e8 8c ff ff ff call 401204 <fun7>
401278: 83 f8 02 cmp $0x2,%eax
40127b: 74 05 je 401282 <secret_phase+0x40>
40127d: e8 b8 01 00 00 call 40143a <explode_bomb>
401282: bf 38 24 40 00 mov $0x402438,%edi
401287: e8 84 f8 ff ff call 400b10 <puts@plt>
40128c: e8 33 03 00 00 call 4015c4 <phase_defused>
401291: 5b pop %rbx
401292: c3 ret
401293: 90 nop
401294: 90 nop
401295: 90 nop
401296: 90 nop
401297: 90 nop
401298: 90 nop
401299: 90 nop
40129a: 90 nop
40129b: 90 nop
40129c: 90 nop
40129d: 90 nop
40129e: 90 nop
40129f: 90 nop
  • lea -0x1(%rax),%eax & cmp $0x3e8,%eax

    The range of the input number must be $[1,1001]$.

  • mov %ebx,%esi & mov $0x6030f0,%edi & call 401204 <fun7> & cmp $0x2,%eax

    The condition for passing the secret phase is that the return value of fun7(0x6030f0, input) must equal 2.

  • <fun7>

    Using (gdb) x/60x 0x6030f0 to inspect memory, we obtain the following data:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    0x6030f0 <n1>:  0x0000000000000024      0x0000000000603110
    0x603100 <n1+16>: 0x0000000000603130 0x0000000000000000
    0x603110 <n21>: 0x0000000000000008 0x0000000000603190
    0x603120 <n21+16>: 0x0000000000603150 0x0000000000000000
    0x603130 <n22>: 0x0000000000000032 0x0000000000603170
    0x603140 <n22+16>: 0x00000000006031b0 0x0000000000000000
    0x603150 <n32>: 0x0000000000000016 0x0000000000603270
    0x603160 <n32+16>: 0x0000000000603230 0x0000000000000000
    0x603170 <n33>: 0x000000000000002d 0x00000000006031d0
    0x603180 <n33+16>: 0x0000000000603290 0x0000000000000000
    0x603190 <n31>: 0x0000000000000006 0x00000000006031f0
    0x6031a0 <n31+16>: 0x0000000000603250 0x0000000000000000
    0x6031b0 <n34>: 0x000000000000006b 0x0000000000603210
    0x6031c0 <n34+16>: 0x00000000006032b0 0x0000000000000000
    0x6031d0 <n45>: 0x0000000000000028 0x0000000000000000
    0x6031e0 <n45+16>: 0x0000000000000000 0x0000000000000000
    0x6031f0 <n41>: 0x0000000000000001 0x0000000000000000
    0x603200 <n41+16>: 0x0000000000000000 0x0000000000000000
    0x603210 <n47>: 0x0000000000000063 0x0000000000000000
    0x603220 <n47+16>: 0x0000000000000000 0x0000000000000000
    0x603230 <n44>: 0x0000000000000023 0x0000000000000000
    0x603240 <n44+16>: 0x0000000000000000 0x0000000000000000
    0x603250 <n42>: 0x0000000000000007 0x0000000000000000
    0x603260 <n42+16>: 0x0000000000000000 0x0000000000000000
    0x603270 <n43>: 0x0000000000000014 0x0000000000000000
    0x603280 <n43+16>: 0x0000000000000000 0x0000000000000000
    0x603290 <n46>: 0x000000000000002f 0x0000000000000000
    0x6032a0 <n46+16>: 0x0000000000000000 0x0000000000000000
    0x6032b0 <n48>: 0x00000000000003e9 0x0000000000000000
    0x6032c0 <n48+16>: 0x0000000000000000 0x0000000000000000

    A BST can be constructed at address 0x6030f0:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
                36 (n1)
    / \
    / \
    8 (n21) 50 (n22)
    / \ / \
    / \ / \
    6 (n31) 22(n32) 45(n33) 107(n34)
    / \ / \ / \ / \
    1 7 20 35 40 47 99 1001
    (n41)(n42)(n43)(n44)(n45)(n46)(n47)(n48)

    Translating the assembly logic of fun7 into C language:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int func7 (T *u,int target)
    {
    if (u == NULL) return -1;
    if (&u <= target)
    {
    if (&u == target) return 0;
    else return 2 * func7 (p -> right,target) + 1;
    }
    else return 2 * func7 (p -> left,target);
    }

    The function encodes the search path as a binary number. To obtain a return value of 2, the recursive sequence must satisfy $2 \times (2 \times 0 + 1) = 2$. This corresponds to the search path left → right → match: from root (36) go left to 8, then right to 22, where the value is found.

    Thus, the input that satisfies fun7(0x6030f0, input) == 2 is 22.


Final answer:

1
2
3
4
5
6
7
Border relations with Canada have never been better.
1 2 4 8 16 32
0 207
0 0 DrEvil
ionefg
4 3 2 1 6 5
22