draugr~ single ELF file analysis tool |
| git clone https://github.com/djnnvx/draugr.git |
| log | files | refs | archive | README |
elf.odin (6104B)
1 package elf 2 3 import "core:encoding/endian" 4 import "core:fmt" 5 6 ELF_MAGIC :: [4]u8{0x7f, 'E', 'L', 'F'} 7 8 ELF_CLASS_32 :: 1 9 ELF_CLASS_64 :: 2 10 11 ELF_DATA_LSB :: 1 12 ELF_DATA_MSB :: 2 13 14 ET_REL :: 1 15 ET_EXEC :: 2 16 ET_DYN :: 3 17 ET_CORE :: 4 18 19 EM_SPARC :: 2 20 EM_386 :: 3 21 EM_68K :: 4 22 EM_MIPS :: 8 23 EM_MIPS_RS3_LE :: 10 24 EM_PARISC :: 15 25 EM_PPC :: 20 26 EM_PPC64 :: 21 27 EM_S390 :: 22 28 EM_ARM :: 40 29 EM_SH :: 42 30 EM_SPARCV9 :: 43 31 EM_ARC :: 45 32 EM_IA_64 :: 50 33 EM_X86_64 :: 62 34 EM_CRIS :: 76 35 EM_AVR :: 83 36 EM_FR30 :: 84 37 EM_V850 :: 87 38 EM_M32R :: 88 39 EM_OPENRISC :: 92 40 EM_ARC_COMPACT :: 93 41 EM_XTENSA :: 94 42 EM_MSP430 :: 105 43 EM_BLACKFIN :: 106 44 EM_UNICORE :: 110 45 EM_TI_C6000 :: 140 46 EM_NDS32 :: 167 47 EM_AARCH64 :: 183 48 EM_MICROBLAZE :: 189 49 EM_TILEGX :: 191 50 EM_ARC_COMPACT2 :: 195 51 EM_RISCV :: 243 52 EM_BPF :: 247 53 EM_CSKY :: 252 54 EM_LOONGARCH :: 258 55 56 PT_NULL :: 0 57 PT_LOAD :: 1 58 PT_DYNAMIC :: 2 59 PT_INTERP :: 3 60 PT_NOTE :: 4 61 PT_SHLIB :: 5 62 PT_PHDR :: 6 63 PT_TLS :: 7 64 PT_GNU_EH_FRAME :: 0x6474e550 65 PT_GNU_STACK :: 0x6474e551 66 PT_GNU_RELRO :: 0x6474e552 67 PT_GNU_PROPERTY :: 0x6474e553 68 69 PF_X :: 1 70 PF_W :: 2 71 PF_R :: 4 72 73 SHF_WRITE :: 1 74 SHF_ALLOC :: 2 75 SHF_EXECINSTR :: 4 76 77 SHT_NULL :: 0 78 SHT_PROGBITS :: 1 79 SHT_SYMTAB :: 2 80 SHT_STRTAB :: 3 81 SHT_RELA :: 4 82 SHT_HASH :: 5 83 SHT_DYNAMIC :: 6 84 SHT_NOTE :: 7 85 SHT_NOBITS :: 8 86 SHT_REL :: 9 87 SHT_SHLIB :: 10 88 SHT_DYNSYM :: 11 89 SHT_INIT_ARRAY :: 14 90 SHT_FINI_ARRAY :: 15 91 SHT_PREINIT_ARRAY :: 16 92 SHT_GROUP :: 17 93 SHT_SYMTAB_SHNDX :: 18 94 SHT_RELR :: 19 95 SHT_GNU_ATTRIBUTES :: 0x6ffffff5 96 SHT_GNU_HASH :: 0x6ffffff6 97 SHT_GNU_VERDEF :: 0x6ffffffd 98 SHT_GNU_VERNEED :: 0x6ffffffe 99 SHT_GNU_VERSYM :: 0x6fffffff 100 101 SHN_UNDEF :: 0 102 SHN_XINDEX :: 0xFFFF 103 PN_XNUM :: 0xFFFF 104 105 STB_LOCAL :: 0 106 STB_GLOBAL :: 1 107 STB_WEAK :: 2 108 109 STT_NOTYPE :: 0 110 STT_OBJECT :: 1 111 STT_FUNC :: 2 112 STT_SECTION :: 3 113 STT_FILE :: 4 114 115 ELF_Header :: struct { 116 class : u8, 117 data : u8, 118 osabi : u8, 119 type : u16, 120 machine : u16, 121 entry : u64, 122 phoff : u64, 123 shoff : u64, 124 phentsize : u16, 125 phnum : u16, 126 shentsize : u16, 127 shnum : u16, 128 shstrndx : u16, 129 flags : u32, 130 } 131 132 Program_Header :: struct { 133 type : u32, 134 flags : u64, 135 offset : u64, 136 vaddr : u64, 137 paddr : u64, 138 filesz : u64, 139 memsz : u64, 140 align : u64, 141 } 142 143 Section_Header :: struct { 144 name : u32, 145 type : u32, 146 flags : u64, 147 addr : u64, 148 offset : u64, 149 size : u64, 150 link : u32, 151 info : u32, 152 addralign : u64, 153 entsize : u64, 154 } 155 156 Symbol :: struct { 157 name : string, 158 value : u64, 159 size : u64, 160 bind : u8, 161 type : u8, 162 shndx : u16, 163 } 164 165 ELF_Info :: struct { 166 header : ELF_Header, 167 program_hdrs : [dynamic]Program_Header, 168 section_hdrs : [dynamic]Section_Header, 169 symbols : [dynamic]Symbol, 170 dyn_symbols : [dynamic]Symbol, 171 dyn_entries : [dynamic]Dyn_Entry, 172 needed : [dynamic]string, 173 relocs : [dynamic]Reloc, 174 soname : string, 175 rpath : string, 176 runpath : string, 177 is_64bit : bool, 178 is_pie : bool, 179 is_dynamic : bool, 180 interp_offset : u64, 181 shstrtab : []u8, 182 strtab : []u8, 183 dynstr : []u8, 184 } 185 186 // Overflow-safe: no addition that can wrap. 187 in_bounds :: proc(data: []u8, offset: u64, size: u64) -> bool { 188 return offset <= u64(len(data)) && size <= u64(len(data)) - offset 189 } 190 191 Byte_Order :: endian.Byte_Order 192 193 byte_order :: proc(header: ELF_Header) -> Byte_Order { 194 return .Little if header.data == ELF_DATA_LSB else .Big 195 } 196 197 // Out-of-range reads yield 0 rather than faulting; ELF fields are untrusted. 198 read_u16 :: proc(data: []u8, offset: int, order: Byte_Order) -> u16 { 199 if offset < 0 || offset + 2 > len(data) { return 0 } 200 v, _ := endian.get_u16(data[offset:offset + 2], order) 201 return v 202 } 203 204 read_u32 :: proc(data: []u8, offset: int, order: Byte_Order) -> u32 { 205 if offset < 0 || offset + 4 > len(data) { return 0 } 206 v, _ := endian.get_u32(data[offset:offset + 4], order) 207 return v 208 } 209 210 read_u64 :: proc(data: []u8, offset: int, order: Byte_Order) -> u64 { 211 if offset < 0 || offset + 8 > len(data) { return 0 } 212 v, _ := endian.get_u64(data[offset:offset + 8], order) 213 return v 214 } 215 216 probe :: proc(data: []u8) -> bool { 217 if len(data) < 16 { return false } 218 if data[0] != ELF_MAGIC[0] { return false } 219 if data[1] != ELF_MAGIC[1] { return false } 220 if data[2] != ELF_MAGIC[2] { return false } 221 if data[3] != ELF_MAGIC[3] { return false } 222 return true 223 } 224 225 parse_header :: proc(data: []u8) -> (ELF_Header, string) { 226 header: ELF_Header 227 228 if len(data) < 16 { 229 return header, "Data too small" 230 } 231 232 if !probe(data) { 233 return header, "Invalid ELF magic" 234 } 235 236 header.class = data[4] 237 header.data = data[5] 238 header.osabi = data[7] 239 240 is_64bit := header.class == ELF_CLASS_64 241 order := byte_order(header) 242 243 if !is_64bit { 244 if header.class != ELF_CLASS_32 { 245 return header, fmt.tprintf("Unknown ELF class: %d", header.class) 246 } 247 } 248 249 header.type = read_u16(data, 16, order) 250 header.machine = read_u16(data, 18, order) 251 252 if is_64bit { 253 header.entry = read_u64(data, 24, order) 254 header.phoff = read_u64(data, 32, order) 255 header.shoff = read_u64(data, 40, order) 256 header.flags = read_u32(data, 48, order) 257 header.phentsize = read_u16(data, 54, order) 258 header.phnum = read_u16(data, 56, order) 259 header.shentsize = read_u16(data, 58, order) 260 header.shnum = read_u16(data, 60, order) 261 header.shstrndx = read_u16(data, 62, order) 262 } else { 263 header.entry = u64(read_u32(data, 24, order)) 264 header.phoff = u64(read_u32(data, 28, order)) 265 header.shoff = u64(read_u32(data, 32, order)) 266 header.flags = read_u32(data, 36, order) 267 header.phentsize = read_u16(data, 42, order) 268 header.phnum = read_u16(data, 44, order) 269 header.shentsize = read_u16(data, 46, order) 270 header.shnum = read_u16(data, 48, order) 271 header.shstrndx = read_u16(data, 50, order) 272 } 273 274 return header, "" 275 }