본문 바로가기

reversing/reversing

MIPS Disassemble

SMALL

MIPS 32bit 환경에서 gdb를 이용해서 분석 해보기.

root@debian-mipsel:/home/user# file hand

hand: ELF 32-bit LSB executable, MIPS, MIPS-II version 1, dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=0x76cbeddb5054f529eabb50bfdada135f44c0675e, with unknown capability 0xf41 = 0x756e6700, with unknown capability 0x70100 = 0x1040000, not stripped

root@debian-mipsel:/home/user# ./hand 

Add : 50

간단한 더하기 프로그램~


   0x00400640 <+0>: addiu sp,sp,-48

   0x00400644 <+4>: sw ra,44(sp)

   0x00400648 <+8>: sw s8,40(sp)

   0x0040064c <+12>: sw s0,36(sp)

   0x00400650 <+16>: move s8,sp

   0x00400654 <+20>: li v0,32

   0x00400658 <+24>: sw v0,24(s8)

   0x0040065c <+28>: li v0,48

   0x00400660 <+32>: sw v0,28(s8)

   0x00400664 <+36>: lui v0,0x40

   0x00400668 <+40>: addiu s0,v0,2176

   0x0040066c <+44>: lw a0,24(s8)

   0x00400670 <+48>: lw a1,28(s8)

   0x00400674 <+52>: jal 0x4006ac <add>

   0x00400678 <+56>: move at,at

   0x0040067c <+60>: move a0,s0

   0x00400680 <+64>: move a1,v0

   0x00400684 <+68>: jal 0x400500 <printf@plt>

   0x00400688 <+72>: move at,at

   0x0040068c <+76>: move v0,zero

   0x00400690 <+80>: move sp,s8

   0x00400694 <+84>: lw ra,44(sp)

   0x00400698 <+88>: lw s8,40(sp)

   0x0040069c <+92>: lw s0,36(sp)

   0x004006a0 <+96>: addiu sp,sp,48

   0x004006a4 <+100>: jr ra

   0x004006a8 <+104>: move at,at


전체 main 함수는 위와 같다.

그림을 그리면서 알아보려고 한다.

먼저 명령어 offset을 보면 명령어들이 4바이트로 정갈하다. RISC 방식인 것을 알 수있다.


   0x00400640 <+0>: addiu sp,sp,-48

   0x00400644 <+4>: sw ra,44(sp)

   0x00400648 <+8>: sw s8,40(sp)

   0x0040064c <+12>: sw s0,36(sp)


해당 부분을 보면 함수 프롤로그와 같다.

<+0> 부분을 보면 stack영역을 48 바이트 만큼 할당한다.   0x30 바이트

<+4> 부분에서는 $ra  == ret 인데,  main 함수를 호출하면서 저장한 ret 값을 넣는다.

<+8> 부분은 ebp 를 설정하는 부분이다. 전 함수의 ebp를 $s8 레지스터가 저장한다.

<+12> 부분은 특정 값인데.. 뭐지 싶다.. [중요한 것일 수도..]



   0x00400650 <+16>: move s8,sp

   0x00400654 <+20>: li v0,32

   0x00400658 <+24>: sw v0,24(s8)

   0x0040065c <+28>: li v0,48

   0x00400660 <+32>: sw v0,28(s8)

   0x00400664 <+36>: lui v0,0x40


<+16> 부분은 아까 확보한 스택 영역을 이제 $s8에 저장한다. 이를 통해서 지역변수에 접근 할 것이다.

<+20> $v0 레지스터에 32 상수 값을 넣는다.

<+24> 지역변수에 접근하는데 sp 에서 +24 된 부분의 4바이트에 $v0 값을 넣는다.

<+28> $v0 레지스터에 48 상수 값을 넣는다.

<+32> 지역 변수 접근, +28 부분, 4바이트 $v0 = 48 값을 넣음

<+36> $v0 = 0x40<<16 이렇게 값을 넣는다. 



   0x00400668 <+40>: addiu s0,v0,2176

   0x0040066c <+44>: lw a0,24(s8)

   0x00400670 <+48>: lw a1,28(s8)

   0x00400674 <+52>: jal 0x4006ac <add>


<+40> 부분에서는 더하기인데 아까 $v0 = 0x400000 + 2176 한 값을 s0에 넣는다. 아마 Data 영역의 값을 넣은 것 일거다.

     한번 찾아가보면...

(gdb) x/s 0x400000+2176

0x400880: "Add : %x\n"

위와 같이 문자열이 넣어져 있다.


<+44 , +48> $a0 와 $a1으로 해서 4까지 인자를 전달 받을 때 사용 한다. 아까 지역 변수에 넣어뒀던 값을 인자로 할당한다.

<+52> 이제 call 하는 부분인데 돌아올 주소[ret]를 $ra에 넣어주고, label로 뛴다.


   0x0040066c <+44>: lw a0,24(s8)

   0x00400670 <+48>: lw a1,28(s8)

   => 0x00400674 <+52>: jal 0x4006ac <add>


(gdb) info reg $ra

ra: 0x77e4e208


보면 아직 +52 부분이 시작 안된 상태에서의 reg $ra 값이다. 


(gdb) si

0x004006ac in add ()

(gdb) info reg $ra

ra: 0x40067c


해당 명령어를 실행 하고 나면, 0x4006ac 부분으로 점프 했고, ret값이    0x0040067c <+60>: move a0,s0 부분으로 바꼈다.

원래 처음 생각은 +56으로 바뀌지 않을까 생각했지만... mov at,at 가 의미 없는 값이여서 그냥 뛰는거 같다.

*추가 : mips의 경우 특징상 link와 관련된 명령어는 속도?를 위해서 pc pc+4 가 같이 수행이 된다.

           그래서 side effect를 피하기 위해서 mov at,at 의미 없는 코드를 pc+4에 집어 넣어서 수행된다.

   load to delay

Note also that the compiler adds a bunch of instructions who are completely useless to us (like move at, at who is used here as delay slot after a jump instruction).

functino <add>

    => 0x004006ac <+0>: addiu sp,sp,-24

   0x004006b0 <+4>: sw s8,20(sp)

   0x004006b4 <+8>: move s8,sp

   0x004006b8 <+12>: sw a0,24(s8)

   0x004006bc <+16>: sw a1,28(s8)

   0x004006c0 <+20>: sw zero,8(s8)

   0x004006c4 <+24>: lw v1,24(s8)

   0x004006c8 <+28>: lw v0,28(s8)

   0x004006cc <+32>: addu v0,v1,v0

   0x004006d0 <+36>: sw v0,8(s8)

   0x004006d4 <+40>: lw v0,8(s8)

   0x004006d8 <+44>: move sp,s8

   0x004006dc <+48>: lw s8,20(sp)

   0x004006e0 <+52>: addiu sp,sp,24

   0x004006e4 <+56>: jr ra

   0x004006e8 <+60>: move at,at


add 함수이다. stack을 할당하고.. main sp 보관하고, 셋팅한다.

<+12, +16> 부분에서 신기했던게, 지역변수를 안쓰긴 했지만.. 스택 할당한 밖 범위에 값을 저장했다. 전달 받은 인자들을

sfp+24에 arg1, sfp+28에 arg2 이렇게 인자를 저장했다.

아마 지역변수가 아닌걸 사용한다는 것을 알릴려고 하는거..? 

<+20>    여기는 지역변수를 0으로 초기화 하는 부분이다

<+24, 28>  부분은 아까 저장한 arg 값을 더하기 위해서 v1, v2에 저장한다.

<+32>       가져온 값을 더한다.

<+36, +40>        그리고 결과 값을 v0에 저장한다.

<+48>    main 함수의 sfp를 복구 시킨다.

<+52>    할당 했던 스택을 돌려주고

<+56>    ret로 돌아간다.


(gdb) si

0x0040067c in main ()


실행시키고 나면 위와같이 다시 main 함수 아까 저장했단 $ra 값으로 돌아왔다.

    => 0x0040067c <+60>: move a0,s0

   0x00400680 <+64>: move a1,v0

   0x00400684 <+68>: jal 0x400500 <printf@plt>


이제 보게 되면 다시 함수 호출을 하기위한 인자 셋팅 부분이다. 


<+60>    부분은 아까 data 영역의 0x400880:  "Add : %x\n" 부분이다.

<+64>    부분은 add 함수의 결과 값이 저장되어 있는 부분이다.

<+68>    그래서 보면 printf("Add : $x\n", $v0);가 된다.



   0x0040068c <+76>: move v0,zero

   0x00400690 <+80>: move sp,s8

   0x00400694 <+84>: lw ra,44(sp)

   0x00400698 <+88>: lw s8,40(sp)

   0x0040069c <+92>: lw s0,36(sp)

   0x004006a0 <+96>: addiu sp,sp,48

   0x004006a4 <+100>: jr ra


printf 이후에는 함수의 프롤로그 부분이다. 스택에 저장되어 있던 값을 복귀 시키고 할당을 풀고, 여기서 보면 <+92>: lw s0,36(sp)

왜 저장하고 복귀 시키는지 잘 모르겠다... 


추후에 공격을 하면서 찾으면 다시 정리해야겠다.



#include "stdio.h"

int add(int arg, int arg2);


int main()

{

int a = 0x20;

int b = 0x30;


printf("Add : %x\n",add(a,b));

return 0;


}


int add ( int arg, int arg2 )

{

int result = 0;


result = arg + arg2;


return result;

}



LIST

'reversing > reversing' 카테고리의 다른 글

inline function hooking  (0) 2017.05.12
[Project] 디버거 만들기 [Python]  (0) 2017.03.30
MIPS Instruction[Assembly]  (0) 2017.03.29
ARM Handray  (0) 2016.12.06
C++ 리버싱 연습  (0) 2016.11.29