# ELF deep look
###### tags: `pwn 👻`
---
## tool
- `readelf`
- `-h`: file header
![](https://i.imgur.com/7SQtlHq.png)
- `-S`: section header (= `objdump -h <file>`)
![](https://i.imgur.com/kXIU3lB.jpg)
- `-s`: symbol (dynsym & symtab) (= `nm <file>`)
![](https://i.imgur.com/S5ICzPS.png)
![](https://i.imgur.com/YvPIKPQ.png)
- `-r`: show relocs
![Uploading file..._dss2jcm37]()
---
## elf
> executable linkable format, 為 linux 下的可執行檔
可以用 `readelf -s <file>` 查看
- 分成:
1. relocatable file: 包含 code & data 的檔案, 用來連結形成 resulting file or shared object (.o .a)
2. executable file: 可以直接執行 (無副檔名)
3. shared object file: 包含 code & data 的檔案, (.so) 在兩種情況下使用:
1. linker 用來與其他 relocatable file, shared object file 組成新的 shared object file
2. dynamic linking, map 到 memory 中給各 process 共享
4. core dump file: process 意外終止時的紀錄檔
- 用 `file` 可查看其特性
```c
typedef struct {
unsigned char e_ident[16]; // magic, class, ABI version...
Elf32_Half e_type; // ex. rel (relocatable file)
Elf32_Half e_machine; // ex. intel80386
Elf32_Word e_version; // 1 generally
Elf32_Addr e_entry; // exec: _start, rel: 0x0
Elf32_Off e_phoff; // start of program headers
Elf32_Off e_shoff; // start of section headers
Elf32_Word e_flags; // some flag
Elf32_Half e_ehsize; // size of this header, elf header 本身大小
Elf32_Half e_phentsize; // size of program headers
Elf32_Half e_phnum; // number of program headers
Elf32_Half e_shentsize; // size of section headers
Elf32_Half e_shnum; // number of section headers
Elf32_Half e_shstrndx; // section header string table index
} Elf32_Ehdr;
```
---
### symbol
> 由 compiler 產生, 目的是讓 linker 可以將不同的 obj, 其 function & variable & others 可以 relocate 至 resulting file
可以用 `readelf -s <file>` 查看
- 分成兩種
1. `dynsym`: 只含 global symbols 的 symtab 子集合
2. `symtab`: 包含所有 non-allocable section 的 section info
```c
typedef struct {
Elf32_Word st_name;
Elf32_Word st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other; // 0, no use
Elf32_Half st_shndx;
} Elf32_Sym;
```
- `st_info`:
- second 4 bit for symbol type
1. `local`: 0, local symbol, 外部不可見
2. `global`: 1, 全域, 外部可見
3. `weak`: 2, 弱引用 (未定義仍能使用)
- first 28 bit for symbol binding
1. `notype`: 0, unknown type symbol
2. `object`: 1, variable, arr 等物件
3. `func`: 2, function or code
4. `section`: 3, 為 section, type 皆為 `local`
5. `file`: 檔案名稱, type 皆為 `local`, `shndx` 必為 abs
- `st_shndx`:
1. value: 對應到的 section header index, 沒對應到的話則該 symbol 為外部定義 or 為特殊符號
2. `abs`: 0xfff1, 一絕對值 (ex. file name symbol)
3. `common`: 0xfff2, 未初始化的 global symbol
4. `undef`: 0, symbol 未定義
- `st_value`:
1. `st_shndx` 非 `common`, 則 `st_value` 代表 section offset
2. 反之即為 symbol 的 alignment attribute
* 弱符號 & 強符號
- 強符號: 不能被重複定義的 symbol
- 弱符號: 可以被重複定義的 symbol, ex. 為未初始化的 variable. 因為其尚未被 assign value, 在生成 resulting file 之前, 其 var type 仍能更改, 所以可以被當作**弱符號**
---
### section
> 將不同種類的 info 分成多個 section, 能根據 info 的特性去限制 memory 使用權限, 或是在多個副本可以 shared 部分 section
- sections 分成
1. runtime used, 又稱 allocable section (ex. code, data)
2. needed by linker, debuger..., 又稱 non-allocable section
- 當 ELF 被執行後, 只有 allocable section 會被 map 到 memory 裡
- `strip` 可以 remove non-allocable section, 使 ELF file size 減少, 因為他們只會在 debug 或其他特定情況才會使用到
- 在沒有 dynamic linking 之前, 只有 non-allocable section (symtab)
- `.data`: 已初始化的 global or static variable
- `.text`: 程式碼片段
- `.bss`: 未初始化的 global or static variable (or 初始化值為 0)
- `.rodata`: read only data, 像是 `printf("%d");` 的 `"%d"` 即是 rodata, 不可修改
- `.comment`: 編譯器版本資訊
- `.note.GNU-stack`: stack 提示 section
- `.strtab`: 字串表
- 用來放普通的 string
- 內部存放連續的 string, 以 `\0` 隔開, 透過 offset 即可存取特定 string
- `.shstrtab`: section string table
- 用來放 section name string
- 同 `.strtab`
- `.symtab`: symbol table
- `.plt`: procedure linkage table
- `.init`: initial code
- `.fini`: finish code
- `.dynamic`: dynamic linking info
- **`.rel.plt`: relocate function**
- **`.rel.dyn`: relocate variable**
- **`.got`: global variable offset**
- **`.got.plt`: global function offset**
- `.dynsym`: dynamic linking symbol
- `.dynstr`: dynamic linking string
* for more
* `.rel.dyn` corresponds to `R_386_GLOB_DAT`, which is global data
* `.rel.plt` corresponds to `R_386_JUMP_SLOT`, which is function
![](https://i.imgur.com/kwFYz5L.png)
#### dynamic section struct
> .dynamic section
可以用 `readelf -d <file>` 查看
![](https://i.imgur.com/lv0Khcd.png)
```c
typedef struct {
Elf32_Sword d_tag;
union {
Elf32_Word d_val;
Elf32_Addr d_ptr;
} d_un;
} Elf32_Dyn;
```
- `d_tag`:
1. `symtab`: dynamic linking symbol table address (.dynsym)
2. `strtab`: dynamic linking string table address (.dynstr)
3. `strsz`: dynamic linking string table size
4. `hash`: dynamic linking hash table address
5. `soname`
6. `rpath`
7. `init`: initial code address
8. `finit`: finish code address
9. `need`: shared object name
10. `rel`: .rel.dyn address (for variable)
11. `jmprel`: .rel.plt address (for function)
12. `relent`: .rel.dyn entry + .rel.plt entry
#### relocable section struct
> .rel.plt, .rel.dyn section
可以用 `readelf -r <file>` 查看
![](https://i.imgur.com/yeTEPid.png)
![](https://i.imgur.com/Hl7l8qA.png)
```c
typedef struct {
Elf32_Addr r_offset;
// target offset (ex. lazy binding 時, .rel.plt 內的 offset 即是 func@got 的 address)
Elf32_Word r_info;
// first 3 bytes for reloc symbol index in symbol table (.dynsym 的 num)
// last 1 byte for reloc type
} Elf32_Rel;
#define ELF32_R_SYM(r_info) (r_info >> 8)
#define ELF32_R_TYPE(r_info) (r_info & 0xff)
```
#### got section
- `.got.plt` 前三項:
1. `.dynamic` section address
2. module ID
3. `<_dl_runtime_resolve>` 的 address
#### symbol section struct
> .dynsym .sym section struct
`readelf --dyn-syms <file>` ==> .dynsym
`readelf -s <file>` ==> .dynsym + .symtab
![](https://i.imgur.com/0dCsvm4.png)
```c
typedef struct {
Elf32_Word st_name; // 在 .strtab or .dynstr 的 offset
Elf32_Word st_value;
Elf32_Word st_size;
unsigned char st_info; // symbol type and binding
unsigned char st_other;
Elf32_Half st_shndx;
} Elf32_Sym;
```
- A reloc entry `rel`:
- `ELF32_R_SYM(rel->r_info)`: rel 在 dynamic symbol table(.dynsym) 的 index
- rel entry 在 `.dynsym` 皆有 num 可以對應
- `.dynsym` address(ex. 0x080481d8) + `.dynsym` entry size(ex. 0x10) * index: rel 其 symbol struct info, 我們假設他為 `rel_sym`
- `rel_sym` first 8 bytes 為 st_name, value 為其在 `.strtab` 的 offset
- `rel_sym->st_name` + `.dynstr`: 為該 rel_sym 的 string name
---
### section header
> 紀錄 section 的各種 info, 如 size, name, offset 等等
可以用 `readelf -S <file>` 查看
**section header table**: 紀錄各個 section header 的一個 section
```c
typedef struct {
Elf32_Word sh_name;
// section name 為一字串, 存在 .shstrtab 字串表
// sh_name 存該 section name 字串在 .shstrtab 字串表的 offset
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset; // section 在 elf file 中的 offset
Elf32_Word sh_size; // section size
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize; // section entry size
} Elf32_Shdr;
```
- `sh_type`:
1. `NULL`: 無效區段
2. `PROGBITS`: 程式區段(.text, .data...)
3. `SYMTAB`: symbol table 符號表
4. `STRTAB`: string table 字串表
5. `RELA`: relocation table
6. `HASH`: symbol table hash
7. `DYNAMIC`: dynamic linking info
8. `NOTE`: 提示性 info
9. `NOBITS`: no content (ex. .bss)
10. `REL`: relocation info
11. `SHLIB`: 保留
12. `DYNSYM`: dynamic linking symbol table
- `sh_flags`:
1. `WRITE`: 1, 可寫
2. `ALLOC`: 2, 該 section 需分配空間
3. `EXECINSTR`: 4, 可執行 section