해설

Daddy told me I should study arm.
But I prefer to study my leg!

 

arm 어셈에 관한 문제이다. ssh로 접속하기 전 문제에서 주어진 leg.asm와 leg.c를 보면 arm 어셈으로 작성된 코드를 볼 수 있다. main 함수를 보면 사용자로부터 정수형 입력을 받아서 key1(), key2(), key3()의 리턴값을 더한 결과와 비교한 후, 같으면 플래그를 출력해주는 코드임을 알 수 있다.

 

key1 함수

Dump of assembler code for function key1:
   0x00008cd4 <+0>:	push	{r11}		; (str r11, [sp, #-4]!)
   0x00008cd8 <+4>:	add	r11, sp, #0
   0x00008cdc <+8>:	mov	r3, pc
   0x00008ce0 <+12>:	mov	r0, r3
   0x00008ce4 <+16>:	sub	sp, r11, #0
   0x00008ce8 <+20>:	pop	{r11}		; (ldr r11, [sp], #4)
   0x00008cec <+24>:	bx	lr

key1 함수는 key1<+8> 라인에서 pc 레지스터의 값을 반환하는 함수이다.

arm 아키텍처의 경우 pc 레지스터에는 fetch 단계에 있는 명령어의 주소가 담겨있다. 보통 프로세서의 명령어 처리 과정은 fetch->decode->execute 과정이 파이프라이닝되어 수행되기 때문에, 해당 key1<+8> 라인이 실행될 때 fetch 단계에 있는 명령어는 key1<+8>의 다음 다음 명령어인 key1<+16>일 것이다. 따라서 이때 pc 레지스터에는 0x8ce4 값이 들어가 있다.

 

key2 함수

Dump of assembler code for function key2:
   0x00008cf0 <+0>:	push	{r11}		; (str r11, [sp, #-4]!)
   0x00008cf4 <+4>:	add	r11, sp, #0
   0x00008cf8 <+8>:	push	{r6}		; (str r6, [sp, #-4]!)
   0x00008cfc <+12>:	add	r6, pc, #1
   0x00008d00 <+16>:	bx	r6
   0x00008d04 <+20>:	mov	r3, pc
   0x00008d06 <+22>:	adds	r3, #4
   0x00008d08 <+24>:	push	{r3}
   0x00008d0a <+26>:	pop	{pc}
   0x00008d0c <+28>:	pop	{r6}		; (ldr r6, [sp], #4)
   0x00008d10 <+32>:	mov	r0, r3
   0x00008d14 <+36>:	sub	sp, r11, #0
   0x00008d18 <+40>:	pop	{r11}		; (ldr r11, [sp], #4)
   0x00008d1c <+44>:	bx	lr

key2 함수는 약간 복잡한데, key2<+12> 라인에서 pc 레지스터 값에 1을 더한 뒤 r6 레지스터에 저장하고, 다음 라인에서 bx r6 명령어가 실행 된다. bx는 브랜치 명령어임과 동시에, arm의 저전력 모드인 thumb 모드로 cpu 모드를 전환하는 명령어이다. thumb 모드는 16비트 모드로, 16비트 명령어가 실행되는 구간이다. 이 때 pc 레지스터에 1을 더해주는 이유는, bx 명령어가 주소값의 홀짝을 보고 홀일 경우, arm 모드에서 thumb모드로, 짝일 경우, thumb모드에서 arm 모드로 전환해주기 때문이다. 따라서 이 때 thumb 모드로의 전환이 일어난다.

그 후에는 16비트 명령어들이 실행되는 것을 확인할 수 있고, 이 때 pc 레지스터 값 + 4를 r3 레지스터에 저장하고 최종적으로 반환됨을 확인할 수 있다. 이 경우에 pc 레지스터는 앞서 key1의 경우와 마찬가지로 해당 시점에서 다음 다음 명령어의 주소 값을 저장하고 있다. 따라서 이 때 pc 레지스터의 값은 0x8d08이다. 여기에 4를 더하면 최종적으로 반환되는 값은 0x8d0c이다.

 

key3 함수

Dump of assembler code for function key3:
   0x00008d20 <+0>:	push	{r11}		; (str r11, [sp, #-4]!)
   0x00008d24 <+4>:	add	r11, sp, #0
   0x00008d28 <+8>:	mov	r3, lr
   0x00008d2c <+12>:	mov	r0, r3
   0x00008d30 <+16>:	sub	sp, r11, #0
   0x00008d34 <+20>:	pop	{r11}		; (ldr r11, [sp], #4)
   0x00008d38 <+24>:	bx	lr

key3 함수는 lr 레지스터의 값을 반환하는 함수이다. lr 레지스터는 함수의 리턴 주소를 저장하고 있는 레지스터로, main 함수에서 key3가 호출되는 시점의 다음 명령어의 주소를 저장하고 있다. main 함수의 디스어셈을 확인하면 이 값은 0x8d80이다.

 

따라서 최종적으로 플래그를 얻기 위해 입력해야 하는 값은 0x8ce4 + 0x8d0c + 0x8d80 = 0x1a770 = 108400 이다.

'pwn' 카테고리의 다른 글

pwnable.kr - shellshock  (0) 2020.07.15
pwnable.kr - mistake  (0) 2020.07.15
pwnable.kr - input  (0) 2019.08.26
pwnable.kr - passcode  (0) 2019.08.22
pwnable.kr - random  (0) 2019.08.16

+ Recent posts