문서 내용 출처: 드림핵
컴퓨터 시스템에서, 프로그램들이 함수나, 변수를 공유해서 사용할 수 있게 한다. 자주 쓰이는 함수, 변수들의 저으이를 하나로 묶어서 미리 만들어 놓고 공유하는 것이다. libc는 우분투에 기본적으로 탑재된 라이브러리다.
Link(링크) 는 많은 프로그래밍 언어에서 컴파일의 마지막 단계다.
리눅스에서 C코드는 전처리, 컴파일, 어셈블 과정을 거쳐 ELF 형식을 갖춘 오브젝트 파일(Object file) 로 번역된다. 이 오브젝트 파일은 형식을 갖추나, 라이브러리 내에 있을 함수들의 위치를 알 수 없다. 심볼과 관련된 정보를 찾아서 최종 실행 파일에 기록하는 것이 링크 과정에서 하는 일 중 하나다.
$ gcc -c hello-world.c -o hello-world.o
$ readelf -s hello-world.o | grep puts
표준 라이브러리 경로는 다음과 같다.
$ ld --verbose | grep SEARCH_DIR | tr -s ' ;' '\n'
SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu")
SEARCH_DIR("=/lib/x86_64-linux-gnu")
SEARCH_DIR("=/usr/lib/x86_64-linux-gnu")
SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64")
SEARCH_DIR("=/usr/local/lib64")
SEARCH_DIR("=/lib64")
SEARCH_DIR("=/usr/lib64")
SEARCH_DIR("=/usr/local/lib")
SEARCH_DIR("=/lib")
SEARCH_DIR("=/usr/lib")
SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64")
SEARCH_DIR("=/usr/x86_64-linux-gnu/lib")
라이브러리는 링크되는 방식에 따라 두 가지 방식으로 나뉘는데, 하나는 동적 링크, 나머지 하나는 정적 링크라고 불린다.
다음과 같이 static과 dynamic을 생성한다.
$ gcc -o static hello-world.c -static
$ gcc -o dynamic hello-world.c -no-pie
static이 50배 가까이 많은 용량을 차지한다.$ ls -lh ./static ./dynamic
-rwxrwxr-x 1 dreamhack dreamhack 16K May 22 02:01 ./dynamic
-rwxrwxr-x 1 dreamhack dreamhack 880K May 22 02:01 ./static
static은 함수가 있는 주소를 직접 호출한다. 반면 dynamic에서는 함수의 plt 주소를 호출한다. 왜냐하면 동적 링크된 바이너리는 함수의 주소를 라이브러리에서 "찾아야"한다. plt가 이 과정에서 사용되는 테이블이다.PLT(Procedure Linkage Table) 와 GOT(Global Offset Table) 은 라이브러리에서 동적 링크된 심볼의 주소를 찾을 때 사용하는 테이블이다.
라이브러리가 ASLR에 의해 임의 주소에 매핑되고, 라이브러리 함수를 호출하면 함수 이름을 통해 라이브러리의 심볼을 탐색하고, 해당 함수의 정의를 발견하면 그 주소로 실행 흐름을 옮긴다. 이를 runtime resolve 라고 한다.
ELF 형식에선 효율을 높이기 위해 PLT에서 탐색을 거친 심볼은 GOT에 저장한다. 이를 통해 다시 호출할 때의 시간을 절약할 수 있다.
놀랍게도 PLT에서 GOT를 참조하여 실행흐름을 옮길 때, GOT 값을 검증하지 않는다. 따라서 어떤 함수의 GOT 엔트리에 저장된 값을 공격자가 임의로 변경하는 경우, 해당 함수가 호출 될 때, 공격자가 원하는 코드가 실행될 수 있다.