Phase 5
의 경우 유형이 3개인데, 이 포스트에서는 그 중 하나만을 다룬다.
이 유형에서의 핵심은 입력된 문자열을 특정 규칙에 따라 정수 배열의 인덱스로 변환하고, 그 값들을 합산하여 미리 정해진 값과 비교하는 로직을 파악하는 것이다.
<+4>
~ <+12>
: string_length
함수를 호출하여 %rbx
에 저장된 입력된 문자열의 길이가 정확히 6인지 검사한다. 길이가 6이 아니면 폭탄이 터진다. abcdef
를 예로 입력해보면 $eax
에 string_length
함수의 결과값으로 문자열 길이인 6이 저장되고, %rbx
에 문자열이 저장됨을 확인할 수 있다. 문자열 길이 검사를 통과하면, 루프를 실행하기 위한 사전 설정 작업 후 <+33>
부터 본격적인 반복문이 시작된다.
<+14> mov %rbx, %rax
: %rax
에 사용자 입력 문자열의 시작 주소(%rbx
)를 저장한다.<+17> lea 0x6(%rbx), %rdi
: %rdi
에 문자열의 끝 주소(시작 주소 + 6)를 저장한다.<+21> mov $0x0, %ecx
: %ecx
레지스터를 0
으로 초기화한다.추후 분석 후에 확인되는, 반목문에서 각 레지스터의 용도는 다음과 같다.
%rax
: 루프를 돌며 입력 문자를 한 글자씩 이동%rdi
: 루프 종료 조건 판별%ecx
: 합계 누적<+26> lea 0x1664(%rip), %rsi
: %rsi
에 0x555555402c20
주소를 로드한다. 이 주소는 어떠한 정수 배열의 시작 주소이다. <+33> movzbl (%rax), %edx
: %rax
(초기 기준 입력한 문자열의 시작 주소)가 가리키는 현재 문자(1바이트)를 %edx
레지스터(4바이트)로 zeroExtend하여 읽어온다.<+36> and $0xf, %edx
: AND 연산을 통해 하위 4비트만 남기고 나머지는 모두 0으로 만든다.<+39> add (%rsi, %rdx, 4), %ecx
: %rsi
(배열 시작 주소)에 %rdx
x 4 x (인덱스( %rdx
값) x 데이터 크기)를 더하여 배열에서 값을 찾아낸 후, 그 값을 %ecx
(누적 합계)에 더한다.계속해서 나아가본다.
<+42> add $0x1, %rax
: 문자열 포인터 %rax
를 1 증가시켜 다음 문자를 가리키게 한다.<+46> cmp %rdi, %rax
: 현재 문자열 포인터(%rax
)와 문자열의 끝 주소(%rdi
)를 비교한다.<+49> jne <phase_5+33>
: 두 주소가 같지 않으면(아직 처리할 문자가 남았으면) 루프의 시작점인 <+33>
으로 다시 점프한다.<+51>
~ <+56>
최종 누적 합계(%ecx
)가 0x38
(10진수 56)과 같은지 비교하고, 같으면 폭탄이 해체되어 페이즈를 마무리한다.앞선 어셈블리 코드 분석을 통해 Phase 5
의 해체 조건은 다음과 같이 요약할 수 있다.
입력한 6개 문자의 ASCII 값에서 각각 하위 4비트를 추출한다. 이 6개의 값을 인덱스로 삼아 미리 정의된 정수 배열에서 값을 꺼낸 뒤, 그 값들의 총합이 56이 되어야 한다.
이제 답을 도출해보자.
먼저, GDB로 확인한 정수 배열에서 6개의 숫자를 (중복을 허용하여) 골라 그 합이 56이 되는 조합을 찾아야 한다.
인덱스 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
값 | 2 | 10 | 6 | 1 | 12 | 16 | 9 | 3 | 4 | 7 | 14 | 5 | 11 | 8 | 15 | 13 |
16 + 16 + 16 + 4 + 2 + 2 = 56
을 선택한다.다음으로, 위에서 선택한 숫자 조합을 배열의 인덱스로 변환한다.
16
은 배열의 인덱스 5
에 있다. (3개 필요)4
는 배열의 인덱스 8
에 있다. (1개 필요)2
는 배열의 인덱스 0
에 있다. (2개 필요)마지막으로, 각 인덱스 값을 하위 4비트로 갖는 ASCII 문자 6개로 문자열을 조합한다. 문자의 순서는 상관없다.
0x5
(3개), 0x8
(1개), 0x0
(2개)5
(0x5): %(0x25), 5(0x35), E(0x45). U(0x55), e(0x65), u(0x75)
등8
(0x8): ( (0x28), 8(0x38), H(0x48), X(0x58), h(0x68), x(0x78)
등0
(0x0): 0(0x30), @(0x40), P(0x50),
(0x60), p(0x70)` 등이 문자들을 조합하여 6자리 문자열을 만들면 된다.
답:
EEEH@@
,HE%Ep@
등 위 조건을 만족하는 모든 6자리 문자열이 정답이 될 수 있다.