OLD 2018 ~ 2021/BASIC → Hacking

[System Hacking ] PLT / GOT 영역

pogn 2018. 7. 10. 21:40

이론적 배경 

Linking
: 실행파일이 호출하는 라이브러리의 API 함수를 정상적으로 실행시킬 수 있도록 
라이브러리의 printf 오브젝트 파일을 서로 연결시켜 주는 과정이다. 

Static Link
: 파일 생성시에 라이브러리 파일을 실행파일에 포함하기 때문에 
따로 라이브러리를 설치할 필요가 없으며
실행 시에도 라이브러리 연동과정이 필요없다.

Dynamic Link
: 메모리에 로딩시킨 라이브러리를 여러 프로그램이 공유한다.

이 때에, PLT GOT는 
다이나믹 링킹과정에서 프로그램이 해당 라이브러리의 위치를 찾아가기 위해 쓰이는 영역이다. 



PLT/GOT 함수 호출과정

junior@catpwn:~/System_Hacking$ gdb -q ./plt_got
Reading symbols from ./plt_got...(no debugging symbols found)...done.
(gdb) disas main
Dump of assembler code for function main:
   0x08048444 <+0>:    push   %ebp
   0x08048445 <+1>:    mov    %esp,%ebp
   0x08048447 <+3>:    push   $0x8048521
   0x0804844c <+8>:    call   0x80482e0 <puts@plt>
   0x08048451 <+13>:    add    $0x4,%esp
   0x08048454 <+16>:    push   $0x804852e
   0x08048459 <+21>:    call   0x80482e0 <puts@plt>
   0x0804845e <+26>:    add    $0x4,%esp
   0x08048461 <+29>:    push   $0x8048536
   0x08048466 <+34>:    call   0x80482e0 <puts@plt>
   0x0804846b <+39>:    add    $0x4,%esp
   0x0804846e <+42>:    call   0x804840b <func1>
   0x08048473 <+47>:    call   0x804841e <func2>
   0x08048478 <+52>:    mov    $0x0,%eax
   0x0804847d <+57>:    leave  
   0x0804847e <+58>:    ret    
End of assembler dump.
먼저, puts 함수 부분을 보면 call하는 함수명이 puts@plt로 되어있다. 

(gdb) b *main+8
Breakpoint 1 at 0x804844c
(gdb) r
Starting program: /home/junior/System_Hacking/plt_got
Breakpoint 1, 0x0804844c in main ()
(gdb) disas main
Dump of assembler code for function main:
   0x08048444 <+0>:    push   %ebp
   0x08048445 <+1>:    mov    %esp,%ebp
   0x08048447 <+3>:    push   $0x8048521
=> 0x0804844c <+8>:    call   0x80482e0 <puts@plt>
   0x08048451 <+13>:    add    $0x4,%esp
   0x08048454 <+16>:    push   $0x804852e
   0x08048459 <+21>:    call   0x80482e0 <puts@plt>
   0x0804845e <+26>:    add    $0x4,%esp
   0x08048461 <+29>:    push   $0x8048536
   0x08048466 <+34>:    call   0x80482e0 <puts@plt>
   0x0804846b <+39>:    add    $0x4,%esp
   0x0804846e <+42>:    call   0x804840b <func1>
   0x08048473 <+47>:    call   0x804841e <func2>
   0x08048478 <+52>:    mov    $0x0,%eax
   0x0804847d <+57>:    leave  
   0x0804847e <+58>:    ret    
End of assembler dump.
이부분에 브레이크 포인트를 걸고 실행시켜 함수를 puts바로 직전까지 실행시켰다. 
(gdb) x/3i 0x80482e0
   0x80482e0 <puts@plt>:    jmp    *0x804a00c
   0x80482e6 <puts@plt+6>:    push   $0x0
   0x80482eb <puts@plt+11>:    jmp    0x80482d0

(gdb) x/wx 0x804a00c
0x804a00c:    0x080482e6
"함수명"@plt의 어셈코드는 세 줄이며,
puts가 처음 실행되는 순간에는 *0x804a00c에 0x80482e6 , 즉 그냥 다음 실행코드가 들어있다 .
(gdb) x/2i 0x80482d0
   0x80482d0:    pushl  0x804a004      // 링크맵 구조체 포인터
   0x80482d6:    jmp    *0x804a008
(gdb) x/xw 0x804a008
0x804a008:    0xf7fee000
(gdb) x/10i 0xf7fee000
   0xf7fee000 <_dl_runtime_resolve>:    push   %eax
   0xf7fee001 <_dl_runtime_resolve+1>:    push   %ecx
   0xf7fee002 <_dl_runtime_resolve+2>:    push   %edx
   0xf7fee003 <_dl_runtime_resolve+3>:    mov    0x10(%esp),%edx
   0xf7fee007 <_dl_runtime_resolve+7>:    mov    0xc(%esp),%eax
   0xf7fee00b <_dl_runtime_resolve+11>:    call   0xf7fe77e0 <_dl_fixup>
   0xf7fee010 <_dl_runtime_resolve+16>:    pop    %edx
   0xf7fee011 <_dl_runtime_resolve+17>:    mov    (%esp),%ecx
   0xf7fee014 <_dl_runtime_resolve+20>:    mov    %eax,(%esp)
   0xf7fee017 <_dl_runtime_resolve+23>:    mov    0x4(%esp),%eax
(gdb) b *0xf7fee00b
Breakpoint 6 at 0xf7fee00b: file ../sysdeps/i386/dl-trampoline.S, line 43.
(gdb) c
Continuing.
Breakpoint 6, _dl_runtime_resolve () at ../sysdeps/i386/dl-trampoline.S:43
43    ../sysdeps/i386/dl-trampoline.S: 그런 파일이나 디렉터리가 없습니다.

(gdb) x/10i 0xf7fee000
   0xf7fee000 <_dl_runtime_resolve>:    push   %eax
   0xf7fee001 <_dl_runtime_resolve+1>:    push   %ecx
   0xf7fee002 <_dl_runtime_resolve+2>:    push   %edx
   0xf7fee003 <_dl_runtime_resolve+3>:    mov    0x10(%esp),%edx
   0xf7fee007 <_dl_runtime_resolve+7>:    mov    0xc(%esp),%eax
=> 0xf7fee00b <_dl_runtime_resolve+11>:    call   0xf7fe77e0 <_dl_fixup>
   0xf7fee010 <_dl_runtime_resolve+16>:    pop    %edx
   0xf7fee011 <_dl_runtime_resolve+17>:    mov    (%esp),%ecx
   0xf7fee014 <_dl_runtime_resolve+20>:    mov    %eax,(%esp)
   0xf7fee017 <_dl_runtime_resolve+23>:    mov    0x4(%esp),%eax
0x80482d0를 따라가 보면  _dll_runtime_resolve 함수가 시작된다. 
_dll_fixup 함수를 call 하는 것을 볼 수 있다. 
이 부분에 브레이크 포인트를 걸고 따라 들어가면
(gdb) x/100i 0xf7fe77e0
   0xf7fe77e0 <_dl_fixup>:    push   %ebp
   0xf7fe77e1 <_dl_fixup+1>:    push   %edi
   0xf7fe77e2 <_dl_fixup+2>:    mov    %eax,%edi
   0xf7fe77e4 <_dl_fixup+4>:    push   %esi
   0xf7fe77e5 <_dl_fixup+5>:    push   %ebx
   0xf7fe77e6 <_dl_fixup+6>:    call   0xf7ff276d <__x86.get_pc_thunk.si>
   0xf7fe77eb <_dl_fixup+11>:    add    $0x15815,%esi
   0xf7fe77f1 <_dl_fixup+17>:    sub    $0x2c,%esp
   0xf7fe77f4 <_dl_fixup+20>:    mov    0x7c(%edi),%ecx
   0xf7fe77f7 <_dl_fixup+23>:    mov    0x34(%eax),%eax
   0xf7fe77fa <_dl_fixup+26>:    mov    %esi,0x8(%esp)
   0xf7fe77fe <_dl_fixup+30>:    add    0x4(%ecx),%edx
   0xf7fe7801 <_dl_fixup+33>:    mov    0x4(%eax),%eax
   0xf7fe7804 <_dl_fixup+36>:    mov    0x38(%edi),%ecx
   0xf7fe7807 <_dl_fixup+39>:    mov    %eax,0xc(%esp)
   0xf7fe780b <_dl_fixup+43>:    mov    %edx,%ebp
   0xf7fe780d <_dl_fixup+45>:    mov    0x4(%edx),%edx
   0xf7fe7810 <_dl_fixup+48>:    mov    0x0(%ebp),%eax
   0xf7fe7813 <_dl_fixup+51>:    mov    %edx,%esi
   0xf7fe7815 <_dl_fixup+53>:    shr    $0x8,%esi
   0xf7fe7818 <_dl_fixup+56>:    mov    %esi,%ebx
   0xf7fe781a <_dl_fixup+58>:    shl    $0x4,%ebx
   0xf7fe781d <_dl_fixup+61>:    add    0x4(%ecx),%ebx
   0xf7fe7820 <_dl_fixup+64>:    mov    (%edi),%ecx
   0xf7fe7822 <_dl_fixup+66>:    add    %ecx,%eax
   0xf7fe7824 <_dl_fixup+68>:    cmp    $0x7,%dl
   0xf7fe7827 <_dl_fixup+71>:    mov    %ebx,0x1c(%esp)
   0xf7fe782b <_dl_fixup+75>:    jne    0xf7fe796f <_dl_fixup+399>
   0xf7fe7831 <_dl_fixup+81>:    testb  $0x3,0xd(%ebx)
   0xf7fe7835 <_dl_fixup+85>:    mov    %eax,%ebp
   0xf7fe7837 <_dl_fixup+87>:    jne    0xf7fe7910 <_dl_fixup+304>
   0xf7fe783d <_dl_fixup+93>:    mov    0xe4(%edi),%edx
   0xf7fe7843 <_dl_fixup+99>:    test   %edx,%edx
   0xf7fe7845 <_dl_fixup+101>:    je     0xf7fe78f0 <_dl_fixup+272>
---Type <return> to continue, or q <return> to quit---
   0xf7fe784b <_dl_fixup+107>:    mov    0x4(%edx),%edx
   0xf7fe784e <_dl_fixup+110>:    movzwl (%edx,%esi,2),%edx
   0xf7fe7852 <_dl_fixup+114>:    and    $0x7fff,%edx
   0xf7fe7858 <_dl_fixup+120>:    shl    $0x4,%edx
   0xf7fe785b <_dl_fixup+123>:    add    0x170(%edi),%edx
   0xf7fe7861 <_dl_fixup+129>:    mov    0x4(%edx),%ecx
   0xf7fe7864 <_dl_fixup+132>:    test   %ecx,%ecx
   0xf7fe7866 <_dl_fixup+134>:    mov    $0x0,%ecx
   0xf7fe786b <_dl_fixup+139>:    cmove  %ecx,%edx
   0xf7fe786e <_dl_fixup+142>:    mov    %gs:0xc,%ecx
   0xf7fe7875 <_dl_fixup+149>:    test   %ecx,%ecx
   0xf7fe7877 <_dl_fixup+151>:    mov    $0x1,%esi
   0xf7fe787c <_dl_fixup+156>:    jne    0xf7fe7950 <_dl_fixup+368>
   0xf7fe7882 <_dl_fixup+162>:    mov    0xc(%esp),%eax
   0xf7fe7886 <_dl_fixup+166>:    add    (%ebx),%eax
   0xf7fe7888 <_dl_fixup+168>:    lea    0x1c(%esp),%ecx
   0xf7fe788c <_dl_fixup+172>:    sub    $0xc,%esp
   0xf7fe788f <_dl_fixup+175>:    push   $0x0
   0xf7fe7891 <_dl_fixup+177>:    push   %esi
   0xf7fe7892 <_dl_fixup+178>:    push   $0x1
   0xf7fe7894 <_dl_fixup+180>:    push   %edx
   0xf7fe7895 <_dl_fixup+181>:    mov    %edi,%edx
   0xf7fe7897 <_dl_fixup+183>:    pushl  0x1cc(%edi)
   0xf7fe789d <_dl_fixup+189>:    call   0xf7fe2a60 <_dl_lookup_symbol_x>
(gdb) b *0xf7fe789d
Breakpoint 7 at 0xf7fe789d: file dl-runtime.c, line 111.
(gdb) c
Continuing.
Breakpoint 7, 0xf7fe789d in _dl_fixup (l=0xf7ffd918, reloc_arg=<optimised out>)
    at dl-runtime.c:111
111    dl-runtime.c: 그런 파일이나 디렉터리가 없습니다.

(gdb) i r $eax
eax            0x8048236    134513206
(gdb) x/s 0x8048236
0x8048236:    "puts"

(gdb) x/10wx 0xf7e1ba48
0xf7e1ba48:    0x00000edc    0x0005fca0    0x000001d0    0x000d0022
0xf7e1ba58:    0x00001522    0x000eb2b0    0x0000007a    0x000d0012
0xf7e1ba68:    0x00001e86    0x0002f100

위와 같이 _dl_lookup_symbol_x라는 함수를 발견할 수 있다.  
이부분에도 역시 브레이크포인트를 걸어서 해당 부분까지 실행시킨다음에 
반환된 레지스터 값은 strtab에 들어있는 puts 라는 문자열의 주소이다. 

그리고, symtab에는 실제 심볼들의 offset이 들어있는데, 
이 곳에서 공유라이브러리의 시작주소와 실제 puts 함수의 구현 코드 사이의 거리를 알 수 있다.


따라서 
>>> hex(0x5fca0+0xf7597000)
'0xf75f6ca0'
값이 puts 함수 코드의 위치임을 알수 있다. 

두 번째 puts 함수 호출부터는 아까 다음코드를 가리키던 어셈블리어쪽에 
plt 주소가 들어가 있어서 조금 더 빠른 호출이 가능하다.  



PLT / GOT