Hacking/System technique / / 2016. 5. 24. 21:16

PLT, GOT, Dynamic Linker


Dynamic Link(동적 링크) 로 컴파일 되었을때의 컴파일을 동적 컴파일 이라고 한다.


동적컴파일과 정적컴파일(static complie)의 차이는 공유라이브러리의 사용에 있다.


논문을 썼는데 파일 이미지를 빽업 안해뒀다..


<*참고 : 컴파일 과정 : http://flyingwolf.co.kr/110175745477>



<그림1. 정적 컴파일 된 파일>


<그림2. 동적 컴파일 된 파일>


동적컴파일이 된 파일은 PLT와 GOT를 가지게 되는데 <그림1> <그림2>을 보게되면 정적 컴파일된 파일엔 <puts>라고 되어있고, 동적 컴파일 된 파일엔 <puts@plt>라고 되어 있을 것이다. 이것이 PLT, GOT라는 것인데.


동적 컴파일된 파일에서 함수는 처음 호출될 때 PLT-GOT-PLT순으로 호출이 되고 두번 째 호출이 될때는 처음 GOT의 주소를 기억 하고 바로 호출이된다.


printf("a\n");        // PLT - GOT - PLT

printf("b\n");        //  바로 호출


함수가 호출될때의 과정을 asm으로 까서 보면 함수가 호출되는 부분에 call 명령으로 PLT주소를 호출한다. PLT주소로 들어가보면 GOT를 호출하게 되고, _dl_runtime_resolve_라는 링커로 이어져 있는데 그 과정을 밑에서 설명할 것이다.


PLT는 Proceidure Linkage Table의 약자로 GOT를 가르키는 주소를 담은 테이블이다.


GOT는 Global offset Table의 약자로 실제 라이브러리가 실행될 주소를 가진 테이블이다. 


여기서 의문이 들 것이다. 왜 굳이 PLT라는 곳을 거쳐서 GOT를 호출하고 GOT에서 실제 함수를 호출하는가?


그 이뉴는 PLT는 각각의 프로시저들을 연결해 주는 테이블이다. 프로시저들은 끼리끼리 연결을 할 때마다 연결 메커니즘이 다르게 되는데


만약 같은파일 안의 프로시저들끼리 호출을 한다면 직접적으로 바로 호출이 가능하겠지만 다른 파일에서 구현된 프로시저들을 연결 해 주려면 PLT를 사용해야한다. 즉 PLT를 사용하는 이유는 파일마다의 프로시저들을 통합해서 링크하려고 사용하는 것이다.


이유는 모든 프로그램이 호출하는 함수(라이브러리)들을 나열해 주기 때문이다!


실제로 디버깅 하며 자세히 알아보자.


test코드를 작성 하였다.

<그림3. test.c>


동적으로 컴파일 후 gcc -o test test.c(동적으로 컴파일은 아무옵션없이 컴파일 하게되면 동적으로 컴파일된다. 정적컴파일 하려면 -static옵션을 줘야함)


gdb로 어셈을 본다.


<그림4. test.asm>


*tips. main함수를 보면 분명 printf 함수를 사용하였는데 asm에서는 puts함수의 plt를 호출하고 있다. 이 이유는 printf, puts 둘다 출력함수이지만 puts는 %d, %s같은 서식문자열을 받지 못하고 printf는 서식문자열을 받을 수 있다. 하지만 printf함수를 호출하는데도 서식문자열을 사용하지 않게 되면 <그림4>와 같이 printf함수대신 puts함수를 부르게 된다.


puts@plt가 보인다 call 0x80482f0을 호출한다. 0x80482f0을 확인해본다.


<그림5. 0x80482f0>



<puts@plt> 에서 0x804a00c부분으로 jmp한다 이부분이 got가 있는 주소에 해당하는 부분이다. Dynamic Linker가 한번도 호출되지 않았을 때에는 <puts@plt+6>으로 넘어간다. 이 부분으로 부터 Dynamic linker에 진입하게 되는데


<puts@plt+6> 에서는 어떤 값(0)을 push 한다. 이부분은 reloc_offset이라는 값인데 여기서 자세하게 다루지 않겠다.


<puts@plt+11> 에서는 또 다시 0x80482e0으로 jmp하게 되는데, 이 부분을 살펴보자.


<그림6. 0x80482e0>


0x80482e0에서 처음 으로 push 하는 값은 link_map 구조체의 주소이다.(자세히 다루지 않겠다.) 이 부분은 GOT+8부분이다.


그리고 0x80482e6에서 0x804a008(GOT+4)부분으로 점프한다. 0x804a008에는 _dl_runtime_resolve 함수 주소가 들어있다.


x/x 0x804a008으로 _dl_runtime_resolve 주소를 구한뒤 _dl_runtime_resolve에 들어가본다.



<그림7. _dl_runtime_resolve>


_dl_runtime_resolve 함수 안에서 _dl_fixup 함수가 호출된다.



<그림8. _dl_runtime_resolve 에서 _dl_fixup 호출>


_dl_fixup 함수 에선 _dl_lookup_symbol_x 함수가 호출된다.



<그림9. _dl_fixup 에서 _dl_lookup_symbol_x 호출>



<그림10. _dl_lookup_symbol_x>




최종적으로 함수의 흐름은


호출 되었을때 func@plt > func@got > func@plt+6 > dl_runtime_resolve() > dl_fixup() > _dl_lookup_symbol_x() > _dl_fixup() > func() 으로 호출이 되는 것이다.


자세한 함수설명은 ㄴㄴ





'Hacking > System technique' 카테고리의 다른 글

Memory Leak & Stack Canary  (0) 2016.03.09
Memory Leak (메모리 릭) - recv , strncpy 함수등  (0) 2016.03.04
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유