ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • ELF PLT & GOT
    System hacking training/Knowledge 2018. 2. 27. 02:29

    ROP라는 기법을 익히기 위해서는 PLT 와 GOT라는 녀석들의 개념을 알고있어야 한다.


    PLT 란?

    Procedure Linkage Table의 약자로 외부 프로시저를 연결해주는 테이블이다.

    PLT를 통해 다른 라이브러리에 있는 프로시저를 호출해 사용할 수 있다.


    PLT는 일종의 실제 호출 코드를 담고 있는 테이블로써 이 내용 참조를 통해 _dl_runtime_resolve가 수행되고,

    실제 시스템 라이브러리 호출이 이뤄지게 된다.


    GOT 란?

    Global Offset Table의 약자로 PLT가 참조하는 테이블이다.

    프로시저들의 주소가 들어있다.


    GOT는 프로시저들의 주소를 가지고 있다.

    PLT가 어떤 외부 프로시저를 호출할때 이 GOT를 참조하여 해당 주소로 점프하게된다.


    ※뇌피셜 Tip

    Procedure == 함수라고 생각하면 될것같다.

    확실한 정의보다는 규약과 같이 쓰이는 용어들이다.

    like function, procedure, subroutine, method, subprogram..


    표출된 바에는 function이 return value가 있고, procedure는 void이며 method는 객체지향이다...

    라고 하지만 printf() call은 procedure로 불리우기도 한다. (printf는 int형이다. 반환값이 있다.)


    100% 같다고 볼수는 없지만 어떤 상황에서 쓰이느냐에 따라 용어를 각기 사용할 뿐 결국 다 함수라는 점은 똑같다.




    GOT와 PLT의 사용 이유


    먼저 Linker를 알아야한다.


    이를 위해 코드 하나를 작성한다.




    [test.c]

    #include <stdio.h>


    int main()          

    {                      

    printf("test1\n");

    printf("test2\n");

    return 0;           

    }                           

                       


    ☞ include한 헤더파일 stdio.h 안에는 printf()의 선언이 있다.

    소스파일을 실행파일로 만들기 위해 컴파일이라는 과정을 거쳐야한다.

    컴파일을 통해 오브젝트 파일이 생성된다.


    하지만 이 오브젝트 파일은 파일 그 자체를 실행할 수 없다.

    이유는 printf()의 구현 코드를 모르기 때문이다.

    printf()를 호출 하였을 때 어떤 코드를 실행 해야하는지, 우리가 작성한 코드만 가지고서는 아무것도 알 수 없다.


    따라서 오브젝트 파일을 실행 가능하게 만들기 위해서는 printf()의 실행코드를 찾아서 오브젝트 파일과 연결시켜야한다.

    printf()의 실행 코드는 printf()의 구현 코드를 컴파일한 오브젝트 파일로, 이런 오브젝트 파일들이 모여있는 곳을 라이브러리(Library)라고 한다.


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

    이렇게 링크까지 마치면 실행파일이 생긴다.




    Link를 하는 방법에도 두가지 방법이 존재한다.


    Static & Dynamic 방식이다.


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

    $ gcc -static -o test test.c 처럼 -static옵션을 주면 Static Link 방식으로 컴파일된다.


    Static Link 방식은 실행파일 안에 모든 코드가 있기 때문에 라이브러리 연동이 필요없다.

    다만 파일의 크기가 커진다는 단점이 있고, 동일한 라이브러리를 사용하더라도 해당 라이브러리를 사용하는 모든 프로그램들은 라이브러리의 내용을 메모리에 매핑시켜야한다.


    2. Dynamic Link 방식 : 공유 라이브러리를 사용한다. 

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

    $ gcc -o test test.c 처럼 아무 옵션없이 컴파일하면 Dynamic Link 방식으로 컴파일이된다.


    Dynamic Link 방식은 실행파일 안에 코드가 없기때문에 Static Link 방식보다 훨씬 파일의 크기가 작다.

    실행시에도 상대적으로 작은 메모리 공간을 차지한다.

    하지만 실행파일이 라이브러리에 의존해야 하기 때문에 라이브러리가 없으면 실행을 할 수 없다.




    Q : Dynamic Link 방식으로 컴파일 했을때 왜 plt 와 got를 사용하는가?


    - Static Link 방식으로 컴파일 하면 라이브러리가 프로그램 내부에 있기 때문에 함수의 주소를 알아오는 과정이 필요없다.


    하지만


    - Dynamic Link 방식으로 컴파일 한다면 라이브러리가 프로그램 외부에 있기 때문에 함수의 주소를 알아오는 과정이 필요하다.


    Dynamic Link 방식으로 프로그램이 만들어지면 함수를 호출할 때 plt를 참조하게 되는데

    plt 에서 got로 점프를 하고, got에는 라이브러리에 존재하는 실제 함수의 주소가 쓰여있기 때문에 이 함수를 호출하게 된다.


    이 때 첫번째 호출을 했을때와 아닐때 동작과정의 차이가 존재한다.


    ex) 함수 호출이 처음일때


    func() 호출 -> plt로 이동 -> got 참조 -> 다시 plt로 이동 -> _dl_runtime_resolve -> got 저장후, 실제 함수 주소로 점프!


    ex) 함수 호출이 처음이 아닐때(got에 실제 func()의 주소가 저장되어있다.)


    func() 호출 -> plt로 이동 -> got 참조 -> func() 로 점프!


    ▶ 이 처럼 한번 호출한 함수는 got 참조를 통하여 _dl_runtime_resolve를 다시 거치지 않고 빠르게 수행 할 수 있다.


    /* 두번째 호출이라면 got에 실제 함수의 주소가 쓰여있지만, 

    첫번째 호출이라면 got에 실제 함수의 주소가 쓰여있지 않기 때문에 got에 써준 후 호출하는 과정이 필요하다.


    따라서 첫번째 호출시에는 Linker가 dl_resolve라는 함수를 사용하여 필요한 함수의 주소를 알아오고,

    got에 그 주소를 써준 후 해당 함수를 호출한다. */




    [실습 - Dynamic Link vs Static Link]


    위의 소스파일을 Dynamic Link 방식으로 컴파일한 파일을 gdb에 올리고



    p puts로 실행하기 전 puts@plt의 주소를 본다. (0x80482e0)


    r 로 실행을 하고, 다시 puts의 주소를 보면


    0xb7e69ca0으로 이전의 주소와는 다른것을 확인할 수 있다.


    하지만 Static Link 방식으로 컴파일을 한 파일을 같은 방식으로 확인을 해보면



    이전 Dynamic Link 방식과는 다르게 실행하기전과 실행을 한 후의 puts 주소가 동일한것을 확인할 수 있고,

    0x804f170의 위치에 있다.(text영역으로 추측된다.)


    이상 PLT 와 GOT에 대한 정리를 마친다.


    PLT&amp;GOT_step 1.txt


    반응형

    'System hacking training > Knowledge' 카테고리의 다른 글

    ELF Technique - ROP  (2) 2018.03.05
    ELF Technique - GOT Overwrite  (0) 2018.02.28
    ELF Technique - RTL Chaining  (1) 2018.02.22
    ELF Technique - RTL(Return To Library)  (0) 2018.02.16
    gdb 명령어  (0) 2018.02.13
Designed by Tistory.