mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
383 lines
22 KiB
Markdown
383 lines
22 KiB
Markdown
# ELF Tricks
|
|
|
|
{{#include ../../banners/hacktricks-training.md}}
|
|
|
|
## Program Headers
|
|
|
|
ELF를 메모리에 로드하는 방법을 로더에게 설명합니다:
|
|
```bash
|
|
readelf -lW lnstat
|
|
|
|
Elf file type is DYN (Position-Independent Executable file)
|
|
Entry point 0x1c00
|
|
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 0x00001b 0x00001b R 0x1
|
|
[Requesting program interpreter: /lib/ld-linux-aarch64.so.1]
|
|
LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x003f7c 0x003f7c R E 0x10000
|
|
LOAD 0x00fc48 0x000000000001fc48 0x000000000001fc48 0x000528 0x001190 RW 0x10000
|
|
DYNAMIC 0x00fc58 0x000000000001fc58 0x000000000001fc58 0x000200 0x000200 RW 0x8
|
|
NOTE 0x000254 0x0000000000000254 0x0000000000000254 0x0000e0 0x0000e0 R 0x4
|
|
GNU_EH_FRAME 0x003610 0x0000000000003610 0x0000000000003610 0x0001b4 0x0001b4 R 0x4
|
|
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
|
|
GNU_RELRO 0x00fc48 0x000000000001fc48 0x000000000001fc48 0x0003b8 0x0003b8 R 0x1
|
|
|
|
Section to Segment mapping:
|
|
Segment Sections...
|
|
00
|
|
01 .interp
|
|
02 .interp .note.gnu.build-id .note.ABI-tag .note.package .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
|
|
03 .init_array .fini_array .dynamic .got .data .bss
|
|
04 .dynamic
|
|
05 .note.gnu.build-id .note.ABI-tag .note.package
|
|
06 .eh_frame_hdr
|
|
07
|
|
08 .init_array .fini_array .dynamic .got
|
|
```
|
|
이전 프로그램에는 **9개의 프로그램 헤더**가 있으며, **세그먼트 매핑**은 **각 섹션이 위치한** 프로그램 헤더(00에서 08까지)를 나타냅니다.
|
|
|
|
### PHDR - 프로그램 헤더
|
|
|
|
프로그램 헤더 테이블과 메타데이터 자체를 포함합니다.
|
|
|
|
### INTERP
|
|
|
|
이진 파일을 메모리에 로드하는 데 사용할 로더의 경로를 나타냅니다.
|
|
|
|
### LOAD
|
|
|
|
이 헤더는 **이진 파일을 메모리에 로드하는 방법**을 나타내는 데 사용됩니다.\
|
|
각 **LOAD** 헤더는 **메모리**의 영역(크기, 권한 및 정렬)을 나타내고, 그곳에 복사할 ELF **이진 파일의 바이트**를 나타냅니다.
|
|
|
|
예를 들어, 두 번째 헤더는 크기가 0x1190이며, 0x1fc48에 위치해야 하고, 읽기 및 쓰기 권한을 가지며, 오프셋 0xfc48에서 0x528로 채워집니다(모든 예약된 공간을 채우지 않음). 이 메모리에는 섹션 `.init_array .fini_array .dynamic .got .data .bss`가 포함됩니다.
|
|
|
|
### DYNAMIC
|
|
|
|
이 헤더는 프로그램을 라이브러리 종속성과 연결하고 재배치를 적용하는 데 도움을 줍니다. **`.dynamic`** 섹션을 확인하세요.
|
|
|
|
### NOTE
|
|
|
|
이진 파일에 대한 공급업체 메타데이터 정보를 저장합니다.
|
|
|
|
### GNU_EH_FRAME
|
|
|
|
디버거와 C++ 예외 처리 런타임 함수에서 사용하는 스택 언와인드 테이블의 위치를 정의합니다.
|
|
|
|
### GNU_STACK
|
|
|
|
스택 실행 방지 방어의 구성을 포함합니다. 활성화되면 이진 파일은 스택에서 코드를 실행할 수 없습니다.
|
|
|
|
### GNU_RELRO
|
|
|
|
이진 파일의 RELRO(재배치 읽기 전용) 구성을 나타냅니다. 이 보호는 프로그램이 로드된 후 실행되기 전에 메모리의 특정 섹션(예: `GOT` 또는 `init` 및 `fini` 테이블)을 읽기 전용으로 표시합니다.
|
|
|
|
이전 예제에서는 0x3b8 바이트를 0x1fc48에 읽기 전용으로 복사하여 섹션 `.init_array .fini_array .dynamic .got .data .bss`에 영향을 미칩니다.
|
|
|
|
RELRO는 부분적이거나 전체적일 수 있으며, 부분 버전은 **지연 바인딩**에 사용되는 **`.plt.got`** 섹션을 보호하지 않으며, 라이브러리의 위치를 처음 검색할 때 주소를 기록하기 위해 이 메모리 공간에 **쓰기 권한**이 필요합니다.
|
|
|
|
### TLS
|
|
|
|
스레드 로컬 변수에 대한 정보를 저장하는 TLS 항목의 테이블을 정의합니다.
|
|
|
|
## 섹션 헤더
|
|
|
|
섹션 헤더는 ELF 이진 파일에 대한 보다 자세한 정보를 제공합니다.
|
|
```
|
|
objdump lnstat -h
|
|
|
|
lnstat: file format elf64-littleaarch64
|
|
|
|
Sections:
|
|
Idx Name Size VMA LMA File off Algn
|
|
0 .interp 0000001b 0000000000000238 0000000000000238 00000238 2**0
|
|
CONTENTS, ALLOC, LOAD, READONLY, DATA
|
|
1 .note.gnu.build-id 00000024 0000000000000254 0000000000000254 00000254 2**2
|
|
CONTENTS, ALLOC, LOAD, READONLY, DATA
|
|
2 .note.ABI-tag 00000020 0000000000000278 0000000000000278 00000278 2**2
|
|
CONTENTS, ALLOC, LOAD, READONLY, DATA
|
|
3 .note.package 0000009c 0000000000000298 0000000000000298 00000298 2**2
|
|
CONTENTS, ALLOC, LOAD, READONLY, DATA
|
|
4 .gnu.hash 0000001c 0000000000000338 0000000000000338 00000338 2**3
|
|
CONTENTS, ALLOC, LOAD, READONLY, DATA
|
|
5 .dynsym 00000498 0000000000000358 0000000000000358 00000358 2**3
|
|
CONTENTS, ALLOC, LOAD, READONLY, DATA
|
|
6 .dynstr 000001fe 00000000000007f0 00000000000007f0 000007f0 2**0
|
|
CONTENTS, ALLOC, LOAD, READONLY, DATA
|
|
7 .gnu.version 00000062 00000000000009ee 00000000000009ee 000009ee 2**1
|
|
CONTENTS, ALLOC, LOAD, READONLY, DATA
|
|
8 .gnu.version_r 00000050 0000000000000a50 0000000000000a50 00000a50 2**3
|
|
CONTENTS, ALLOC, LOAD, READONLY, DATA
|
|
9 .rela.dyn 00000228 0000000000000aa0 0000000000000aa0 00000aa0 2**3
|
|
CONTENTS, ALLOC, LOAD, READONLY, DATA
|
|
10 .rela.plt 000003c0 0000000000000cc8 0000000000000cc8 00000cc8 2**3
|
|
CONTENTS, ALLOC, LOAD, READONLY, DATA
|
|
11 .init 00000018 0000000000001088 0000000000001088 00001088 2**2
|
|
CONTENTS, ALLOC, LOAD, READONLY, CODE
|
|
12 .plt 000002a0 00000000000010a0 00000000000010a0 000010a0 2**4
|
|
CONTENTS, ALLOC, LOAD, READONLY, CODE
|
|
13 .text 00001c34 0000000000001340 0000000000001340 00001340 2**6
|
|
CONTENTS, ALLOC, LOAD, READONLY, CODE
|
|
14 .fini 00000014 0000000000002f74 0000000000002f74 00002f74 2**2
|
|
CONTENTS, ALLOC, LOAD, READONLY, CODE
|
|
15 .rodata 00000686 0000000000002f88 0000000000002f88 00002f88 2**3
|
|
CONTENTS, ALLOC, LOAD, READONLY, DATA
|
|
16 .eh_frame_hdr 000001b4 0000000000003610 0000000000003610 00003610 2**2
|
|
CONTENTS, ALLOC, LOAD, READONLY, DATA
|
|
17 .eh_frame 000007b4 00000000000037c8 00000000000037c8 000037c8 2**3
|
|
CONTENTS, ALLOC, LOAD, READONLY, DATA
|
|
18 .init_array 00000008 000000000001fc48 000000000001fc48 0000fc48 2**3
|
|
CONTENTS, ALLOC, LOAD, DATA
|
|
19 .fini_array 00000008 000000000001fc50 000000000001fc50 0000fc50 2**3
|
|
CONTENTS, ALLOC, LOAD, DATA
|
|
20 .dynamic 00000200 000000000001fc58 000000000001fc58 0000fc58 2**3
|
|
CONTENTS, ALLOC, LOAD, DATA
|
|
21 .got 000001a8 000000000001fe58 000000000001fe58 0000fe58 2**3
|
|
CONTENTS, ALLOC, LOAD, DATA
|
|
22 .data 00000170 0000000000020000 0000000000020000 00010000 2**3
|
|
CONTENTS, ALLOC, LOAD, DATA
|
|
23 .bss 00000c68 0000000000020170 0000000000020170 00010170 2**3
|
|
ALLOC
|
|
24 .gnu_debugaltlink 00000049 0000000000000000 0000000000000000 00010170 2**0
|
|
CONTENTS, READONLY
|
|
25 .gnu_debuglink 00000034 0000000000000000 0000000000000000 000101bc 2**2
|
|
CONTENTS, READONLY
|
|
```
|
|
그것은 위치, 오프셋, 권한뿐만 아니라 섹션의 **데이터 유형**도 나타냅니다.
|
|
|
|
### 메타 섹션
|
|
|
|
- **문자열 테이블**: ELF 파일에 필요한 모든 문자열을 포함하고 있습니다(하지만 프로그램에서 실제로 사용되는 문자열은 아닙니다). 예를 들어, `.text` 또는 `.data`와 같은 섹션 이름을 포함합니다. 그리고 문자열 테이블에서 `.text`가 오프셋 45에 있다면 **name** 필드에서 숫자 **45**를 사용합니다.
|
|
- 문자열 테이블이 어디에 있는지 찾기 위해 ELF는 문자열 테이블에 대한 포인터를 포함합니다.
|
|
- **심볼 테이블**: 이름(문자열 테이블의 오프셋), 주소, 크기 및 심볼에 대한 추가 메타데이터와 같은 심볼에 대한 정보를 포함합니다.
|
|
|
|
### 주요 섹션
|
|
|
|
- **`.text`**: 실행할 프로그램의 명령어입니다.
|
|
- **`.data`**: 프로그램에서 정의된 값을 가진 전역 변수입니다.
|
|
- **`.bss`**: 초기화되지 않은 전역 변수(또는 0으로 초기화됨). 여기의 변수는 자동으로 0으로 초기화되므로 이진 파일에 쓸모없는 0이 추가되는 것을 방지합니다.
|
|
- **`.rodata`**: 상수 전역 변수(읽기 전용 섹션)입니다.
|
|
- **`.tdata`** 및 **`.tbss`**: 스레드 로컬 변수가 사용될 때 .data 및 .bss와 같습니다(`__thread_local` in C++ 또는 `__thread` in C).
|
|
- **`.dynamic`**: 아래를 참조하십시오.
|
|
|
|
## 심볼
|
|
|
|
심볼은 프로그램 내의 명명된 위치로, 함수, 전역 데이터 객체, 스레드 로컬 변수 등이 될 수 있습니다.
|
|
```
|
|
readelf -s lnstat
|
|
|
|
Symbol table '.dynsym' contains 49 entries:
|
|
Num: Value Size Type Bind Vis Ndx Name
|
|
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
|
|
1: 0000000000001088 0 SECTION LOCAL DEFAULT 12 .init
|
|
2: 0000000000020000 0 SECTION LOCAL DEFAULT 23 .data
|
|
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strtok@GLIBC_2.17 (2)
|
|
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND s[...]@GLIBC_2.17 (2)
|
|
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strlen@GLIBC_2.17 (2)
|
|
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND fputs@GLIBC_2.17 (2)
|
|
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND exit@GLIBC_2.17 (2)
|
|
8: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _[...]@GLIBC_2.34 (3)
|
|
9: 0000000000000000 0 FUNC GLOBAL DEFAULT UND perror@GLIBC_2.17 (2)
|
|
10: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterT[...]
|
|
11: 0000000000000000 0 FUNC WEAK DEFAULT UND _[...]@GLIBC_2.17 (2)
|
|
12: 0000000000000000 0 FUNC GLOBAL DEFAULT UND putc@GLIBC_2.17 (2)
|
|
[...]
|
|
```
|
|
각 기호 항목에는 다음이 포함됩니다:
|
|
|
|
- **이름**
|
|
- **바인딩 속성** (약한, 로컬 또는 전역): 로컬 기호는 프로그램 자체에서만 접근할 수 있으며, 전역 기호는 프로그램 외부에서 공유됩니다. 약한 객체는 예를 들어 다른 함수에 의해 재정의될 수 있는 함수입니다.
|
|
- **유형**: NOTYPE (유형이 지정되지 않음), OBJECT (전역 데이터 변수), FUNC (함수), SECTION (섹션), FILE (디버거용 소스 코드 파일), TLS (스레드 로컬 변수), GNU_IFUNC (재배치를 위한 간접 함수)
|
|
- **섹션** 인덱스 (위치)
|
|
- **값** (메모리 내 주소)
|
|
- **크기**
|
|
|
|
## 동적 섹션
|
|
```
|
|
readelf -d lnstat
|
|
|
|
Dynamic section at offset 0xfc58 contains 28 entries:
|
|
Tag Type Name/Value
|
|
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
|
|
0x0000000000000001 (NEEDED) Shared library: [ld-linux-aarch64.so.1]
|
|
0x000000000000000c (INIT) 0x1088
|
|
0x000000000000000d (FINI) 0x2f74
|
|
0x0000000000000019 (INIT_ARRAY) 0x1fc48
|
|
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)
|
|
0x000000000000001a (FINI_ARRAY) 0x1fc50
|
|
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
|
|
0x000000006ffffef5 (GNU_HASH) 0x338
|
|
0x0000000000000005 (STRTAB) 0x7f0
|
|
0x0000000000000006 (SYMTAB) 0x358
|
|
0x000000000000000a (STRSZ) 510 (bytes)
|
|
0x000000000000000b (SYMENT) 24 (bytes)
|
|
0x0000000000000015 (DEBUG) 0x0
|
|
0x0000000000000003 (PLTGOT) 0x1fe58
|
|
0x0000000000000002 (PLTRELSZ) 960 (bytes)
|
|
0x0000000000000014 (PLTREL) RELA
|
|
0x0000000000000017 (JMPREL) 0xcc8
|
|
0x0000000000000007 (RELA) 0xaa0
|
|
0x0000000000000008 (RELASZ) 552 (bytes)
|
|
0x0000000000000009 (RELAENT) 24 (bytes)
|
|
0x000000000000001e (FLAGS) BIND_NOW
|
|
0x000000006ffffffb (FLAGS_1) Flags: NOW PIE
|
|
0x000000006ffffffe (VERNEED) 0xa50
|
|
0x000000006fffffff (VERNEEDNUM) 2
|
|
0x000000006ffffff0 (VERSYM) 0x9ee
|
|
0x000000006ffffff9 (RELACOUNT) 15
|
|
0x0000000000000000 (NULL) 0x0
|
|
```
|
|
NEEDED 디렉토리는 프로그램이 계속 진행하기 위해 **언급된 라이브러리를 로드해야 함**을 나타냅니다. NEEDED 디렉토리는 공유 **라이브러리가 완전히 작동하고 사용 준비가 되었을 때** 완료됩니다.
|
|
|
|
## Relocations
|
|
|
|
로더는 또한 로드한 후 종속성을 재배치해야 합니다. 이러한 재배치는 REL 또는 RELA 형식의 재배치 테이블에 표시되며, 재배치 수는 동적 섹션 RELSZ 또는 RELASZ에 제공됩니다.
|
|
```
|
|
readelf -r lnstat
|
|
|
|
Relocation section '.rela.dyn' at offset 0xaa0 contains 23 entries:
|
|
Offset Info Type Sym. Value Sym. Name + Addend
|
|
00000001fc48 000000000403 R_AARCH64_RELATIV 1d10
|
|
00000001fc50 000000000403 R_AARCH64_RELATIV 1cc0
|
|
00000001fff0 000000000403 R_AARCH64_RELATIV 1340
|
|
000000020008 000000000403 R_AARCH64_RELATIV 20008
|
|
000000020010 000000000403 R_AARCH64_RELATIV 3330
|
|
000000020030 000000000403 R_AARCH64_RELATIV 3338
|
|
000000020050 000000000403 R_AARCH64_RELATIV 3340
|
|
000000020070 000000000403 R_AARCH64_RELATIV 3348
|
|
000000020090 000000000403 R_AARCH64_RELATIV 3350
|
|
0000000200b0 000000000403 R_AARCH64_RELATIV 3358
|
|
0000000200d0 000000000403 R_AARCH64_RELATIV 3360
|
|
0000000200f0 000000000403 R_AARCH64_RELATIV 3370
|
|
000000020110 000000000403 R_AARCH64_RELATIV 3378
|
|
000000020130 000000000403 R_AARCH64_RELATIV 3380
|
|
000000020150 000000000403 R_AARCH64_RELATIV 3388
|
|
00000001ffb8 000a00000401 R_AARCH64_GLOB_DA 0000000000000000 _ITM_deregisterTM[...] + 0
|
|
00000001ffc0 000b00000401 R_AARCH64_GLOB_DA 0000000000000000 __cxa_finalize@GLIBC_2.17 + 0
|
|
00000001ffc8 000f00000401 R_AARCH64_GLOB_DA 0000000000000000 stderr@GLIBC_2.17 + 0
|
|
00000001ffd0 001000000401 R_AARCH64_GLOB_DA 0000000000000000 optarg@GLIBC_2.17 + 0
|
|
00000001ffd8 001400000401 R_AARCH64_GLOB_DA 0000000000000000 stdout@GLIBC_2.17 + 0
|
|
00000001ffe0 001e00000401 R_AARCH64_GLOB_DA 0000000000000000 __gmon_start__ + 0
|
|
00000001ffe8 001f00000401 R_AARCH64_GLOB_DA 0000000000000000 __stack_chk_guard@GLIBC_2.17 + 0
|
|
00000001fff8 002e00000401 R_AARCH64_GLOB_DA 0000000000000000 _ITM_registerTMCl[...] + 0
|
|
|
|
Relocation section '.rela.plt' at offset 0xcc8 contains 40 entries:
|
|
Offset Info Type Sym. Value Sym. Name + Addend
|
|
00000001fe70 000300000402 R_AARCH64_JUMP_SL 0000000000000000 strtok@GLIBC_2.17 + 0
|
|
00000001fe78 000400000402 R_AARCH64_JUMP_SL 0000000000000000 strtoul@GLIBC_2.17 + 0
|
|
00000001fe80 000500000402 R_AARCH64_JUMP_SL 0000000000000000 strlen@GLIBC_2.17 + 0
|
|
00000001fe88 000600000402 R_AARCH64_JUMP_SL 0000000000000000 fputs@GLIBC_2.17 + 0
|
|
00000001fe90 000700000402 R_AARCH64_JUMP_SL 0000000000000000 exit@GLIBC_2.17 + 0
|
|
00000001fe98 000800000402 R_AARCH64_JUMP_SL 0000000000000000 __libc_start_main@GLIBC_2.34 + 0
|
|
00000001fea0 000900000402 R_AARCH64_JUMP_SL 0000000000000000 perror@GLIBC_2.17 + 0
|
|
00000001fea8 000b00000402 R_AARCH64_JUMP_SL 0000000000000000 __cxa_finalize@GLIBC_2.17 + 0
|
|
00000001feb0 000c00000402 R_AARCH64_JUMP_SL 0000000000000000 putc@GLIBC_2.17 + 0
|
|
00000001feb8 000d00000402 R_AARCH64_JUMP_SL 0000000000000000 opendir@GLIBC_2.17 + 0
|
|
00000001fec0 000e00000402 R_AARCH64_JUMP_SL 0000000000000000 fputc@GLIBC_2.17 + 0
|
|
00000001fec8 001100000402 R_AARCH64_JUMP_SL 0000000000000000 snprintf@GLIBC_2.17 + 0
|
|
00000001fed0 001200000402 R_AARCH64_JUMP_SL 0000000000000000 __snprintf_chk@GLIBC_2.17 + 0
|
|
00000001fed8 001300000402 R_AARCH64_JUMP_SL 0000000000000000 malloc@GLIBC_2.17 + 0
|
|
00000001fee0 001500000402 R_AARCH64_JUMP_SL 0000000000000000 gettimeofday@GLIBC_2.17 + 0
|
|
00000001fee8 001600000402 R_AARCH64_JUMP_SL 0000000000000000 sleep@GLIBC_2.17 + 0
|
|
00000001fef0 001700000402 R_AARCH64_JUMP_SL 0000000000000000 __vfprintf_chk@GLIBC_2.17 + 0
|
|
00000001fef8 001800000402 R_AARCH64_JUMP_SL 0000000000000000 calloc@GLIBC_2.17 + 0
|
|
00000001ff00 001900000402 R_AARCH64_JUMP_SL 0000000000000000 rewind@GLIBC_2.17 + 0
|
|
00000001ff08 001a00000402 R_AARCH64_JUMP_SL 0000000000000000 strdup@GLIBC_2.17 + 0
|
|
00000001ff10 001b00000402 R_AARCH64_JUMP_SL 0000000000000000 closedir@GLIBC_2.17 + 0
|
|
00000001ff18 001c00000402 R_AARCH64_JUMP_SL 0000000000000000 __stack_chk_fail@GLIBC_2.17 + 0
|
|
00000001ff20 001d00000402 R_AARCH64_JUMP_SL 0000000000000000 strrchr@GLIBC_2.17 + 0
|
|
00000001ff28 001e00000402 R_AARCH64_JUMP_SL 0000000000000000 __gmon_start__ + 0
|
|
00000001ff30 002000000402 R_AARCH64_JUMP_SL 0000000000000000 abort@GLIBC_2.17 + 0
|
|
00000001ff38 002100000402 R_AARCH64_JUMP_SL 0000000000000000 feof@GLIBC_2.17 + 0
|
|
00000001ff40 002200000402 R_AARCH64_JUMP_SL 0000000000000000 getopt_long@GLIBC_2.17 + 0
|
|
00000001ff48 002300000402 R_AARCH64_JUMP_SL 0000000000000000 __fprintf_chk@GLIBC_2.17 + 0
|
|
00000001ff50 002400000402 R_AARCH64_JUMP_SL 0000000000000000 strcmp@GLIBC_2.17 + 0
|
|
00000001ff58 002500000402 R_AARCH64_JUMP_SL 0000000000000000 free@GLIBC_2.17 + 0
|
|
00000001ff60 002600000402 R_AARCH64_JUMP_SL 0000000000000000 readdir64@GLIBC_2.17 + 0
|
|
00000001ff68 002700000402 R_AARCH64_JUMP_SL 0000000000000000 strndup@GLIBC_2.17 + 0
|
|
00000001ff70 002800000402 R_AARCH64_JUMP_SL 0000000000000000 strchr@GLIBC_2.17 + 0
|
|
00000001ff78 002900000402 R_AARCH64_JUMP_SL 0000000000000000 fwrite@GLIBC_2.17 + 0
|
|
00000001ff80 002a00000402 R_AARCH64_JUMP_SL 0000000000000000 fflush@GLIBC_2.17 + 0
|
|
00000001ff88 002b00000402 R_AARCH64_JUMP_SL 0000000000000000 fopen64@GLIBC_2.17 + 0
|
|
00000001ff90 002c00000402 R_AARCH64_JUMP_SL 0000000000000000 __isoc99_sscanf@GLIBC_2.17 + 0
|
|
00000001ff98 002d00000402 R_AARCH64_JUMP_SL 0000000000000000 strncpy@GLIBC_2.17 + 0
|
|
00000001ffa0 002f00000402 R_AARCH64_JUMP_SL 0000000000000000 __assert_fail@GLIBC_2.17 + 0
|
|
00000001ffa8 003000000402 R_AARCH64_JUMP_SL 0000000000000000 fgets@GLIBC_2.17 + 0
|
|
```
|
|
### 정적 재배치
|
|
|
|
프로그램이 **선호하는 주소**(보통 0x400000)와 다른 위치에 로드되면(주소가 이미 사용 중이거나 **ASLR** 또는 기타 이유로), 정적 재배치는 선호하는 주소에 바이너리가 로드될 것으로 예상했던 값을 가진 포인터를 **수정**합니다.
|
|
|
|
예를 들어, `R_AARCH64_RELATIV` 유형의 섹션은 재배치 편향에 주소를 수정하고 추가 값(addend value)을 더해야 합니다.
|
|
|
|
### 동적 재배치 및 GOT
|
|
|
|
재배치는 외부 기호(종속성의 함수와 같은)를 참조할 수도 있습니다. 예를 들어, libC의 malloc 함수입니다. 그런 다음 로더는 libC를 로드할 때 malloc 함수가 로드된 주소를 확인하고, 이 주소를 GOT(전역 오프셋 테이블) 테이블(재배치 테이블에 표시됨)에 기록합니다. 여기서 malloc의 주소가 지정되어야 합니다.
|
|
|
|
### 프로시저 링크 테이블
|
|
|
|
PLT 섹션은 지연 바인딩을 수행할 수 있게 해주며, 이는 함수의 위치 해석이 처음 접근할 때 수행된다는 것을 의미합니다.
|
|
|
|
따라서 프로그램이 malloc을 호출할 때, 실제로는 PLT의 `malloc`에 해당하는 위치(`malloc@plt`)를 호출합니다. 처음 호출될 때 `malloc`의 주소를 해석하고 저장하므로 다음에 `malloc`이 호출될 때는 PLT 코드 대신 그 주소가 사용됩니다.
|
|
|
|
## 프로그램 초기화
|
|
|
|
프로그램이 로드된 후 실행할 시간입니다. 그러나 실행되는 첫 번째 코드는 항상 `main` 함수가 아닙니다. 예를 들어 C++에서 **전역 변수가 클래스의 객체**인 경우, 이 객체는 main이 실행되기 **전에** **초기화**되어야 합니다.
|
|
```cpp
|
|
#include <stdio.h>
|
|
// g++ autoinit.cpp -o autoinit
|
|
class AutoInit {
|
|
public:
|
|
AutoInit() {
|
|
printf("Hello AutoInit!\n");
|
|
}
|
|
~AutoInit() {
|
|
printf("Goodbye AutoInit!\n");
|
|
}
|
|
};
|
|
|
|
AutoInit autoInit;
|
|
|
|
int main() {
|
|
printf("Main\n");
|
|
return 0;
|
|
}
|
|
```
|
|
이 전역 변수들은 `.data` 또는 `.bss`에 위치하지만, `__CTOR_LIST__`와 `__DTOR_LIST__` 목록에는 초기화 및 소멸할 객체들이 저장되어 이들을 추적할 수 있습니다.
|
|
|
|
C 코드에서는 GNU 확장을 사용하여 동일한 결과를 얻을 수 있습니다:
|
|
```c
|
|
__attributte__((constructor)) //Add a constructor to execute before
|
|
__attributte__((destructor)) //Add to the destructor list
|
|
```
|
|
컴파일러 관점에서, `main` 함수가 실행되기 전과 후에 이러한 작업을 실행하기 위해 `init` 함수와 `fini` 함수를 생성할 수 있으며, 이는 동적 섹션에서 **`INIT`** 및 **`FIN`**으로 참조됩니다. 그리고 ELF의 `init` 및 `fini` 섹션에 배치됩니다.
|
|
|
|
언급된 다른 옵션은 동적 섹션의 **`INIT_ARRAY`** 및 **`FINI_ARRAY`** 항목에서 **`__CTOR_LIST__`** 및 **`__DTOR_LIST__`** 목록을 참조하는 것입니다. 이들의 길이는 **`INIT_ARRAYSZ`** 및 **`FINI_ARRAYSZ`**로 표시됩니다. 각 항목은 인수 없이 호출될 함수 포인터입니다.
|
|
|
|
또한, **`PREINIT_ARRAY`**를 가질 수 있으며, 이는 **`INIT_ARRAY`** 포인터보다 **먼저** 실행될 **포인터**를 포함합니다.
|
|
|
|
### 초기화 순서
|
|
|
|
1. 프로그램이 메모리에 로드되고, 정적 전역 변수가 **`.data`**에서 초기화되며, 초기화되지 않은 변수는 **`.bss`**에서 0으로 설정됩니다.
|
|
2. 프로그램 또는 라이브러리에 대한 모든 **종속성**이 **초기화**되고 동적 링크가 실행됩니다.
|
|
3. **`PREINIT_ARRAY`** 함수가 실행됩니다.
|
|
4. **`INIT_ARRAY`** 함수가 실행됩니다.
|
|
5. **`INIT`** 항목이 있으면 호출됩니다.
|
|
6. 라이브러리인 경우, dlopen은 여기서 종료되며, 프로그램인 경우 **실제 진입점**(`main` 함수)을 호출할 시간입니다.
|
|
|
|
## 스레드 로컬 저장소 (TLS)
|
|
|
|
C++에서 **`__thread_local`** 키워드 또는 GNU 확장 **`__thread`**를 사용하여 정의됩니다.
|
|
|
|
각 스레드는 이 변수에 대해 고유한 위치를 유지하므로 오직 해당 스레드만 자신의 변수를 접근할 수 있습니다.
|
|
|
|
이것이 사용될 때, ELF에서 **`.tdata`** 및 **`.tbss`** 섹션이 사용됩니다. 이는 TLS에 대한 `.data` (초기화됨) 및 `.bss` (초기화되지 않음)와 유사합니다.
|
|
|
|
각 변수는 TLS 헤더에 항목을 가지며, 여기에는 크기와 TLS 오프셋이 지정됩니다. 이는 스레드의 로컬 데이터 영역에서 사용할 오프셋입니다.
|
|
|
|
`__TLS_MODULE_BASE`는 스레드 로컬 저장소의 기본 주소를 참조하는 데 사용되는 기호이며, 모듈의 모든 스레드 로컬 데이터를 포함하는 메모리 영역을 가리킵니다.
|
|
|
|
{{#include ../../banners/hacktricks-training.md}}
|