2 minute read

결과 화면

Image





진행 과정

Image

그냥 슥 훑어봤을 때 jmp instruction이 많이 보이는 것을 보아 switch문이지 않을까… 하는 추측을 해볼 수 있겠다.

<+0> ~ <+18> 스택 확보, 함수 호출 준비 <+20> ~ <+35> %rsp에서 4byte 떨어진 주소를 %rcx(두 번째 입력)에 load하고 %rsp를 %rdx(첫 번째 입력)에 저장. 두 개의 값을 받을 듯. %rip 기준 0x1a95만큼 떨어진 주소(0x555555402e29)를 %rsi에 넣길래 뭘까 확인해봤더니 입력 포맷 문자열이었다. 바로 sscanf를 호출하여 입력을 받는다.

Image

<+40> ~ <+49> 값을 두 개 받으니 0x1과 %eax값을 compare하여 맞는 개수의 답이 들어왔는지 판단한다. 1 이하면 폭탄으로… 만약 두 개의 값을 잘 입력한 상태라면, 첫 번째 값((%rsp))이 7보다 작거나 같은지 판단하여 더 크면 폭탄으로 이동. 즉, 첫 번째 값은 7 이하임을 알 수 있다. 여기서 ja명령어 자체가 unsigned number를 comparing할 때 쓰는 것이므로, 음수를 의도하고 입력할 경우 맨 앞 비트가 부호가 아닌 수로 처리되어 이 조건에 걸릴 것이다. 따라서 음수 입력은 고려하지 않아도 되고, 입력 값의 범위를 0~7로 한정지을 수 있다.

<+55> ~ <+58> 첫 번째 값((%rsp))을 %eax에 load한다, 또 %rip에서 0x17a2만큼 떨어진 값을 %rdx에 load한다. 뭐가 저장되어있을지는 아직 잘 모르겠다.

<+65> movslq instruction은 테이블의 특정 항목을 읽어오는 명령어라고 한다. 또 sign extension으로 32bit 값을 64bit로 변환한다. 이 코드같은 경우는 %rdx주소에 %rax값을 4바이트 단위로 곱해 더한 주소에 있는 값을 읽는다. 그러니 방금 전 %rdx에 저장된 값은 테이블의 주소였을 것이다. %rdx 주소 기준으로 %rax에 들어있는 값을 사용하여 테이블의 요소를 참조하니 %rax가 index 역할을 하겠다고 생각할 수 있겠다. 테이블에 뭐가 저장되어있는지 볼까?

Image

4바이트 값 32개를 읽어봤다. Little Endian 방식이니 실제로 4바이트 값을 읽으면 %rax=0 -> 0xffffe86e, %rax=1 -> 0xffffe875 … 이런 식일 것. 전부 음수가 저장되어있다.

<+69> ~ <+72> %rax에 %rdx값을 더한다. 이제 %rax에는 점프해야 할 주소가 저장되어 있을 것이다. 다만 입력 값의 첫 요소가 0~7일 수 있으므로, 경우에 따라 다른 테이블 값을 읽어와 다른 값이 저장될 것이다. 입력 요소별 %rax값은 다음과 같다.

Image

입력값에 따라 점프할 주소가 다른데, 일단 0을 기준으로 해보겠다.

<+81> ~ <+86> 0x5555554013ce로 점프했다. %eax에 0x2ec(748)값을 저장한다. 또 점프한다.

<+93> ~ <+132> 뭔가 계속 add되고 subtract되고 있다… compare가 나오기 전까지 0x2a0 sub(672) 두 번, 0x36b(875) add 한 번이 일어나서 최종 %eax 값엔 748–672*2+875=279 값이 저장되어있을 것. 이때 현재 stack pointer에 있는 값(첫 번째 입력한 수)과 0x5를 비교하여 그보다 작아야 폭탄을 피할 수 있다. 이에 따라 처음 입력 값이 0~5로 제한된다.

<+134> 0은 5보다 작으니 다음으로 넘어오자. 두 번째 입력한 수(0x4(%rsp))와 %eax(결과가 들어있는 값)를 비교하여 같으면 <+145>로 이동하여 함수호출을 끝내는 작업을 수행하고, 아닌 경우 폭탄을 만난다. 현재 %eax=279이므로, 만약 첫 번째 수로 0을 입력했다면 두 번째 수는 279로 유일하게 정해진다. 다른 수에 대해서도 마찬가지이다. 입력 값에 따른 결과를 정리하면 다음과 같다.

Image



정답

Image



Leave a comment