Blog

[CS:APP] BombLab Phase5 Walkthrough

Published 4 min read

phase_5

Dump of assembler code for function phase_5: => 0x00005555554014ca <+0>: push %rbx 0x00005555554014cb <+1>: mov %rdi,%rbx 0x00005555554014ce <+4>: callq 0x55555540176f <string_length> 0x00005555554014d3 <+9>: cmp $0x6,%eax 0x00005555554014d6 <+12>: jne 0x555555401509 <phase_5+63> 0x00005555554014d8 <+14>: mov %rbx,%rax 0x00005555554014db <+17>: lea 0x6(%rbx),%rdi 0x00005555554014df <+21>: mov $0x0,%ecx 0x00005555554014e4 <+26>: lea 0x1675(%rip),%rsi # 0x555555402b60 <array.3417> 0x00005555554014eb <+33>: movzbl (%rax),%edx 0x00005555554014ee <+36>: and $0xf,%edx 0x00005555554014f1 <+39>: add (%rsi,%rdx,4),%ecx 0x00005555554014f4 <+42>: add $0x1,%rax 0x00005555554014f8 <+46>: cmp %rdi,%rax 0x00005555554014fb <+49>: jne 0x5555554014eb <phase_5+33> 0x00005555554014fd <+51>: cmp $0x3a,%ecx 0x0000555555401500 <+54>: je 0x555555401507 <phase_5+61> 0x0000555555401502 <+56>: callq 0x555555401a90 <explode_bomb> 0x0000555555401507 <+61>: pop %rbx 0x0000555555401508 <+62>: retq 0x0000555555401509 <+63>: callq 0x555555401a90 <explode_bomb> 0x000055555540150e <+68>: jmp 0x5555554014d8 <phase_5+14>

<+1 ~ 12>

0x00005555554014cb <+1>: mov %rdi,%rbx 0x00005555554014ce <+4>: callq 0x55555540176f <string_length> 0x00005555554014d3 <+9>: cmp $0x6,%eax 0x00005555554014d6 <+12>: jne 0x555555401509 <phase_5+63>

<+1> : As analyzed before, what we enter is stored in %rdi as a single line of string. And this is also stored in %rbx.

<+4> : As analyzed in phase_1, string_length is a function that works with the registers %rdi and %rdx and returns the gap between them by storing it in %rax.

<+9> : Compares that return value with 6.

<+12> : If the return value, i.e. the length of the string, isn't 6, it jumps to <+63> and the bomb explodes, so the string we enter must have length 6.

0x0000555555401509 <+63>: callq 0x555555401a90 <explode_bomb>

<+14 ~ 36>

0x00005555554014d8 <+14>: mov %rbx,%rax 0x00005555554014db <+17>: lea 0x6(%rbx),%rdi 0x00005555554014df <+21>: mov $0x0,%ecx 0x00005555554014e4 <+26>: lea 0x1675(%rip),%rsi # 0x555555402b60 <array.3417> 0x00005555554014eb <+33>: movzbl (%rax),%edx 0x00005555554014ee <+36>: and $0xf,%edx

<+14> : Copies the pointer %rbx holds into %rax.

<+17> : Stores 0x6(%rbx), i.e. the 6th character, in %rdi.

<+21> : Stores 0 in %ecx.

<+26> : I'm guessing this stores an array.

<+33> : (%rax) is the first character of the string. This is stored in %edx.

<+36> : ANDs the first character with 15. Regardless of whether it's an uppercase or lowercase English letter or a digit character, it maps them in order to the integers 1 through 26.

abcdefghijkl
ABCDEFGHIJKL
'1''2''3''4''5''6''7''8''9'
↓↓↓↓↓↓↓↓↓↓↓↓
123456789101112
mnopqrstuvwxyz
MNOPQRSTUVWXYZ
↓↓↓↓↓↓↓↓↓↓↓↓↓↓
1314151617181920212223242526

<+39 ~ 68>

0x00005555554014f1 <+39>: add (%rsi,%rdx,4),%ecx 0x00005555554014f4 <+42>: add $0x1,%rax 0x00005555554014f8 <+46>: cmp %rdi,%rax 0x00005555554014fb <+49>: jne 0x5555554014eb <phase_5+33> 0x00005555554014fd <+51>: cmp $0x3a,%ecx 0x0000555555401500 <+54>: je 0x555555401507 <phase_5+61> 0x0000555555401502 <+56>: callq 0x555555401a90 <explode_bomb> 0x0000555555401507 <+61>: pop %rbx 0x0000555555401508 <+62>: retq 0x0000555555401509 <+63>: callq 0x555555401a90 <explode_bomb> 0x000055555540150e <+68>: jmp 0x5555554014d8 <phase_5+14>

<+39> : An array whose contents are hard to tell was stored in %rsi. And from the operand of this <+39>, we can see that the array in %rsi is accessed in 4-byte units. So we can view %rsi as holding a 4-byte int array.

(gdb) x/30dw $rsi 0x555555402b60 <array.3417>: 2 10 6 1 0x555555402b70 <array.3417+16>: 12 16 9 3 0x555555402b80 <array.3417+32>: 4 7 14 5 0x555555402b90 <array.3417+48>: 11 8 15 13 0x555555402ba0: 2032168787 1948284271 1802398056 1970239776 0x555555402bb0: 1851876128 1869902624 1752440944 1868701797 0x555555402bc0: 1998611053 543716457 1819440227 539779885 0x555555402bd0: 2032168804 4158831

So, if we print the values stored in memory split into 4-byte units, we get the following.

I printed 30 of them, and up to the 16th there are values that look like they were put in deliberately, and after that there are garbage values, so I only wrote down the first 16 that seem like they'll be used.

And it stores in %ecx the element reached by moving through this array one slot at a time, as many times as the value of the first character we entered ANDed with 15.

Since I assumed we entered "abcdef", it stores 2, the first element.

<+42> : Adds 1 to %rax.

<+46> : Compares %rax and %rdi.

<+49> : If %rax and %rdi are different, jumps to <+33>.

<+51> : If %rax and %rdi are the same, compares 58 with %ecx.

<+54> : If it's 58, it jumps to <+61> and the phase is solved.

<Conclusion>

If we look at the situation,

%rax goes through the array from the first element to the last element.

While going through it, each character we entered acts as an index into the integer array above, and the integer the index points to is accumulated into %ecx.

And once it finishes going through the last element, R[%ecx] must be 58.

In other words, the string we need to enter is one where each character maps to 1 through 9 and their sum is 58, and there are tons of answers.

To give just a few examples,

first we need to split 58 into a sum of 6 numbers from the array above,

so we can split it as 10 + 10 + 10 + 16 + 9 + 3.

The index of each number is 1 1 1 5 6 7, and there are tons of possible combinations of characters that map to 1 1 1 5 6 7, including the ones below.

aaaefg, 111567, AAAEFG, a1156G

Comments

Leaving a comment stores your nickname (or GitHub profile info). Privacy policy

GitHub