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> : 전에 분석했듯이 우리가 입력한 것들은 한줄의 문자열로 %rdi에 저장됩니다. 그리고 이를 %rbx에도 저장합니다.

 

<+4> : string_length도 phase_1에서 분석했었듯이 레지스터 %rdi와 %rdx로 이루어져 그 간격을 %rax에 저장해서 반환하는 함수입니다.

 

<+9> : 그 반환값을 6과 비교합니다.

 

<+12> : 반환값, 즉 문자열의 길이가 6이 아니라면 <+63>으로 점프해서 폭탄이 터지므로, 입력하는 문자열의 길이는 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> : %rax에 %rbx가 가지고 있는 포인터를 복사합니다.

 

<+17> : %rdi에 0x6(%rbx), 즉 6번째 문자를 저장합니다.

 

<+21> : %ecx에 0을 저장합니다.

 

<+26> : 배열을 저장하는것으로 추측됩니다.

 

<+33> : (%rax)는 문자열의 첫번째 문자입니다. 이를 %edx에 저장합니다.

 

<+36> : 첫번째 문자를 15와 &연산합니다. 영어 문자가 대소문자든 숫자문자든 아무상관없이 정수 1부터 26까지 순서대로 대응되도록 해줍니다.

 

 

a b c d e f g h i j k l
A B C D E F G H I J K L
'1' '2' '3' '4' '5' '6' '7' '8' '9'      
1 2 3 4 5 6 7 8 9 10 11 12

 

m n o p q r s t u v w x y z
M N O P Q R S T U V W X Y Z
13 14 15 16 17 18 19 20 21 22 23 24 25 26

 

 


<+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> : %rsi에 정보를 알기 힘든 배열을 저장했었습니다. 그리고 이 <+39>의 operand에서 %rsi의 배열을 4바이트를 단위로 접근함을 알 수 있습니다. 즉 %rsi는 4바이트 int형 정수배열이 저장되었다는 관점으로 볼 수 있습니다.

 

(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

 

때문에, 4바이트 단위로 끊어서 메모리에 저장된 값을 출력하면 다음과 같습니다.

 

30개를 출력해보았더니, 16개까지는 인위적으로 값을 집어넣은듯한 값이 있고 그 이후로는 쓰레기 값이 있기때문에 우선 사용할것같은 16개까지만 적었습니다. 

 

 

그리고 이 배열의 입력한 첫번째 문자에서 15와 &연산한 값만큼 한칸씩 이동해서 나온 element를 %ecx에 저장합니다.

저는 "abcdef"를 입력했다고 가정했기 때문에, 첫번째 element인 2를 저장합니다.

 

<+42> : %rax에 1을 더합니다.

 

<+46> :  %rax와 %rdi를 비교합니다.

 

<+49> : %rax와 %rdi가 다르면 <+33>으로 점프합니다.

 

<+51> : %rax와 %rdi가 같으면 58과 %ecx를 비교합니다.

 

<+54> : 58이면 <+61>로 점프해서 문제가 해결됩니다.

 


<결론>

상황을 관찰해보면,

%rax는 배열을 첫번째 요소에서 마지막 요소까지 순회합니다.

순회하면서, 각 입력한 문자가 위의 정수 배열의 인덱스 역할을 하며 인덱스가 가리키는 정수를 %ecx에 누적합니다.

 

그리고 마지막 요소의 순회까지 끝나면 R[%ecx]가 58이 되어야 합니다.

즉, 우리가 입력해야하는 문자열은 각 문자가 1부터 9로 대응되며 그 합이 58이 되는 문자열이고 답은 너무나도 많습니다.

 

몇가지 예시만 들어보면,

우선 58을 위의 배열에 있는 숫자 중에서 6개 숫자의 합으로 분리해야하므로,

10 + 10 + 10 + 16 + 9 + 3 으로 분리할 수 있습니다.

각 숫자의 인덱스는 1 1 1 5 6 7 이고, 1 1 1 5 6 7로 대응되는 문자들은 아래를 포함하여 너무나 많은 조합이 가능합니다.

aaaefg, 111567, AAAEFG, a1156G

 

'CS:APP' 카테고리의 다른 글

[CS:APP 2.2] Binary Number Encoding  (0) 2023.10.26
[CS:APP] BombLab Phase6 해설  (0) 2023.10.20
[CS:APP] BombLab Phase4 해설  (0) 2023.10.20
[CS:APP] BombLab Phase3 해설  (0) 2023.10.20
[CS:APP] BombLab Phase2 해설  (0) 2023.10.19

+ Recent posts