Dynamic Linking : 재배치 + 심볼 해석
함수 호출 시 함수 이름만 존재하는 PLT(Procedure Linkage Table)을 참조하면 해당 함수의 실제 주소가 들어 있는 GOT(Global Offset Table)로 연결되어 해당 함수 주소를 찾아가게 된다.
- 그러나 동적 링킹 시에 GOT는 dynamic linker(
ld.so) 호출 주소가 저장되어 있고, 해당 함수가 처음 호출될 때ld.so가 실제 함수 주소를 찾아서 GOT 값을 업데이트한다. → Lazy Binding
재배치
PLT와 GOT

PLT(Procedure Linkage Table) : .plt 섹션
- 참조할 외부 함수들의 이름을 가지고 있음
- add, sum, printf, … 등 함수 이름을 가진 table
- 다른 외부 라이브러리에 위치한 함수를 호출할 경우 PLT를 사용한다.
GOT(Global Offset Table) : .got.plt 섹션
- PLT에 있는 함수들의 실제 주소를 가지고 있음
- PLT가 어떤 외부 함수를 호출할 때 이 GOT를 참조해서 해당 주소로 점프한다.
※ .got 섹션은 재배치할 전역변수들의 주소들로 load-time에 결정된다.
Lazy Binding
- 초기에 GOT 엔트리는 dynamic linker 호출을 위한 PLT 코드를 가리키고 있음
- 호출된 dynamic linker 내의
_dl_runtime_reslove()를 통하여 실제 함수 주소를 찾아 GOT 값을 업데이트 한다.(Lazy Binding) - 이후 동일 함수에 대한 호출에 대해서는 dynamic linker 호출 없이 GOT 값을 통해 실제 함수 주소를 얻게 된다.

Dynamic Linking 실습

sum-d실행파일은add를 두번 호출한다.- add 함수를 실행하기 위해 PLT에 저장되어 있는 주소로 jump한다.

add를 호출하는 라인에 브레이크 포인트를 걸고 실행한다.- 첫번째
add를 실행하기 직전 상태가 된다.
- 첫번째
- 해당 지점에서 disassemble 했을 때
0x804a010에 들어 있는 값으로 jump한다.0x804a010에는0x804845e가 들어 있다. → PC는0x804845e로 jump한다.
push $0x20실행0x08048408로 jump한다.0x08048408에는 동적 링커(Dynamic Linker, ld.so)의 이름이 위치하고 있다.
0x8048408에서 다시 disassemble를 했을 때 4.pushl 0x8049ff8실행 - $이 없으니 해당 위치에 있는 값인0x0012d918를 stack에 넣는다. 5.0x8049ffc에 위치한 값인0x00122a80으로 jump한다. - 메모리에 적재된 실제 동적 링커(ld.so) 주소가 위치하고 있다.
0x00122a80으로 jump하면_dl_runtime_resolve가 실행된다. 6._dl_fixup(실제 함수 주소를 찾고 GOT를 업데이트하는 함수)가 실행된다.
- 라이브러리에 있는
add에 브레이크 포인트를 걸고 실행한다. - 메모리 내 add 함수의 실제 위치는
0x0012f41c이다.
finish실행 → (현재 함수의 실행을 끝내고, 해당 함수가 return하는 시점까지 실행한 뒤 멈춘다.)
-
두번째
add함수를 호출한다.
-
이전과 동일하게
0x804a010에 저장된 값으로 점프한다.- 해당 값에는
0x0012f41c, 라이브러리 내 실제 add 함수가 위치한 곳이라는 것을 확인할 수 있다.
- 해당 값에는
심볼 해석
.dynsym, .dynstr, .rel.plt

Dynamic Symbol Table: .dynsym 섹션
- 심볼 이름, offset, 크기, 바인딩 정보 등이 저장되어 있다.(add, sub, printf 같은 함수 이름이 몇번째 항목인지, 해당 함수의 라이브러리 내부에서 offset(상대 주소)는 얼마인지)
Dynamic String Table: .dynstr 섹션
.dynsym의 항목이 가리키는 문자열 데이터(심볼 이름)이 저장되어 있다.
- 심볼 이름 : Dynamic String Table(
dynstr)의 인덱스 - 1 엔트리 크기 == 16 바이트
- 심볼 이름 : Dynamic String Table(
Relocation for PLT : .rel.plt 섹션
- PLT를 사용하는 함수 호출을 위해 재배치 정보가 있다.
- 어떤 GOT 슬롯을 수정해야 하는지, 어떤
dynsym에서 찾아야 하는지 알려준다.
- 어떤 GOT 슬롯을 수정해야 하는지, 어떤
sum-d의 재배치 정보

- add함수의 실제 주소는
0x0804a010이다. - Info의 상위 3바이트는
.dynsym에서 몇번째 심볼인지를 나타낸다. - Info의 하위 1바이트는 Relocation 타입으로 어떤 방식으로 재배치 할지를 나타낸다.
sum-d와 libcalc.so의 심볼 정보

-
sum-d(실행파일)- 내부에서 add()를 호출하지만 주소는 모르는 상태이다.
- dynamic symbol table의 add 함수가 UND(Undefined) 상태 이다.
- 내부에서 add()를 호출하지만 주소는 모르는 상태이다.
-
libcalc.so(내가 만든 동적 라이브러리)- add함수는 0x0000041c에 위치하고 있다.(상대 위치)
정리
sum-d는 실행파일이고, 내부에서add()를 호출하지만 주소는 모른다.- 그래서
.dynsym심볼 테이블에 UND (undefined) 상태로 존재하고 있다.
- 그래서
sum-d를 실행하던 중, 동적 링커(ld.so)가 이 심볼을 해석(resolution)한다.- 해석 과정에서
libcalc.so에 있는add()를 찾고, 그 오프셋 값이0x0000041c임을 확인한다.- 공유 라이브러리의
.dynsym에 strcmp해서 일치하는 심볼이 없는 경우 다른 라이브러리로 이동한다.
- 공유 라이브러리의
- 메모리에서 로딩된 실제 주소(Base Address,
0x0012f000)와 해당 오프셋을 더해서 최종 주소0x0012f41c를 계산한다.
출처
- 숭실대학교 이정현 교수님 시스템 보안