음.. 윈도우 PE파일에서는 프로그램이 실행되면 Import table과 Export table을 사용해 프로그램에서 사용할 라이브러리 주소를 가져오지요. dll 같은 경우는 로드될때 base address가 바뀔수도 있기 때문에 PE Loader가 프로그램이 실행되면 특정 메모리에 함수들의 주소를 다 쓰지요.
그러면 대표적인 리눅스 실행 파일인 ELF 파일은 라이브러리 함수 주소를 어떤식으로 가져와 사용할까요?
테스트를 진행할 소스코드입니다. 단순한 덧셈 프로그램이지요.
-static 옵션을 사용하지 않고 컴파일 후 진행하도록 하겠습니다.
컴파일이 끝났으면 readelf -S 를 사용해 섹션 헤더를 봐보겠습니다.
주목해야할 섹션은 .plt 섹션과 .got.plt 섹션
.plt 섹션은 Procedure Linkable Table 의 약자로서 말그대로 함수들 링크가 가능한 테이블로 프로그램이 호출하는 모든 함수가 나열되어 있습니다.
.got.plt는 Global Offset Table로서 전역 offset을 가지는 테이블 이랍니다.
한번 쭉 프로그램을 실행하면서 따라가보죠.
main함수 첫 부분을 보면 printf 함수를 호출하고 있습니다.
그러면 해당 주소를 가보죠
printf 실제 링크 주소로 오는 것이 아닌 plt 라는 영역으로 들어오게 됩니다.
어딘가 점프를 또 하네요. 따라가보겠습니다.
이번엔 got 영역으로 들어오는군요. 원래는 저 부분에 printf의 실질적인 라이브러리 주소가 있어야합니다.
하지만 지금은 첫번째로 printf가 호출되는 상황이므로 아직 printf의 라이브러리 주소를 구해놓지 않은 상황입니다.
잘 보시면 0x08048346 주소는 plt 영역의 <printf@plt+6> 주소가 같은 것을 확인할 수 있습니다.
즉, 현재는 jmp *0x804a000을 수행하면 <printf@plt+6> 위치로 오게 됨을 알 수 있습니다.
그리고 나서 jmp 0x8048330을 수행하는데 저 부분은 dl_runtime_resolve 함수를 수행하는 부분인데요.
실제 printf의 라이브러리 주소를 got에 저장하고 printf의 실제 주소로 점프를 한다고 합니다.
윈도우 PE파일과 다르게 호출되는 함수 주소를 한번에 다 올리는 것이 아닌 프로그램 실행 시 호출될 때마다 라이브러리 주소를 got에 넣는다고 하네요. 그 다음번 printf를 호출할 땐 이미 앞서 got에 printf의 라이브러리 주소를 가져왔으므로 dl_runtime_resolve 함수를 수행하지 않고 바로 printf 를 호출할 수 있습니다.
한번 main 함수의 printf 다음 주소에 bp를 걸고 수행 후 got를 확인해 보겠습니다.
아까와는 값이 다르게 있다는 것을 알 수 있겠네요.
결론은 FSB 기법을 활용해 got overwrite를 해서 쉘을 따는 방법도 널리널리 알려졌습니다.
아 그리고 -static 옵션을 사용해 컴파일을 하면 위 과정 따윈 다 ~~ 없습니다. 모든 함수들이 프로그램 내부로 들어오기 때문이죠. 대신 용량은~? 엄청 커지겠네요. 위 실행 파일을 대상으로 비교를 해보니 용량은 90배 가량 차이가 났습니다.
배보다 배꼽이 더큰 상황이 -0-;; 아무튼 리눅스도 잘해야합니다..... 윈도우도 잘 못하는 것이 별의별 걱정을 다하네요.
'My Study > Programming&Theory' 카테고리의 다른 글
PE 파일의 .reloc 섹션 (8) | 2012.06.06 |
---|---|
Visual Studio 에서 %n 서식 문자 사용하기 (0) | 2012.05.21 |
Calling Convention Process for AMD 64 Bit (4) | 2012.04.02 |
Windows rand() 랜덤 비율 (2) | 2012.02.14 |
ARM 명령어 공부 (6) | 2012.01.27 |