what is debugging symbols & common symbols
문득 공부를 하다가 다음과 같은 의문이 생겼다.
glibc는
(pwn) amemoyoi ~$ file /lib/x86_64-linux-gnu/libc.so.6
/lib/x86_64-linux-gnu/libc.so.6: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=42c84c92e6f98126b3e2230ebfdead22c235b667, for GNU/Linux 3.2.0, stripped다음과 같이 stripped 되어 있는데 왜 심볼들이 다 살아있지? 내가 아는 심볼의 정의가 틀렸던 것인가? 라는 생각이 들었다.
그래서 한번 정리 해보았다.
일단 우리가 일반적으로 바이너리를 컴파일해보자
(pwn) amemoyoi ~$ cat test.c
#include <stdio.h>
int global_var1 = 250;
int main(){
int var_1 = 10;
int var_2 = 50;
int input_var = 0;
scanf("%d" , &input_var);
if ( input_var == 1 )
printf("%d!!! " , var_1 );
else if (input_var == 2)
printf("%d!!! " , var_2 );
else
printf("%d!!! " , global_var1);
printf("hello world!\n");
return 0;
}
(pwn) amemoyoi ~$ gcc -o test test.c
(pwn) amemoyoi ~$ file test
test: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=fa108236c1857fdbcd5bc8c61f68839c92f3ebad, for GNU/Linux 3.2.0, not stripped
(pwn) amemoyoi ~$ 일반적으로 컴파일을 하면 다음과 같이 not stripped 라고 나온다.
(pwn) amemoyoi ~$ objdump -t ./test
./test: file format elf64-x86-64
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 Scrt1.o
000000000000038c l O .note.ABI-tag 0000000000000020 __abi_tag
0000000000000000 l df *ABS* 0000000000000000 crtstuff.c
00000000000010f0 l F .text 0000000000000000 deregister_tm_clones
0000000000001120 l F .text 0000000000000000 register_tm_clones
0000000000001160 l F .text 0000000000000000 __do_global_dtors_aux
0000000000004014 l O .bss 0000000000000001 completed.0
0000000000003da8 l O .fini_array 0000000000000000 __do_global_dtors_aux_fini_array_entry
00000000000011a0 l F .text 0000000000000000 frame_dummy
0000000000003da0 l O .init_array 0000000000000000 __frame_dummy_init_array_entry
0000000000000000 l df *ABS* 0000000000000000 test.c
0000000000000000 l df *ABS* 0000000000000000 crtstuff.c
00000000000020f8 l O .eh_frame 0000000000000000 __FRAME_END__
0000000000000000 l df *ABS* 0000000000000000
0000000000003db0 l O .dynamic 0000000000000000 _DYNAMIC
000000000000201c l .eh_frame_hdr 0000000000000000 __GNU_EH_FRAME_HDR
0000000000003fa0 l O .got 0000000000000000 _GLOBAL_OFFSET_TABLE_
0000000000000000 F *UND* 0000000000000000 __libc_start_main@GLIBC_2.34
0000000000000000 w *UND* 0000000000000000 _ITM_deregisterTMCloneTable
0000000000004000 w .data 0000000000000000 data_start
0000000000000000 F *UND* 0000000000000000 puts@GLIBC_2.2.5
0000000000004014 g .data 0000000000000000 _edata
0000000000001280 g F .fini 0000000000000000 .hidden _fini
0000000000000000 F *UND* 0000000000000000 __stack_chk_fail@GLIBC_2.4
0000000000000000 F *UND* 0000000000000000 printf@GLIBC_2.2.5
0000000000004000 g .data 0000000000000000 __data_start
0000000000000000 w *UND* 0000000000000000 __gmon_start__
0000000000004008 g O .data 0000000000000000 .hidden __dso_handle
0000000000002000 g O .rodata 0000000000000004 _IO_stdin_used
0000000000004018 g .bss 0000000000000000 _end
00000000000010c0 g F .text 0000000000000026 _start
0000000000004014 g .bss 0000000000000000 __bss_start
00000000000011a9 g F .text 00000000000000d7 main
0000000000004010 g O .data 0000000000000004 global_var1
0000000000000000 F *UND* 0000000000000000 __isoc99_scanf@GLIBC_2.7
0000000000004018 g O .data 0000000000000000 .hidden __TMC_END__
0000000000000000 w *UND* 0000000000000000 _ITM_registerTMCloneTable
0000000000000000 w F *UND* 0000000000000000 __cxa_finalize@GLIBC_2.2.5
0000000000001000 g F .init 0000000000000000 .hidden _init하지만 다음과 같이 main 같은 심볼이 보이는 것을 알 수 있다. 심볼의 종류는 2가지로 나뉜다.
(pwn) amemoyoi ~$ readelf -S ./test
There are 31 section headers, starting at offset 0x3748:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000000318 00000318
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.gnu.pr[...] NOTE 0000000000000338 00000338
0000000000000030 0000000000000000 A 0 0 8
[ 3] .note.gnu.bu[...] NOTE 0000000000000368 00000368
0000000000000024 0000000000000000 A 0 0 4
[ 4] .note.ABI-tag NOTE 000000000000038c 0000038c
0000000000000020 0000000000000000 A 0 0 4
[ 5] .gnu.hash GNU_HASH 00000000000003b0 000003b0
0000000000000024 0000000000000000 A 6 0 8
[ 6] .dynsym DYNSYM 00000000000003d8 000003d8
00000000000000f0 0000000000000018 A 7 1 8
[ 7] .dynstr STRTAB 00000000000004c8 000004c8
00000000000000c8 0000000000000000 A 0 0 1
[ 8] .gnu.version VERSYM 0000000000000590 00000590
0000000000000014 0000000000000002 A 6 0 2
[ 9] .gnu.version_r VERNEED 00000000000005a8 000005a8
0000000000000050 0000000000000000 A 7 1 8
[10] .rela.dyn RELA 00000000000005f8 000005f8
00000000000000c0 0000000000000018 A 6 0 8
[11] .rela.plt RELA 00000000000006b8 000006b8
0000000000000060 0000000000000018 AI 6 24 8
[12] .init PROGBITS 0000000000001000 00001000
000000000000001b 0000000000000000 AX 0 0 4
[13] .plt PROGBITS 0000000000001020 00001020
0000000000000050 0000000000000010 AX 0 0 16
[14] .plt.got PROGBITS 0000000000001070 00001070
0000000000000010 0000000000000010 AX 0 0 16
[15] .plt.sec PROGBITS 0000000000001080 00001080
0000000000000040 0000000000000010 AX 0 0 16
[16] .text PROGBITS 00000000000010c0 000010c0
00000000000001c0 0000000000000000 AX 0 0 16
[17] .fini PROGBITS 0000000000001280 00001280
000000000000000d 0000000000000000 AX 0 0 4
[18] .rodata PROGBITS 0000000000002000 00002000
000000000000001b 0000000000000000 A 0 0 4
[19] .eh_frame_hdr PROGBITS 000000000000201c 0000201c
0000000000000034 0000000000000000 A 0 0 4
[20] .eh_frame PROGBITS 0000000000002050 00002050
00000000000000ac 0000000000000000 A 0 0 8
[21] .init_array INIT_ARRAY 0000000000003da0 00002da0
0000000000000008 0000000000000008 WA 0 0 8
[22] .fini_array FINI_ARRAY 0000000000003da8 00002da8
0000000000000008 0000000000000008 WA 0 0 8
[23] .dynamic DYNAMIC 0000000000003db0 00002db0
00000000000001f0 0000000000000010 WA 7 0 8
[24] .got PROGBITS 0000000000003fa0 00002fa0
0000000000000060 0000000000000008 WA 0 0 8
[25] .data PROGBITS 0000000000004000 00003000
0000000000000014 0000000000000000 WA 0 0 8
[26] .bss NOBITS 0000000000004014 00003014
0000000000000004 0000000000000000 WA 0 0 1
[27] .comment PROGBITS 0000000000000000 00003014
000000000000002b 0000000000000001 MS 0 0 1
[28] .symtab SYMTAB 0000000000000000 00003040
00000000000003c0 0000000000000018 29 18 8
[29] .strtab STRTAB 0000000000000000 00003400
000000000000022d 0000000000000000 0 0 1
[30] .shstrtab STRTAB 0000000000000000 0000362d
000000000000011a 0000000000000000 0 0 1다음과 같이 섹션을 확인했을때
[ 6] .dynsym DYNSYM 00000000000003d8 000003d8
00000000000000f0 0000000000000018 A 7 1 8
[ 7] .dynstr STRTAB 00000000000004c8 000004c8
00000000000000c8 0000000000000000 A 0 0 1여기에 위치하는 재배치를 위한 심볼들과
[28] .symtab SYMTAB 0000000000000000 00003040
00000000000003c0 0000000000000018 29 18 8
[29] .strtab STRTAB 0000000000000000 00003400
000000000000022d 0000000000000000 0 0 1
여기에 위치하는 디버깅이나 리버싱을 위해 존재하는 심볼들이다.
.dynsym 에 대한 심볼들은 필수이다. 이 심볼들은 런타임과 로드가 될때 로더에 의해 재배치가 된다. 즉, 외부 라이브러리나 외부 파일에 대한 심볼들이다.
그에 반해 .symtab 여기에 존재하는 심볼들은 필수가 아니다. 이미 내부에 있는 함수들은 컴파일 시간에 위치가 전부 정해진다. 따라서, rip를 따라가는 특성을 가진 컴퓨터 입장에서는 심볼은 아무의미를 가지지 않는다. 즉, 컴퓨터 입장에서는 call “printf” 가 아닌 call 0x1e0(%rip)와 같은 철저히 이미 컴파일 시간에 계산된 rip를 따라갈 뿐이다. 따라서 굳이 필요없다.
그래서 내가 여기서 strip 명령어로 strip을 하면 저 .symtab 섹션을 지워버린다
(pwn) amemoyoi ~$ strip test
(pwn) amemoyoi ~$ readelf -S ./test
There are 29 section headers, starting at offset 0x3150:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000000318 00000318
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.gnu.pr[...] NOTE 0000000000000338 00000338
0000000000000030 0000000000000000 A 0 0 8
[ 3] .note.gnu.bu[...] NOTE 0000000000000368 00000368
0000000000000024 0000000000000000 A 0 0 4
[ 4] .note.ABI-tag NOTE 000000000000038c 0000038c
0000000000000020 0000000000000000 A 0 0 4
[ 5] .gnu.hash GNU_HASH 00000000000003b0 000003b0
0000000000000024 0000000000000000 A 6 0 8
[ 6] .dynsym DYNSYM 00000000000003d8 000003d8
00000000000000f0 0000000000000018 A 7 1 8
[ 7] .dynstr STRTAB 00000000000004c8 000004c8
00000000000000c8 0000000000000000 A 0 0 1
[ 8] .gnu.version VERSYM 0000000000000590 00000590
0000000000000014 0000000000000002 A 6 0 2
[ 9] .gnu.version_r VERNEED 00000000000005a8 000005a8
0000000000000050 0000000000000000 A 7 1 8
[10] .rela.dyn RELA 00000000000005f8 000005f8
00000000000000c0 0000000000000018 A 6 0 8
[11] .rela.plt RELA 00000000000006b8 000006b8
0000000000000060 0000000000000018 AI 6 24 8
[12] .init PROGBITS 0000000000001000 00001000
000000000000001b 0000000000000000 AX 0 0 4
[13] .plt PROGBITS 0000000000001020 00001020
0000000000000050 0000000000000010 AX 0 0 16
[14] .plt.got PROGBITS 0000000000001070 00001070
0000000000000010 0000000000000010 AX 0 0 16
[15] .plt.sec PROGBITS 0000000000001080 00001080
0000000000000040 0000000000000010 AX 0 0 16
[16] .text PROGBITS 00000000000010c0 000010c0
00000000000001c0 0000000000000000 AX 0 0 16
[17] .fini PROGBITS 0000000000001280 00001280
000000000000000d 0000000000000000 AX 0 0 4
[18] .rodata PROGBITS 0000000000002000 00002000
000000000000001b 0000000000000000 A 0 0 4
[19] .eh_frame_hdr PROGBITS 000000000000201c 0000201c
0000000000000034 0000000000000000 A 0 0 4
[20] .eh_frame PROGBITS 0000000000002050 00002050
00000000000000ac 0000000000000000 A 0 0 8
[21] .init_array INIT_ARRAY 0000000000003da0 00002da0
0000000000000008 0000000000000008 WA 0 0 8
[22] .fini_array FINI_ARRAY 0000000000003da8 00002da8
0000000000000008 0000000000000008 WA 0 0 8
[23] .dynamic DYNAMIC 0000000000003db0 00002db0
00000000000001f0 0000000000000010 WA 7 0 8
[24] .got PROGBITS 0000000000003fa0 00002fa0
0000000000000060 0000000000000008 WA 0 0 8
[25] .data PROGBITS 0000000000004000 00003000
0000000000000014 0000000000000000 WA 0 0 8
[26] .bss NOBITS 0000000000004014 00003014
0000000000000004 0000000000000000 WA 0 0 1
[27] .comment PROGBITS 0000000000000000 00003014
000000000000002b 0000000000000001 MS 0 0 1
[28] .shstrtab STRTAB 0000000000000000 0000303f
000000000000010a 0000000000000000 0 0 1다음과 같이 지워진다.
(pwn) amemoyoi ~$ file test
test: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=fa108236c1857fdbcd5bc8c61f68839c92f3ebad, for GNU/Linux 3.2.0, stripped그리고 stripped 이 된것을 알수 있다.
그럼 처음에 궁금했던 것을 해소해보자
libc는 당연히 .symtab 은 존재하지 않는다. stripped을 굳이 안할이유가 없기 때문이다.
(pwn) amemoyoi ~$ objdump -t /lib/x86_64-linux-gnu/libc.so.6
/lib/x86_64-linux-gnu/libc.so.6: file format elf64-x86-64
SYMBOL TABLE:
no symbols
따라서 확인해보면 일반 심볼은 존재하지 않는다.
대신, 라이브러리 특성상 외부에서 자신의 함수를 알릴 이정표를 가지고 있어야 한다. 이를 .dynsym 에 넣어서 마치 api와 같은 역할을 한다. 이러한 재배치 심볼들을 우리는 읽고 사용한다. pwntools에서도 이 값을 읽고 사용한다.