mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-26 13:03:37 +00:00
388 lines
23 KiB
Markdown
388 lines
23 KiB
Markdown
# Truques ELF
|
|
|
|
<details>
|
|
|
|
<summary><strong>Aprenda hacking AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
|
|
|
* Você trabalha em uma **empresa de cibersegurança**? Gostaria de ver sua **empresa anunciada no HackTricks**? ou gostaria de ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
|
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
|
* Adquira o [**swag oficial PEASS & HackTricks**](https://peass.creator-spring.com)
|
|
* **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-me** no **Twitter** 🐦[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.**
|
|
* **Compartilhe seus truques de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
|
|
|
</details>
|
|
|
|
## Cabeçalhos do Programa
|
|
|
|
Descrevem ao carregador como carregar o ELF na memória:
|
|
```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
|
|
```
|
|
O programa anterior tem **9 cabeçalhos de programa**, então, o **mapeamento de segmentos** indica em qual cabeçalho de programa (de 00 a 08) **cada seção está localizada**.
|
|
|
|
### PHDR - Program HeaDeR
|
|
|
|
Contém as tabelas de cabeçalho do programa e os metadados em si.
|
|
|
|
### INTERP
|
|
|
|
Indica o caminho do carregador a ser usado para carregar o binário na memória.
|
|
|
|
### LOAD
|
|
|
|
Esses cabeçalhos são usados para indicar **como carregar um binário na memória**.\
|
|
Cada cabeçalho **LOAD** indica uma região de **memória** (tamanho, permissões e alinhamento) e indica os bytes do ELF **binário a serem copiados lá**.
|
|
|
|
Por exemplo, o segundo tem um tamanho de 0x1190, deve estar localizado em 0x1fc48 com permissões de leitura e escrita e será preenchido com 0x528 a partir do deslocamento 0xfc48 (não preenche todo o espaço reservado). Esta memória conterá as seções `.init_array .fini_array .dynamic .got .data .bss`.
|
|
|
|
### DYNAMIC
|
|
|
|
Este cabeçalho ajuda a vincular programas às suas dependências de biblioteca e aplicar realocações. Verifique a seção **`.dynamic`**.
|
|
|
|
### NOTE
|
|
|
|
Armazena informações de metadados do fornecedor sobre o binário.
|
|
|
|
### GNU\_EH\_FRAME
|
|
|
|
Define a localização das tabelas de desenrolamento de pilha, usadas por depuradores e funções de tempo de execução de tratamento de exceções C++.
|
|
|
|
### GNU\_STACK
|
|
|
|
Contém a configuração da defesa de prevenção de execução de pilha. Se ativado, o binário não poderá executar código da pilha.
|
|
|
|
### GNU\_RELRO
|
|
|
|
Indica a configuração RELRO (Relocation Read-Only) do binário. Essa proteção marcará como somente leitura certas seções da memória (como o `GOT` ou as tabelas `init` e `fini`) após o programa ter sido carregado e antes de começar a ser executado.
|
|
|
|
No exemplo anterior, está copiando 0x3b8 bytes para 0x1fc48 como somente leitura afetando as seções `.init_array .fini_array .dynamic .got .data .bss`.
|
|
|
|
Observe que o RELRO pode ser parcial ou completo, a versão parcial não protege a seção **`.plt.got`**, que é usada para **ligação preguiçosa** e precisa que este espaço de memória tenha **permissões de escrita** para escrever o endereço das bibliotecas na primeira vez que sua localização é pesquisada.
|
|
|
|
### TLS
|
|
|
|
Define uma tabela de entradas TLS, que armazena informações sobre variáveis locais de thread.
|
|
|
|
## Cabeçalhos de Seção
|
|
|
|
Os cabeçalhos de seção fornecem uma visão mais detalhada do binário 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
|
|
```
|
|
### Seções Meta
|
|
|
|
* **Tabela de strings**: Contém todas as strings necessárias pelo arquivo ELF (mas não aquelas realmente usadas pelo programa). Por exemplo, contém nomes de seções como `.text` ou `.data`. E se `.text` estiver no offset 45 na tabela de strings, usará o número **45** no campo **name**.
|
|
* Para encontrar onde está a tabela de strings, o ELF contém um ponteiro para a tabela de strings.
|
|
* **Tabela de símbolos**: Contém informações sobre os símbolos como o nome (offset na tabela de strings), endereço, tamanho e mais metadados sobre o símbolo.
|
|
|
|
### Seções Principais
|
|
|
|
* **`.text`**: As instruções do programa a serem executadas.
|
|
* **`.data`**: Variáveis globais com um valor definido no programa.
|
|
* **`.bss`**: Variáveis globais não inicializadas (ou inicializadas para zero). As variáveis aqui são automaticamente inicializadas para zero, evitando assim zeros inúteis de serem adicionados ao binário.
|
|
* **`.rodata`**: Variáveis globais constantes (seção somente leitura).
|
|
* **`.tdata`** e **`.tbss`**: Semelhante ao .data e .bss quando são usadas variáveis locais de thread (`__thread_local` em C++ ou `__thread` em C).
|
|
* **`.dynamic`**: Veja abaixo.
|
|
|
|
## Símbolos
|
|
|
|
Símbolos são locais nomeados no programa que podem ser uma função, um objeto de dados global, variáveis locais de thread...
|
|
```
|
|
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)
|
|
[...]
|
|
```
|
|
Cada entrada de símbolo contém:
|
|
|
|
- **Nome**
|
|
- **Atributos de ligação** (fraco, local ou global): Um símbolo local só pode ser acessado pelo programa em si, enquanto o símbolo global é compartilhado fora do programa. Um objeto fraco é, por exemplo, uma função que pode ser substituída por outra.
|
|
- **Tipo**: NOTYPE (nenhum tipo especificado), OBJECT (variável de dados global), FUNC (função), SECTION (seção), FILE (arquivo de código-fonte para depuradores), TLS (variável local de segmento), GNU_IFUNC (função indireta para realocação)
|
|
- Índice de **Seção** onde está localizado
|
|
- **Valor** (endereço na memória)
|
|
- **Tamanho**
|
|
|
|
## Seção Dinâmica
|
|
```
|
|
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
|
|
```
|
|
O diretório NEEDED indica que o programa **precisa carregar a biblioteca mencionada** para continuar. O diretório NEEDED é concluído uma vez que a **biblioteca compartilhada está totalmente operacional e pronta** para uso.
|
|
|
|
## Realocações
|
|
|
|
O carregador também deve realocar dependências após tê-las carregado. Essas realocações são indicadas na tabela de realocação nos formatos REL ou RELA e o número de realocações é fornecido nas seções dinâmicas RELSZ ou 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
|
|
```
|
|
### Relocações Estáticas
|
|
|
|
Se o **programa for carregado em um local diferente** do endereço preferido (geralmente 0x400000) porque o endereço já está em uso ou por causa de **ASLR** ou qualquer outro motivo, uma relocação estática **corrige ponteiros** que tinham valores esperando que o binário fosse carregado no endereço preferido.
|
|
|
|
Por exemplo, qualquer seção do tipo `R_AARCH64_RELATIV` deve ter modificado o endereço no deslocamento da relocação mais o valor do adendo.
|
|
|
|
### Relocações Dinâmicas e GOT
|
|
|
|
A relocação também pode fazer referência a um símbolo externo (como uma função de uma dependência). Como a função malloc da libC. Então, o carregador, ao carregar a libC em um endereço verificando onde a função malloc está carregada, escreverá este endereço na tabela GOT (Global Offset Table) (indicada na tabela de relocação) onde o endereço de malloc deve ser especificado.
|
|
|
|
### Tabela de Ligação de Procedimentos
|
|
|
|
A seção PLT permite realizar ligação tardia, o que significa que a resolução da localização de uma função será realizada na primeira vez que ela for acessada.
|
|
|
|
Portanto, quando um programa chama malloc, na verdade chama a localização correspondente de `malloc` na PLT (`malloc@plt`). Na primeira vez que é chamado, resolve o endereço de `malloc` e o armazena para que na próxima vez que `malloc` for chamado, esse endereço seja usado em vez do código PLT.
|
|
|
|
## Inicialização do Programa
|
|
|
|
Após o programa ser carregado, é hora de executá-lo. No entanto, o primeiro código que é executado **nem sempre é a função `main`**. Isso ocorre porque, por exemplo, em C++ se uma **variável global for um objeto de uma classe**, esse objeto deve ser **inicializado** **antes** da execução do main, como em:
|
|
```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;
|
|
}
|
|
```
|
|
Note que essas variáveis globais estão localizadas em `.data` ou `.bss`, mas nas listas `__CTOR_LIST__` e `__DTOR_LIST__`, os objetos a serem inicializados e destruídos são armazenados para acompanhamento.
|
|
|
|
A partir do código C, é possível obter o mesmo resultado usando as extensões GNU:
|
|
```c
|
|
__attributte__((constructor)) //Add a constructor to execute before
|
|
__attributte__((destructor)) //Add to the destructor list
|
|
```
|
|
Do ponto de vista do compilador, para executar essas ações antes e depois da função `main` ser executada, é possível criar uma função `init` e uma função `fini` que seriam referenciadas na seção dinâmica como **`INIT`** e **`FIN`** e são colocadas nas seções `init` e `fini` do ELF.
|
|
|
|
A outra opção, como mencionado, é referenciar as listas **`__CTOR_LIST__`** e **`__DTOR_LIST__`** nas entradas **`INIT_ARRAY`** e **`FINI_ARRAY`** na seção dinâmica e o comprimento destas é indicado por **`INIT_ARRAYSZ`** e **`FINI_ARRAYSZ`**. Cada entrada é um ponteiro de função que será chamado sem argumentos.
|
|
|
|
Além disso, também é possível ter um **`PREINIT_ARRAY`** com **ponteiros** que serão executados **antes** dos ponteiros do **`INIT_ARRAY`**.
|
|
|
|
### Ordem de Inicialização
|
|
|
|
1. O programa é carregado na memória, variáveis globais estáticas são inicializadas em **`.data`** e as não inicializadas são zeradas em **`.bss`**.
|
|
2. Todas as **dependências** do programa ou bibliotecas são **inicializadas** e o **linking dinâmico** é executado.
|
|
3. As funções **`PREINIT_ARRAY`** são executadas.
|
|
4. As funções **`INIT_ARRAY`** são executadas.
|
|
5. Se houver uma entrada **`INIT`**, ela é chamada.
|
|
6. Se for uma biblioteca, o dlopen termina aqui, se for um programa, é hora de chamar o **ponto de entrada real** (função `main`).
|
|
|
|
## Armazenamento Local de Threads (TLS)
|
|
|
|
São definidos usando a palavra-chave **`__thread_local`** em C++ ou a extensão GNU **`__thread`**.
|
|
|
|
Cada thread manterá um local único para essa variável, para que apenas a thread possa acessar sua variável.
|
|
|
|
Quando isso é usado, as seções **`.tdata`** e **`.tbss`** são usadas no ELF. Que são como `.data` (inicializado) e `.bss` (não inicializado) mas para TLS.
|
|
|
|
Cada variável terá uma entrada no cabeçalho TLS especificando o tamanho e o deslocamento TLS, que é o deslocamento que será usado na área de dados local da thread.
|
|
|
|
O `__TLS_MODULE_BASE` é um símbolo usado para se referir ao endereço base do armazenamento local de threads e aponta para a área na memória que contém todos os dados locais da thread de um módulo.
|