# 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