security/포너블 - pwnable.kr

pwnable.kr - [Toddler's Bottle] leg

민사민서 2023. 2. 5. 22:30
#include <stdio.h>
#include <fcntl.h>
int key1(){
   asm("mov r3, pc\n");
}
int key2(){
   asm(
   "push  {r6}\n"
   "add   r6, pc, $1\n"
   "bx    r6\n"
   ".code   16\n"
   "mov   r3, pc\n"
   "add   r3, $0x4\n"
   "push  {r3}\n"
   "pop   {pc}\n"
   ".code 32\n"
   "pop   {r6}\n"
   );
}
int key3(){
   asm("mov r3, lr\n");
}
int main(){
   int key=0;
   printf("Daddy has very strong arm! : ");
   scanf("%d", &key);
   if( (key1()+key2()+key3()) == key ){
      printf("Congratz!\n");
      int fd = open("flag", O_RDONLY);
      char buf[100];
      int r = read(fd, buf, 100);
      write(0, buf, r);
   }
   else{
      printf("I have strong leg :P\n");
   }
   return 0;
}

 

asm 명령어 분석해보자
<서브루틴 들어가기전>
bl 0x8cd4 <key1> ; <key1>으로 분기, R14(=lr)에 복귀주소(현재+4) 저장
<서브루틴 안>
push {r11} ; r11(=sfp) 저장, 이전 sfp 백업 
add r11, sp, #0 ; r11에 sp(=r13,스택포인터)+0 값 저장
--------
; r0(=eax)에 함수의 리턴값 저장
-------- 
sub sp, r11, #0 ; 스택프레임 정리
pop {r11} ; sfp 복구
bx lr ; lr(=R14)에 저장된 값(복귀주소)으로 분기 
<본문> 
; pc(=r15)의 특이점-다음다음 실행할 명령어 주소 담고있음
; ARM mode에선 현재주소+0x8, Thumb mode에선 현재주소+0x4
; why? arm은 fetch(명령어가져옴)->decode->execute 단계 거침
; 특정 명령어 실행되기 위해선 cycle 두번 돌아야함(2words, 8B)
; bx라는 명령어에 점프할 주소를 주게 되는데, 
; 해당 주소의 LSB가 1이면 Thumb로, 0이면 ARM으로 간다 
; Thumb mode는 16bit instruction set을 가지고있다(한번에 16bit 처리)
; for any 3-operand ARM instructions that has a 2-operand Thumb equivalent, specifying the destination register is optional - if omitted it will default to the first source register*.
; 위 설명에 따라 adds r3, #4는 add r3,r3,#4와 같겠네!


<key1>
mov r3, pc; pc의 값(0x00008cdc+0x4*2=0x00008ce4) r3에 저장
mov r0, r3; 리턴값은 0x8ce4겠네요 
<key3>
mov r3, lr; lr 값은 복귀주소(0x00008d80)
mov r0, r3; lr 값이 r3를 거쳐 리턴값으로 들어가네요 (0x8d80)
<key2>
push   {r6}
add    r6, pc, #1 ; pc(0x00008cfc+0x8=0x00008d04)+1 값이 r6로 
bx r6 ; r6(0x8d04+1) 값으로 분기, LSB=1이므로 thumb 모드 진입?
mov    r3, pc ; 이쪽으로 분기, r3=0x00008d04+0x2*2=0x00008d08
adds   r3, #4 ; r3=0x8d0c
push   {r3}
pop    {pc}
pop    {r6}
mov    r0, r3 ; 리턴값은 0x8d0c

key1()+key2()+key3() = 0x1a770 = 108400