공유 라이브러리(PLT, GOT)

2024. 6. 17. 23:28· Hacking/Pwnable
목차
  1. 공유 라이브러리( PLT, GOT)
  2. 1. 라이브러리란?
  3. 2. 링크
  4. 3. PLT, GOT
  5. 4. GOT Overwrite
  6. 5. Reference

공유 라이브러리( PLT, GOT)


1. 라이브러리란?

1. 라이브러리(Library)

프로그램은 공통으로 사용하는 함수들이 있다

printf, scanf, strlen, memcpy, malloc 등 많은 함수들이 있다

이러한 함수들의 정의를 묶어 만든 파일(오브젝트 파일)을 라이브러리라고 한다

 

C의 표준 라이브러리인 libc 는 우분투에 기본으로 탑재된 라이브러리다

 

2. Lazy Binding & Now Binding

ELF(Executable and Linkable Format)

리눅스 기반 시스템의 기본 바이너리 형식

 

Lazy Binding

Dynamic Linking 방식으로 컴파일 된  바이너리에서

함수를 처음 호출할 때 해당 함수의 주소를 공유 라이브러리에서 가져오는 것

 

Now Binding

프로그램이 실행될 때 해당 프로그램에서 사용하는 모든 함수들의 주소를 읽어와 got영역에 저장하는 것이다

 

2. 링크

1. 링크(Link)

리눅스에서 C 소스 코드는 전처리, 컴파일, 어셈블 과정을 거쳐서 ELF 형식을 갖춘 오브젝트 파일(Object file)로 번역된다

C 컴파일 과정

오브젝트 파일은 라이브러리 함수들의 정의의 위치를 모르므로 실행이 불가능하다

링크 과정

라이브러리 등 필요한 오브젝트 파일을 연결시키는 작업을 링킹(Linking)이라고 한다

링크 과정까지 마치면 최종 실행파일이 생긴다

 

2. Static (정적) 링크

Static Link 방식은 파일 생성시 라이브러리 내용을 포함한 실행 파일을 만든다

#include <stdio.h>

void main() {
    puts("pwd");
}

pwd 를 출력하는 간단한 C 코드이다

 

리눅스에서 정적 링크로 파일을 만드려면 -static 옵션을 사용하면 된다

gcc 는 기본적으로 동적 (dynamic)으로 컴파일 한다

gcc -o pg_static pg.c -static
gcc -o pg_dynamic pg.c

파일을 확인해보면 statically linked 로 정적 링크된 것을 확인할 수 있다

 

ls 명령으로 확인해보면 

정적으로 링크된 파일은 실행 파일 안에 모든 코드가 포함되기 때문에 용량이 큰 것을 확인할 수 있다

 

   0x0000000000401775 <+0>:     endbr64
   0x0000000000401779 <+4>:     push   rbp
   0x000000000040177a <+5>:     mov    rbp,rsp
   0x000000000040177d <+8>:     lea    rax,[rip+0x96880]        # 0x498004
   0x0000000000401784 <+15>:    mov    rdi,rax
   0x0000000000401787 <+18>:    call   0x40c170 <puts>
   0x000000000040178c <+23>:    nop
   0x000000000040178d <+24>:    pop    rbp
   0x000000000040178e <+25>:    ret

pg_static 파일의 어셈블리를 확인해보자

static 링크 방식에서는 puts 가 있는 0x40c170  을 직접 호출한다

 

함수 호출 전과 후의 주소가 같은 것을 확인할 수 있다

처음부터 puts 함수의 주소를 가리키고 있고, 주소는 프로그램의 text 영역에 있는 것으로 확인할 수 있다

 

3. Dynamic (동적) 링크

Dynamic link 방식은 공유 라이브러리를 사용한다

라이브러리를 하나의 메모리 공간에 매핑하고 여러 프로그램에서 공유하여 사용한다

 

gcc 는 기본적으로 Dynamic link 방식으로 컴파일한다

 

실행 파일 안에 라이브러리 코드를 포함하지 않기 때문에 static 방식보다 파일 크기가 훨씬 작다

덕분에 실행시에도 적은 메모리를 사용하게 된다

하지만 라이브러리가 없으면 실행할 수 없다는 단점이 있다

 

   0x0000000000001149 <+0>:     endbr64
   0x000000000000114d <+4>:     push   rbp
   0x000000000000114e <+5>:     mov    rbp,rsp
   0x0000000000001151 <+8>:     lea    rax,[rip+0xeac]        # 0x2004
   0x0000000000001158 <+15>:    mov    rdi,rax
   0x000000000000115b <+18>:    call   0x1050 <puts@plt>
   0x0000000000001160 <+23>:    nop
   0x0000000000001161 <+24>:    pop    rbp
   0x0000000000001162 <+25>:    ret

pg_dynamic 파일의 어셈블리를 확인해보자

dynamic 에서는 puts 의 plt 주소인 0x1050을 호출한다

dynamic link 방식은 함수의 주소를 라이브러리에서 찾아야 하는데,

이 과정에서 사용되는 것이 plt 이다

 

파일을 실행한 후 주소를 확인하면

함수 호출 전과 후의 주소가 다르고, 두 번째 호출부터 puts 의 주소를 가리키고 있다

 

 

3. PLT, GOT

1. PLT & GOT

PLT(Procedure Linkage Table)

외부 라이브러리 함수를 사용할 수 있도록 주소를 연결해주는 테이블이다

PLT를 통해 다른 라이브러리에 있는 함수를 호출해 사용할 수 있다

 

GOT(Global Offset Table)

PLT 에서 호출하는 resolve 함수를 통해 구한 라이브러리 함수의 절대 주소가 저장되어 있는 테이블이다

 

바이너리가 실행되면 ASLR 에 의해 라이브러리가 임의의 주소에 매핑된다

라이브러리 함수를 호출하면, 함수의 이름을 바탕으로 라이브러리에서 심볼을 탐색하고,

해당 함수의 정의를 발견하면 그 주소로 실행 흐름을 옮기게 된다

이 과정을 runtime resolve 라고 한다

 

2. dl_resolve

Dynamic Link 방식으로 컴파일 하면 함수를 호출할 때 PLT 를 참조하게 된다

PLT 에서는 GOT로 점프하는데, GOT 에는 라이브러리에 존재하는 실제 함수의 주소가 쓰여있다

_dl_resolve

두 번째 호출이면 GOT 에 실제 함수의 주소가 쓰여있지만, 첫 번째 호출이면 주소가 쓰여있지 않다

그래서 첫 호출 시에는 Linker 가 dl_resolve 라는 함수를 사용해 필요한 함수의 주소를 알아오고,

GOT 에 써준 후 해당 함수를 호출한다.

 

// Name : got.c
//Compile : gcc -o got got.c -no-pie -fno-stack-protector -m32

#include <stdio.h>

int main() {
  puts("Resolving address of 'puts'.");
  puts("Get address from GOT");
}

위의 코드를 컴파일 하고 실행해보자

 

Dump of assembler code for function main:
   0x08049176 <+0>:     lea    ecx,[esp+0x4]
   0x0804917a <+4>:     and    esp,0xfffffff0
   0x0804917d <+7>:     push   DWORD PTR [ecx-0x4]
   0x08049180 <+10>:    push   ebp
   0x08049181 <+11>:    mov    ebp,esp
   0x08049183 <+13>:    push   ebx
   0x08049184 <+14>:    push   ecx
   0x08049185 <+15>:    call   0x80490b0 <__x86.get_pc_thunk.bx>
   0x0804918a <+20>:    add    ebx,0x2e76
   0x08049190 <+26>:    sub    esp,0xc
   0x08049193 <+29>:    lea    eax,[ebx-0x1ff8]
   0x08049199 <+35>:    push   eax
   0x0804919a <+36>:    call   0x8049050 <puts@plt>
   0x0804919f <+41>:    add    esp,0x10
   0x080491a2 <+44>:    sub    esp,0xc
   0x080491a5 <+47>:    lea    eax,[ebx-0x1fdb]
   0x080491ab <+53>:    push   eax
   0x080491ac <+54>:    call   0x8049050 <puts@plt>
   0x080491b1 <+59>:    add    esp,0x10
   0x080491b4 <+62>:    mov    eax,0x0
   0x080491b9 <+67>:    lea    esp,[ebp-0x8]
   0x080491bc <+70>:    pop    ecx
   0x080491bd <+71>:    pop    ebx
   0x080491be <+72>:    pop    ebp
   0x080491bf <+73>:    lea    esp,[ecx-0x4]
   0x080491c2 <+76>:    ret
End of assembler dump.

main 함수의 어셈블리이다

main() 에서 puts@plt 를 호출하는 지점에 break를 건다

 

3. resolve 되기 전

call 하는 주소로 이동하면 PLT 가 있다

PLT 는 GOT 를 참조하기 때문에 0x804c010 은 GOT 일 것이다

 

GOT 가 맞는 것을 확인할 수 있다

 

_dl_runtime_resolve

si 명령어로 실행흐름을 따라가보면

_dl_runtime_resolve 함수가 호출되는 것을 확인할 수 있다

_dl_rumtime_resolve 함수는 puts 의 실제 주소를 구하고, GOT 에 주소를 저장한다

 

si 명령어로 _dl_runtime_resolve 안으로 진입한 후, finish 명령어로 빠져나오면

puts 의 GOT 엔트리에 라이브러리 영역의 실제 puts 주소인 0xf7df52a0 이 쓰여있는 것을 확인할 수 있다

 

4. resolve 된 후

puts@plt 를 두 번째 호출 할 때 break 를 걸고 확인하면

puts 에 GOT 에 puts 의 실제 주소인 0xf7df52a0 이 쓰여있는 것을 확인할 수 있다

 

 

4. GOT Overwrite

1. GOT Overwrite

PLT 에서 GOT 를 참조할 때, GOT 의 값을 검증하지 않는다

따라서 puts 의 GOT 에 저장된 값을 공격자가 임의로 변경하면

puts 가 호출될 때 원하는 함수가 실행되게 할 수 있다

 

위의 그림과 같이 GOT 에 임의의 값을 Overwrite 하여 실행흐름을 변조하는 공격기법을 

GOT Overwrite 라고 한다

 

 

5. Reference


https://learn.dreamhack.io/66#1

https://blackperl-security.gitlab.io/blog/2016/03/07/2016-03-07-pltgot-01/

https://blackperl-security.gitlab.io/blog/2016/03/08/2016-03-08-pltgot-02/

 

 

저작자표시 비영리 변경금지

'Hacking > Pwnable' 카테고리의 다른 글

GOT Overwrite  (1) 2024.06.30
Dynamic Link 시 함수 호출 과정 (Runtime Resolve)  (0) 2024.06.28
NX-bit, ASLR  (0) 2024.05.10
스택 카나리 (Stack Canary)  (0) 2024.05.03
셸코드 (Shellcode)  (0) 2024.04.29
  1. 공유 라이브러리( PLT, GOT)
  2. 1. 라이브러리란?
  3. 2. 링크
  4. 3. PLT, GOT
  5. 4. GOT Overwrite
  6. 5. Reference
'Hacking/Pwnable' 카테고리의 다른 글
  • GOT Overwrite
  • Dynamic Link 시 함수 호출 과정 (Runtime Resolve)
  • NX-bit, ASLR
  • 스택 카나리 (Stack Canary)
GunP4ng
GunP4ng
GunP4ng
GunP4ng
GunP4ng
전체
오늘
어제
  • 분류 전체보기 (99)
    • Hacking (29)
      • Pwnable (28)
      • Web (0)
      • Reversing (0)
      • Misc (1)
    • War Game (18)
      • Pwnable (18)
      • Web (0)
      • Misc (0)
    • pwnable.kr (0)
    • CTF (0)
    • Coding (48)
      • baekjoon (26)
      • C (22)
    • ETC (4)
      • Certificate (4)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • 글쓰기

공지사항

인기 글

태그

  • BOF
  • 스택
  • 코딩도장
  • send_sig
  • srop
  • got_overwrite
  • PIE
  • ROP
  • 함수
  • return_to_library
  • 포인터
  • Got
  • plaid_ctf
  • 코딩
  • stack pivoting
  • Dreamhack
  • memory_corruption
  • C언어
  • 메모리
  • ptmalloc
  • rtl_chaining
  • x64
  • sschall
  • 백준
  • shellcode
  • WarGame
  • RTL
  • x86
  • plt
  • 구조체

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.3.0
GunP4ng
공유 라이브러리(PLT, GOT)
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.