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에 스트링이 들어가 있지 않음.