Search

2장 연습문제

1. 수동으로 헤더 검사하기

# xxd -g 1 a.out |head -n 30 00000000: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 .ELF............ // e_ident[16] 00000010: 03 00 3e 00 01 00 00 00 30 05 00 00 00 00 00 00 ..>.....0....... // e_type 03 00 / e_machine 3e 00 / e_version 01 00 00 00 / e_entry 30 05 00 00 00 00 00 00 00000020: 40 00 00 00 00 00 00 00 28 19 00 00 00 00 00 00 @.......(....... // e_phoff 40 00 00 00 00 00 00 00 / e_shoff 28 19 00 00 00 00 00 00 00000030: 00 00 00 00 40 00 38 00 09 00 40 00 1d 00 1c 00 ....@.8...@..... // e_flags 00 00 00 00 / e_ehsize 40 00 / e_phentsize 38 00 / e_phnum 09 00 / e_shentsize 40 00 / e_shnum 1d 00 / e_shstrndx 1c 00
C
복사

2. 섹션과 세그먼트

# readelf --wide --segments a.out Elf file type is DYN (Shared object file) Entry point 0x530 There are 9 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000040 0x0000000000000040 0x0000000000000040 0x0001f8 0x0001f8 R 0x8 INTERP 0x000238 0x0000000000000238 0x0000000000000238 0x00001c 0x00001c R 0x1 [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000838 0x000838 R E 0x200000 LOAD 0x000db8 0x0000000000200db8 0x0000000000200db8 0x000258 0x000260 RW 0x200000 DYNAMIC 0x000dc8 0x0000000000200dc8 0x0000000000200dc8 0x0001f0 0x0001f0 RW 0x8 NOTE 0x000254 0x0000000000000254 0x0000000000000254 0x000044 0x000044 R 0x4 GNU_EH_FRAME 0x0006f4 0x00000000000006f4 0x00000000000006f4 0x00003c 0x00003c R 0x4 GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10 GNU_RELRO 0x000db8 0x0000000000200db8 0x0000000000200db8 0x000248 0x000248 R 0x1 Section to Segment mapping: Segment Sections... 00 01 .interp 02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame 03 .init_array .fini_array .dynamic .got .data .bss 04 .dynamic 05 .note.ABI-tag .note.gnu.build-id 06 .eh_frame_hdr 07 08 .init_array .fini_array .dynamic .got
C
복사
1번째 Load Segment가 흔히 말하는 코드 영역(텍스트 영역)
2번째 Load Segment가 데이터 영역

3. C와 C++ 바이너리 비교

C
root@DESKTOP-2HBCL3H:~/chp1/2# readelf -h a.out ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: DYN (Shared object file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x530 Start of program headers: 64 (bytes into file) Start of section headers: 6440 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 9 Size of section headers: 64 (bytes) Number of section headers: 29 Section header string table index: 28 root@DESKTOP-2HBCL3H:~/chp1/2# readelf --sections --wide a.out There are 29 section headers, starting at offset 0x1928: Section Headers: [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 [ 1] .interp PROGBITS 0000000000000238 000238 00001c 00 A 0 0 1 [ 2] .note.ABI-tag NOTE 0000000000000254 000254 000020 00 A 0 0 4 [ 3] .note.gnu.build-id NOTE 0000000000000274 000274 000024 00 A 0 0 4 [ 4] .gnu.hash GNU_HASH 0000000000000298 000298 00001c 00 A 5 0 8 [ 5] .dynsym DYNSYM 00000000000002b8 0002b8 0000a8 18 A 6 1 8 [ 6] .dynstr STRTAB 0000000000000360 000360 000082 00 A 0 0 1 [ 7] .gnu.version VERSYM 00000000000003e2 0003e2 00000e 02 A 5 0 2 [ 8] .gnu.version_r VERNEED 00000000000003f0 0003f0 000020 00 A 6 1 8 [ 9] .rela.dyn RELA 0000000000000410 000410 0000c0 18 A 5 0 8 [10] .rela.plt RELA 00000000000004d0 0004d0 000018 18 AI 5 22 8 [11] .init PROGBITS 00000000000004e8 0004e8 000017 00 AX 0 0 4 [12] .plt PROGBITS 0000000000000500 000500 000020 10 AX 0 0 16 [13] .plt.got PROGBITS 0000000000000520 000520 000008 08 AX 0 0 8 [14] .text PROGBITS 0000000000000530 000530 0001a2 00 AX 0 0 16 [15] .fini PROGBITS 00000000000006d4 0006d4 000009 00 AX 0 0 4 [16] .rodata PROGBITS 00000000000006e0 0006e0 000012 00 A 0 0 4 [17] .eh_frame_hdr PROGBITS 00000000000006f4 0006f4 00003c 00 A 0 0 4 [18] .eh_frame PROGBITS 0000000000000730 000730 000108 00 A 0 0 8 [19] .init_array INIT_ARRAY 0000000000200db8 000db8 000008 08 WA 0 0 8 [20] .fini_array FINI_ARRAY 0000000000200dc0 000dc0 000008 08 WA 0 0 8 [21] .dynamic DYNAMIC 0000000000200dc8 000dc8 0001f0 10 WA 6 0 8 [22] .got PROGBITS 0000000000200fb8 000fb8 000048 08 WA 0 0 8 [23] .data PROGBITS 0000000000201000 001000 000010 00 WA 0 0 8 [24] .bss NOBITS 0000000000201010 001010 000008 00 WA 0 0 1 [25] .comment PROGBITS 0000000000000000 001010 000029 01 MS 0 0 1 [26] .symtab SYMTAB 0000000000000000 001040 0005e8 18 27 43 8 [27] .strtab STRTAB 0000000000000000 001628 000202 00 0 0 1 [28] .shstrtab STRTAB 0000000000000000 00182a 0000fe 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), l (large), p (processor specific) root@DESKTOP-2HBCL3H:~/chp1/2# readelf --segments --wide a.out Elf file type is DYN (Shared object file) Entry point 0x530 There are 9 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000040 0x0000000000000040 0x0000000000000040 0x0001f8 0x0001f8 R 0x8 INTERP 0x000238 0x0000000000000238 0x0000000000000238 0x00001c 0x00001c R 0x1 [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000838 0x000838 R E 0x200000 LOAD 0x000db8 0x0000000000200db8 0x0000000000200db8 0x000258 0x000260 RW 0x200000 DYNAMIC 0x000dc8 0x0000000000200dc8 0x0000000000200dc8 0x0001f0 0x0001f0 RW 0x8 NOTE 0x000254 0x0000000000000254 0x0000000000000254 0x000044 0x000044 R 0x4 GNU_EH_FRAME 0x0006f4 0x00000000000006f4 0x00000000000006f4 0x00003c 0x00003c R 0x4 GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10 GNU_RELRO 0x000db8 0x0000000000200db8 0x0000000000200db8 0x000248 0x000248 R 0x1 Section to Segment mapping: Segment Sections... 00 01 .interp 02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame 03 .init_array .fini_array .dynamic .got .data .bss 04 .dynamic 05 .note.ABI-tag .note.gnu.build-id 06 .eh_frame_hdr 07 08 .init_array .fini_array .dynamic .got root@DESKTOP-2HBCL3H:~/chp1/2# root@DESKTOP-2HBCL3H:~/chp1/2# md5sum a.out df761dd4f9f301176edd28eab9377e93 a.out
C
복사
C++
root@DESKTOP-2HBCL3H:~/chp1/2# readelf -h a.out.cpp ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: DYN (Shared object file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x530 Start of program headers: 64 (bytes into file) Start of section headers: 6448 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 9 Size of section headers: 64 (bytes) Number of section headers: 29 Section header string table index: 28 root@DESKTOP-2HBCL3H:~/chp1/2# readelf --sections --wide a.out.cpp There are 29 section headers, starting at offset 0x1930: Section Headers: [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 [ 1] .interp PROGBITS 0000000000000238 000238 00001c 00 A 0 0 1 [ 2] .note.ABI-tag NOTE 0000000000000254 000254 000020 00 A 0 0 4 [ 3] .note.gnu.build-id NOTE 0000000000000274 000274 000024 00 A 0 0 4 [ 4] .gnu.hash GNU_HASH 0000000000000298 000298 00001c 00 A 5 0 8 [ 5] .dynsym DYNSYM 00000000000002b8 0002b8 0000a8 18 A 6 1 8 [ 6] .dynstr STRTAB 0000000000000360 000360 000082 00 A 0 0 1 [ 7] .gnu.version VERSYM 00000000000003e2 0003e2 00000e 02 A 5 0 2 [ 8] .gnu.version_r VERNEED 00000000000003f0 0003f0 000020 00 A 6 1 8 [ 9] .rela.dyn RELA 0000000000000410 000410 0000c0 18 A 5 0 8 [10] .rela.plt RELA 00000000000004d0 0004d0 000018 18 AI 5 22 8 [11] .init PROGBITS 00000000000004e8 0004e8 000017 00 AX 0 0 4 [12] .plt PROGBITS 0000000000000500 000500 000020 10 AX 0 0 16 [13] .plt.got PROGBITS 0000000000000520 000520 000008 08 AX 0 0 8 [14] .text PROGBITS 0000000000000530 000530 0001a2 00 AX 0 0 16 [15] .fini PROGBITS 00000000000006d4 0006d4 000009 00 AX 0 0 4 [16] .rodata PROGBITS 00000000000006e0 0006e0 000012 00 A 0 0 4 [17] .eh_frame_hdr PROGBITS 00000000000006f4 0006f4 00003c 00 A 0 0 4 [18] .eh_frame PROGBITS 0000000000000730 000730 000108 00 A 0 0 8 [19] .init_array INIT_ARRAY 0000000000200db8 000db8 000008 08 WA 0 0 8 [20] .fini_array FINI_ARRAY 0000000000200dc0 000dc0 000008 08 WA 0 0 8 [21] .dynamic DYNAMIC 0000000000200dc8 000dc8 0001f0 10 WA 6 0 8 [22] .got PROGBITS 0000000000200fb8 000fb8 000048 08 WA 0 0 8 [23] .data PROGBITS 0000000000201000 001000 000010 00 WA 0 0 8 [24] .bss NOBITS 0000000000201010 001010 000008 00 WA 0 0 1 [25] .comment PROGBITS 0000000000000000 001010 000029 01 MS 0 0 1 [26] .symtab SYMTAB 0000000000000000 001040 0005e8 18 27 43 8 [27] .strtab STRTAB 0000000000000000 001628 000204 00 0 0 1 [28] .shstrtab STRTAB 0000000000000000 00182c 0000fe 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), l (large), p (processor specific) root@DESKTOP-2HBCL3H:~/chp1/2# readelf --segments --wide a.out.cpp Elf file type is DYN (Shared object file) Entry point 0x530 There are 9 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000040 0x0000000000000040 0x0000000000000040 0x0001f8 0x0001f8 R 0x8 INTERP 0x000238 0x0000000000000238 0x0000000000000238 0x00001c 0x00001c R 0x1 [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000838 0x000838 R E 0x200000 LOAD 0x000db8 0x0000000000200db8 0x0000000000200db8 0x000258 0x000260 RW 0x200000 DYNAMIC 0x000dc8 0x0000000000200dc8 0x0000000000200dc8 0x0001f0 0x0001f0 RW 0x8 NOTE 0x000254 0x0000000000000254 0x0000000000000254 0x000044 0x000044 R 0x4 GNU_EH_FRAME 0x0006f4 0x00000000000006f4 0x00000000000006f4 0x00003c 0x00003c R 0x4 GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10 GNU_RELRO 0x000db8 0x0000000000200db8 0x0000000000200db8 0x000248 0x000248 R 0x1 Section to Segment mapping: Segment Sections... 00 01 .interp 02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame 03 .init_array .fini_array .dynamic .got .data .bss 04 .dynamic 05 .note.ABI-tag .note.gnu.build-id 06 .eh_frame_hdr 07 08 .init_array .fini_array .dynamic .got root@DESKTOP-2HBCL3H:~/chp1/2# md5sum a.out.cpp 66145552595fbc2eeabb30a66ed8b29e a.out.cpp
C
복사
섹션 해더의 사이즈가 8바이트밖에 차이가 안남
컴파일러가 다르기 때문에 엄청 큰 차이를 보일거라 생각했지만 생각보다 잘 보이진 않았음.

4. 지연 바인딩

root@DESKTOP-2HBCL3H:~/chp1/2# objdump -d --section .plt a.out a.out: file format elf64-x86-64 Disassembly of section .plt: 0000000000000500 <.plt>: 500: ff 35 ba 0a 20 00 pushq 0x200aba(%rip) # 200fc0 <_GLOBAL_OFFSET_TABLE_+0x8> 506: ff 25 bc 0a 20 00 jmpq *0x200abc(%rip) # 200fc8 <_GLOBAL_OFFSET_TABLE_+0x10> 50c: 0f 1f 40 00 nopl 0x0(%rax) 0000000000000510 <puts@plt>: 510: ff 25 ba 0a 20 00 jmpq *0x200aba(%rip) # 200fd0 <puts@GLIBC_2.2.5> 516: 68 00 00 00 00 pushq $0x0 51b: e9 e0 ff ff ff jmpq 500 <.plt> root@DESKTOP-2HBCL3H:~/chp1/2# objdump -d --section .got a.out a.out: file format elf64-x86-64 Disassembly of section .got: 0000000000200fb8 <_GLOBAL_OFFSET_TABLE_>: 200fb8: c8 0d 20 00 00 00 00 00 00 00 00 00 00 00 00 00 .. ............. ... 200fd0: 16 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ... root@DESKTOP-2HBCL3H:~/chp1/2# objdump -d --section .plt.got a.out a.out: file format elf64-x86-64 Disassembly of section .plt.got: 0000000000000520 <__cxa_finalize@plt>: 520: ff 25 d2 0a 20 00 jmpq *0x200ad2(%rip) # 200ff8 <__cxa_finalize@GLIBC_2.2.5> 526: 66 90 xchg %ax,%ax root@DESKTOP-2HBCL3H:~/chp1/2# readelf --relocs a.out Relocation section '.rela.dyn' at offset 0x410 contains 8 entries: Offset Info Type Sym. Value Sym. Name + Addend 000000200db8 000000000008 R_X86_64_RELATIVE 630 000000200dc0 000000000008 R_X86_64_RELATIVE 5f0 000000201008 000000000008 R_X86_64_RELATIVE 201008 000000200fd8 000100000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_deregisterTMClone + 0 000000200fe0 000300000006 R_X86_64_GLOB_DAT 0000000000000000 __libc_start_main@GLIBC_2.2.5 + 0 000000200fe8 000400000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0 000000200ff0 000500000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_registerTMCloneTa + 0 000000200ff8 000600000006 R_X86_64_GLOB_DAT 0000000000000000 __cxa_finalize@GLIBC_2.2.5 + 0 Relocation section '.rela.plt' at offset 0x4d0 contains 1 entry: Offset Info Type Sym. Value Sym. Name + Addend 000000200fd0 000200000007 R_X86_64_JUMP_SLO 0000000000000000 puts@GLIBC_2.2.5 + 0
C
복사
이론상으론 애매하여 직접 눈으로으로 봐야 하는 스타일이라 직접 IDA로 까봄
//메인 안에서 _puts를 콜함 .text:000000000000063A ; int __cdecl main(int argc, const char **argv, const char **envp) .text:000000000000063A public main .text:000000000000063A main proc near ; DATA XREF: _start+1D↑o .text:000000000000063A .text:000000000000063A var_10 = qword ptr -10h .text:000000000000063A var_4 = dword ptr -4 .text:000000000000063A .text:000000000000063A ; __unwind { .text:000000000000063A push rbp .text:000000000000063B mov rbp, rsp .text:000000000000063E sub rsp, 10h .text:0000000000000642 mov [rbp+var_4], edi .text:0000000000000645 mov [rbp+var_10], rsi .text:0000000000000649 lea rdi, s ; "Hello, world!" .text:0000000000000650 call _puts .text:0000000000000655 mov eax, 0 .text:000000000000065A leave .text:000000000000065B retn .text:000000000000065B ; } // starts at 63A .text:000000000000065B main endp //.plt section에 존재하는 _puts는 puts의 puts의 주소값을 가져와 점프 .plt:0000000000000510 ; int puts(const char *s) .plt:0000000000000510 _puts proc near ; CODE XREF: main+16↓p .plt:0000000000000510 jmp cs:puts_ptr .plt:0000000000000510 _puts endp .plt:0000000000000510 //.got section에는 puts_ptr이 put 포인터를 가지고있음 .got:0000000000200FD0 puts_ptr dq offset puts ; DATA XREF: _puts↑r //extern으로 외부에서 참조하는것을 알 수 있음. extern:0000000000201020 ; int puts(const char *s) extern:0000000000201020 extrn puts:near ; CODE XREF: _puts↑j extern:0000000000201020 ; DATA XREF: .got:puts_ptr↑o
C
복사
해당 포스팅처럼 .load section에 스트링이 들어가 있지 않음.