해설
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 |