둘둘리둘둘리둘둘리둘둘리둘둘리둘

.plt .got 동작과정 본문

Linux/Reversing

.plt .got 동작과정

dool2ly 2015. 8. 22. 00:37

#include <stdio.h>


int main(){

        printf("hello\n");

        printf("rekcah\n");

        return 0;

}


위의 소스를 예로 들어 설명함.


먼저 간략하게 설명하자면 main에서 printf 호출시 printf@plt를 호출하고 plt가 got에서 함수의 주소를 찾고 그 함수가 없으면 _dl_runtime_resolve를 통해서 함수를 찾는다.(_dl_runtime_resolve에서 got에 함수 주소를 입력해 이후로는 함수를 쉽게 찾을 수 있도록 한다)



소스 코드를 보면 <main+36>과 <main+52>에서 호출하는 0x080482b0 <_init+56>이 printf임을 짐작할 수 있다.  main+36부터 따라가 보자.







_init을 disassamble하고 <main+36>에서 호출한 <_init+56>부터 보면

ds:0x08049590으로 jump한다 그럼 ds:0x08049590을 보자.






(gdb) x/x 0x08049590

0x8049590 <_GLOBAL_OFFSET_TABLE_+16>:   0x080482b6


0x080482b6이고.. 0x080482b6은 <_init+62>d이다 .. 위에 보이듯이 0x08049590은 global offset table 즉 got영역이다.  앞서 설명했듯이 함수 호출순서가 plt -> got -> printf 니까 got이전에서 참조한 0x080482b0이 plt영역이다.



그런데 plt에서 got영역을 참조하고 다시 plt영역으로 돌아왔다(정확하게는 init+56 -> got -> init+62) 이는 got에서 printf 주소를 찾지 못했음을 뜻하고 다시 init+56을 따라가보면 0x08을 push하고 init+24로 돌아가 ds:0x08049584(GOT+4)를 push하고 ds:0x08049588(GOT+8:_dl_runtime_resolve)로 jump한다.. 


그 후 _dl_runtime_resolve를 수행하며 아래와 같이 got+16에 실제 printf의 주소를 입력하고 printf를 수행한다.

(gdb) x/x 0x08049590

0x8049590 <_GLOBAL_OFFSET_TABLE_+16>:   0x0075e660

(gdb) x/20i 0x0075e660

0x75e660 <printf>:      push   ebp

0x75e661 <printf+1>:    mov    ebp,esp

0x75e663 <printf+3>:    lea    eax,[ebp+12]

0x75e666 <printf+6>:    push   ebx

0x75e667 <printf+7>:    sub    esp,0xc

0x75e66a <printf+10>:   mov    ecx,DWORD PTR [ebp+8]

0x75e66d <printf+13>:   call   0x730c71 <__i686.get_pc_thunk.bx>

0x75e672 <printf+18>:   add    ebx,0xe0982

0x75e678 <printf+24>:   mov    DWORD PTR [esp+8],eax

0x75e67c <printf+28>:   mov    edx,DWORD PTR [ebx-416]

0x75e682 <printf+34>:   mov    DWORD PTR [esp+4],ecx

0x75e686 <printf+38>:   mov    eax,DWORD PTR [edx]

0x75e688 <printf+40>:   mov    DWORD PTR [esp],eax

0x75e68b <printf+43>:   call   0x755f80 <vfprintf>

0x75e690 <printf+48>:   add    esp,0xc

0x75e693 <printf+51>:   pop    ebx

0x75e694 <printf+52>:   pop    ebp

0x75e695 <printf+53>:   ret



이 다음 printf를 호출할 경우 아래와 같이 plt에서 got+16이 가지고있는 printf의 실제 주소를 바로 호출할 수 있게 된다,

(gdb) b *main+52

Breakpoint 2 at 0x804839c

(gdb) c

Continuing.


Breakpoint 2, 0x0804839c in main ()

(gdb) si

0x080482b0 in ?? ()

(gdb) x/3i 0x080482b0
0x80482b0 <_init+56>:   jmp    ds:0x8049590
0x80482b6 <_init+62>:   push   0x8
0x80482bb <_init+67>:   jmp    0x8048290 <_init+24>
(gdb) x *0x08049590
0x75e660 <printf>:      push   ebp


'Linux > Reversing' 카테고리의 다른 글

gdb-peda 설치  (0) 2016.02.28
IDA를 이용한 리눅스 원격 디버깅  (0) 2015.12.30
ROPeMe (ROP Exploit Made Easy)  (0) 2015.11.17
64비트 elf 인자전달방식  (0) 2015.10.07
칼리 리눅스에 버추얼박스 게스트 확장 설치  (0) 2015.10.07
Comments