티스토리 뷰

반응형

 

세 번째 phase를 살펴보자. 가보자 가보자!

 

phase_3 함수를 어셈블리어로 추출하여보자.

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

 

길이가 길어진 거 같은 느낌이 들지만, 천천히 해보자.

 

400f5b에서 sscanf 함수를 호출하고, 이후 %rax 레지스터와 상수 0x1을 비교한다. AT&T 기준이므로 만약 %rax가 1보다 클 경우, 400f6a로 점프하게 된다. 폭탄이 터지지 않으려면 jg가 true가 되어야 하고, 또한 phase_2에서 sscanf을 호출 한 뒤에 %rax에는 인수의 개수가 담긴다고 하였으므로, 최소한 두 개의 인수를 받는다는 것을 유추할 수 있다. 

 

따라서, 2개의 인수를 넣어보자. 테스트를 위하여 "100 200"를 넣어주었다.

 

이후 상수 0x7과 *[%rsp+0x8]을 비교하여, 오른쪽의 값이 더 크면 점프한다는 사실을 알 수 있다. 점프를 할 경우 폭탄이 터지기 때문에, 적어도 %rsp+0x8의 값은 7보다 작은 값을 지녀야 한다.

 

따라서, 일단 %rsp-8안에는 어떤 값이 들어가 있는지 확인하여보자. x 명령어를 이용하여 직접 확인해보면 다음과 같다.

(gdb) x/d $rsp+8
0x7fffffffdf28: 100

아하! %rsp+8에는 첫 번째 input 정수가 들어가 있다는 것을 추측할 수 있다! 그러면, %rsp+4에는? 스택에 값이 push되는 원리를 생각해보면 두 번째 input 정수가 들어가 있을 확률이 매우 크다. 직접 찍어보자!

(gdb) x/d $rsp+4
0x7fffffffdf24: 0

흠... 우리가 넣은 "200"이라는 정수 대신 다른 값이 들어가 있는 것을 확인할 수 있다. 따라서, 일단은 잠깐 넘기고, 계속하여 실행하여보자. 400f6f이 true일 경우 폭탄이 터지는 지점으로 jmp하므로, jg가 false가 나야한다. 즉, 첫 번째 input은 7보다 작은 숫자여야 한다.

 

그럼, 테스트를 위하여 "1 345"라는 값을 넣어보도록 하자.

 

우리가 분석하지 않은 지점부터 계속하여 실행하자. %rax 레지스터 안에 첫 번째 input 값을 옮긴 다음, jmpq를 통해 이상한 위치로 jmp한다. 도착해보니 400fb9에 도착하였고, %rax 안에 0x137 =  311이란 값이 들어간다. 이후, *(%rsp+0xc)와 %rax의 값이 비교하여, 같지 않을 경우 폭탄이 터지는 것을 볼 수 있다. 그럼, 먼저 *(%rsp+0xc)에 어떤 값이 들어가는지 부터 살펴보아야 한다.

(gdb) x/d $rsp+12
0x7fffffffdf2c: 200

아하! 우리가 넣은 두 번째 input은 *(%rsp+0xc)에 위치해 있는 것까지 확인하였다.

 

정리하자면, 첫 번째 input은 1과 비교, 두 번째 input은 %rax = 311과 비교하여, 하나라도 다르면 폭탄이 터진다고 할 수 있다.

 

답은 쉽게 구할 수 있었지만, 아직 완전한 이해를 하지 않았으므로 미심쩍은 부분을 파헤쳐보자.


위의 설명에서 뭉게면서 넘어간 부분은 해당 instruction이다.

  400f75:	ff 24 c5 70 24 40 00 	jmpq   *0x402470(,%rax,8)

분석해보면, (0x402470 + %rax * 8)의 메모리 주소로 점프하라는 내용이다. 그럼, 0x402470에서 앞뒤로 담긴 내용을 살펴보면 다음과 같다.

(gdb) x/16gx 0x402470
0x402470:       0x0000000000400f7c      0x0000000000400fb9
0x402480:       0x0000000000400f83      0x0000000000400f8a
0x402490:       0x0000000000400f91      0x0000000000400f98
0x4024a0:       0x0000000000400f9f      0x0000000000400fa6
0x4024b0 <array.3449>:  0x737265697564616d      0x6c796276746f666e
0x4024c0:       0x7420756f79206f53      0x756f79206b6e6968
0x4024d0:       0x6f7473206e616320      0x6f62206568742070
0x4024e0:       0x206874697720626d      0x202c632d6c727463

 

여러 개의 메모리 주소가 나와있다. 예를 들어, %rax에 1이 담겨있을 경우 0x402478의 값인 0x400fb9로 점프하고, %rax에 2가 담겨 있을 경우 0x402480의 값인 0x400f83으로 점프한다. 이러한 점프 테이블을 가지고 있는, 우리에게 친숙한 문법이 있지 않나?

 

그렇다. Phase 3는 switch문으로 구현되어 있는 함수라 할 수 있다. 우리에게 친숙한 코드로 변환하면 다음과 같이 변환할 수 있다.

unsigned int input1, input2;
unsigned int res;

sscanf("%d %d", &input1, &input2);

if (input1 > 7) {
   explode_bomb();
}
else {
    switch(input1) {
    	case 0:
            res = 0xcf; // 207
            break;
        case 1:
            res = 0x137; // 311
             break;
        case 2:
            res = 0x2c3; // 707
            break;
        case 3:
            res = 0x100; // 256
            break;
        case 4:
            res = 0x185; // 389
            break;
        case 5:
       	    res = 0xce; // 206
            break;
        case 6:
            res = 0x2aa; // 682
            break;
        case 7:
            res = 0x147; // 327
            break;
     }
     
     if (input2 == res) {
     	return;
     } else {
     	explode_bomb();
     }
}

답은 해당 input1과 input2를 잘 대응시켜 입력한다면, 총 7가지의 답이 존재할 수 있다.

 

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

 

아직까진 할만한가?

반응형
댓글
Total
Today
Yesterday
공지사항
최근에 올라온 글
최근에 달린 댓글
링크
«   2024/05   »
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
글 보관함