From c8a66c643afe2d0a2da55eac537b13a466c242c2 Mon Sep 17 00:00:00 2001 From: tzlil Date: Tue, 21 Mar 2023 12:56:39 +0200 Subject: reading section names --- src/structs.rs | 426 +++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 311 insertions(+), 115 deletions(-) (limited to 'src/structs.rs') diff --git a/src/structs.rs b/src/structs.rs index 850a47c..69ec14e 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -1,47 +1,65 @@ +use bitflags::bitflags; + #[repr(C, packed)] #[derive(Debug, Copy, Clone)] pub struct ElfIdent { - /// Magic number - 0x7F, then 'ELF' in ASCII - pub magic: [u8; 4], - - /// 1 = 32 bit, 2 = 64 bit - pub class: Class, + /// Magic number - 0x7F, then 'ELF' in ASCII + pub magic: [u8; 4], + + /// 1 = 32 bit, 2 = 64 bit + pub class: Class, - // 1 = little endian, 2 = big endian - pub data: Endian, + // 1 = little endian, 2 = big endian + pub data: Endian, - /// ELF header version - pub version: u8, + /// ELF header version + pub version: u8, - /// OS ABI - usually 0 for System V - pub OSABI: OSABI, + /// OS ABI - usually 0 for System V + pub OSABI: OSABI, - // This field is used to distinguish among incompatible versions of an ABI. - pub ABIVersion: u8, + // This field is used to distinguish among incompatible versions of an ABI. + pub ABIVersion: u8, - /// Unused/padding - pub _unused: [u8; 7], + /// Unused/padding + pub _unused: [u8; 7], } impl std::fmt::Display for ElfIdent { fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str(" Magic: "); - - for b in unsafe {*(std::ptr::addr_of!(self.magic) as *const [u8; 16])} { - formatter.pad(&format!("{:02x?} ", b)); + formatter.write_str(" Magic: ")?; + + for b in unsafe { *(std::ptr::addr_of!(self.magic) as *const [u8; 16]) } { + formatter.pad(&format!("{:02x?} ", b))?; } - formatter.write_str("\n"); - - formatter.write_fmt(format_args!(" Class: {:?}\n", self.class)); - formatter.write_fmt(format_args!(" Data: {}\n", self.data)); - formatter.write_fmt(format_args!(" Version: {} ({})\n", self.version, match self.version { - 0 => "invalid", - 1 => "current", - 2_u8..=u8::MAX => todo!(), // need to cover all cases - })); - formatter.write_fmt(format_args!(" OS/ABI: {}\n", self.OSABI)); - formatter.write_fmt(format_args!(" ABI Version: {}\n", self.ABIVersion)) + formatter.write_str("\n")?; + + formatter.write_fmt(format_args!( + " Class: {:?}\n", + self.class + ))?; + formatter.write_fmt(format_args!( + " Data: {}\n", + self.data + ))?; + formatter.write_fmt(format_args!( + " Version: {} ({})\n", + self.version, + match self.version { + 0 => "invalid", + 1 => "current", + 2_u8..=u8::MAX => todo!(), // need to cover all cases + } + ))?; + formatter.write_fmt(format_args!( + " OS/ABI: {}\n", + self.OSABI + ))?; + formatter.write_fmt(format_args!( + " ABI Version: {}\n", + self.ABIVersion + )) } } @@ -51,153 +69,331 @@ impl std::fmt::Display for ElfIdent { #[repr(C)] #[derive(Debug)] pub struct ElfHeader { - pub ident: ElfIdent, + pub ident: ElfIdent, + + /// 1 = relocatable, 2 = executable, 3 = shared, 4 = core + pub r#type: Type, + + /// Instruction set - see table below + pub machine: Machine, - /// 1 = relocatable, 2 = executable, 3 = shared, 4 = core - pub r#type: Type, - - /// Instruction set - see table below - pub machine: Machine, + /// ELF Version + pub version: u32, - /// ELF Version - pub version: u32, + /// Program entry position (virtual) + pub entry: u64, - /// Program entry position (virtual) - pub entry: u64, + /// Program header table position (bytes into file) + pub phoff: u64, - /// Program header table position (bytes into file) - pub phoff: u64, + /// Section header table position (bytes into file) + pub shoff: u64, - /// Section header table position (bytes into file) - pub shoff: u64, + /// This member holds processor-specific flags associated with the file + /// Currently, no flags have been defined. + pub flags: u32, - /// This member holds processor-specific flags associated with the file - /// Currently, no flags have been defined. - pub flags: u32, + /// Header size + pub ehsize: u16, - /// Header size - pub ehsize: u16, + /// Size of an entry in the program header table + pub phentsize: u16, - /// Size of an entry in the program header table - pub phentsize: u16, + /// Number of entries in the program header table + pub phnum: u16, - /// Number of entries in the program header table - pub phnum: u16, + /// Size of an entry in the section header table + pub shentsize: u16, - /// Size of an entry in the section header table - pub shentsize: u16, + /// Number of entries in the section header table + pub shnum: u16, - /// Number of entries in the section header table - pub shnum: u16, - - /// Index in section header table with the section names - pub shstrndx: u16, + /// Index in section header table with the section names + pub shstrndx: u16, } impl std::fmt::Display for ElfHeader { fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - // yes, this is really what they do in readelf.c - formatter.write_fmt(format_args!("{}", self.ident)); - formatter.write_fmt(format_args!(" Type: {}\n", self.r#type)); - formatter.write_fmt(format_args!(" Machine: {}\n", self.machine)); - formatter.write_fmt(format_args!(" Version: {:#02x?}\n", self.version)); - formatter.write_fmt(format_args!(" Entry point address: {:#x?}\n", self.entry)); - formatter.write_fmt(format_args!(" Start of program headers: {} (bytes into file)\n", self.phoff)); - formatter.write_fmt(format_args!(" Start of section headers: {} (bytes into file)\n", self.shoff)); - formatter.write_fmt(format_args!(" Flags: {:#x?}\n", self.flags)); - formatter.write_fmt(format_args!(" Size of this header: {} (bytes)\n", self.ehsize)); - formatter.write_fmt(format_args!(" Size of program headers: {} (bytes)\n", self.phentsize)); - formatter.write_fmt(format_args!(" Number of program headers: {}\n", self.phnum)); - formatter.write_fmt(format_args!(" Size of section headers: {} (bytes)\n", self.shentsize)); - formatter.write_fmt(format_args!(" Number of section headers: {}\n", self.shnum)); - formatter.write_fmt(format_args!(" Section header string table index: {}\n", self.shstrndx)) + // yes, this is really what they do in readelf.c + formatter.write_fmt(format_args!("{}", self.ident))?; + formatter.write_fmt(format_args!( + " Type: {}\n", + self.r#type + ))?; + formatter.write_fmt(format_args!( + " Machine: {}\n", + self.machine + ))?; + formatter.write_fmt(format_args!( + " Version: {:#02x?}\n", + self.version + ))?; + formatter.write_fmt(format_args!( + " Entry point address: {:#x?}\n", + self.entry + ))?; + formatter.write_fmt(format_args!( + " Start of program headers: {} (bytes into file)\n", + self.phoff + ))?; + formatter.write_fmt(format_args!( + " Start of section headers: {} (bytes into file)\n", + self.shoff + ))?; + formatter.write_fmt(format_args!( + " Flags: {:#x?}\n", + self.flags + ))?; + formatter.write_fmt(format_args!( + " Size of this header: {} (bytes)\n", + self.ehsize + ))?; + formatter.write_fmt(format_args!( + " Size of program headers: {} (bytes)\n", + self.phentsize + ))?; + formatter.write_fmt(format_args!( + " Number of program headers: {}\n", + self.phnum + ))?; + formatter.write_fmt(format_args!( + " Size of section headers: {} (bytes)\n", + self.shentsize + ))?; + formatter.write_fmt(format_args!( + " Number of section headers: {}\n", + self.shnum + ))?; + formatter.write_fmt(format_args!( + " Section header string table index: {}\n", + self.shstrndx + )) } } #[derive(Debug, Copy, Clone)] #[repr(u16)] pub enum Type { - None = 0, - Rel = 1, - Exec = 2, - Dyn = 3, - Core = 4, + None = 0, + Rel = 1, + Exec = 2, + Dyn = 3, + Core = 4, } impl std::fmt::Display for Type { fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - Type::None => formatter.write_str("NONE (None)"), - Type::Rel => formatter.write_str("REL (Relocatable file)"), - Type::Exec => formatter.write_str("EXEC (Executable file)"), - Type::Dyn => formatter.write_str("DYN (Shared object file)"), - Type::Core => formatter.write_str("CORE (Core file)"), - } + Type::None => formatter.write_str("NONE (None)"), + Type::Rel => formatter.write_str("REL (Relocatable file)"), + Type::Exec => formatter.write_str("EXEC (Executable file)"), + Type::Dyn => formatter.write_str("DYN (Shared object file)"), + Type::Core => formatter.write_str("CORE (Core file)"), + } } } #[derive(Debug, Copy, Clone)] #[repr(u16)] pub enum Machine { - // there are many many many more, im just gonna do x86 - // https://github.com/bminor/binutils-gdb/blob/master/binutils/readelf.c#L2746 - None = 1, - X86_64 = 62, + // there are many many many more, im just gonna do x86 + // https://github.com/bminor/binutils-gdb/blob/master/binutils/readelf.c#L2746 + None = 1, + X86_64 = 62, } impl std::fmt::Display for Machine { fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - Machine::None => formatter.write_str("None"), - Machine::X86_64 => formatter.write_str("Advanced Micro Devices X86-64"), - } + Machine::None => formatter.write_str("None"), + Machine::X86_64 => formatter.write_str("Advanced Micro Devices X86-64"), + } } } - #[derive(Debug, Copy, Clone)] #[repr(u8)] pub enum Class { - ELF32 = 1, - ELF64 = 2, + ELF32 = 1, + ELF64 = 2, } #[derive(Debug, Copy, Clone)] #[repr(u8)] pub enum OSABI { - None = 0x00, - SystemV = 0x01, - // HPUX = 0x02, - // Solaris = 0x03, - // IRIX = 0x04, - // FreeBSD = 0x05, - // TRU64 = 0x06, - // ARM = 0x07, - Standalone = 0x08, + None = 0x00, + SystemV = 0x01, + // HPUX = 0x02, + // Solaris = 0x03, + // IRIX = 0x04, + // FreeBSD = 0x05, + // TRU64 = 0x06, + // ARM = 0x07, + Standalone = 0x08, } impl std::fmt::Display for OSABI { fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - OSABI::None => formatter.write_str("UNIX - System V"), - OSABI::SystemV => formatter.write_str("UNIX - System V"), - OSABI::Standalone => formatter.write_str("Standalone"), - } + OSABI::None => formatter.write_str("UNIX - System V"), + OSABI::SystemV => formatter.write_str("UNIX - System V"), + OSABI::Standalone => formatter.write_str("Standalone"), + } } } #[derive(Debug, Copy, Clone)] #[repr(u8)] pub enum Endian { - Little = 1, - Big = 2, + Little = 1, + Big = 2, } impl std::fmt::Display for Endian { fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - Endian::Little => formatter.write_str("2's complement, little endian"), - Endian::Big => formatter.write_str("1's complement, big endian"), - } + Endian::Little => formatter.write_str("2's complement, little endian"), + Endian::Big => formatter.write_str("1's complement, big endian"), + } + } +} + +#[derive(Debug, Copy, Clone)] +#[repr(C)] +pub struct ElfSectionHeader { + /* This member specifies the name of the section. Its value + is an index into the section header string table section, + giving the location of a null-terminated string. */ + pub name: u32, + /* This member categorizes the section's contents and + semantics. */ + pub r#type: ElfSectionType, + + /* Sections support one-bit flags that describe miscellaneous + attributes. If a flag bit is set in sh_flags, the + attribute is "on" for the section. Otherwise, the + attribute is "off" or does not apply. Undefined + attributes are set to zero. */ + pub flags: ElfSectionFlags, + + /* If this section appears in the memory image of a process, + this member holds the address at which the section's first + byte should reside. Otherwise, the member contains zero. */ + pub addr: u64, + + /* This member's value holds the byte offset from the + beginning of the file to the first byte in the section. + One section type, SHT_NOBITS, occupies no space in the + file, and its sh_offset member locates the conceptual + placement in the file. */ + pub offset: u64, + + /* This member holds the section's size in bytes. Unless the + section type is SHT_NOBITS, the section occupies sh_size + bytes in the file. A section of type SHT_NOBITS may have + a nonzero size, but it occupies no space in the file. */ + pub size: u64, + + /* This member holds a section header table index link, whose + interpretation depends on the section type. */ + pub link: u32, + + /* This member holds extra information, whose interpretation + depends on the section type. */ + pub info: u32, + + /* Some sections have address alignment constraints. If a + section holds a doubleword, the system must ensure + doubleword alignment for the entire section. That is, the + value of sh_addr must be congruent to zero, modulo the + value of sh_addralign. Only zero and positive integral + powers of two are allowed. The value 0 or 1 means that + the section has no alignment constraints. */ + pub addralign: u64, + + /* Some sections hold a table of fixed-sized entries, such as + a symbol table. For such a section, this member gives the + size in bytes for each entry. This member contains zero + if the section does not hold a table of fixed-size + entries. */ + pub entsize: u64, +} + +#[derive(Debug, Copy, Clone)] +#[repr(u32)] +pub enum ElfSectionType { + /* This value marks the section header as inactive. + It does not have an associated section. Other + members of the section header have undefined + values. */ + Null = 0, + + /* This section holds information defined by the + program, whose format and meaning are determined + solely by the program. */ + ProgBits = 1, + + /* This section holds a symbol table. Typically, + SHT_SYMTAB provides symbols for link editing, + though it may also be used for dynamic linking. As + a complete symbol table, it may contain many + symbols unnecessary for dynamic linking. An object + file can also contain a SHT_DYNSYM section. */ + SymTab = 2, + + /* This section holds a string table. An object file + may have multiple string table sections. */ + StrTab = 3, + + /* This section holds relocation entries with explicit + addends, such as type Elf32_Rela for the 32-bit + class of object files. An object may have multiple + relocation sections. */ + Rela = 4, + + /* This section holds a symbol hash table. An object + participating in dynamic linking must contain a + symbol hash table. An object file may have only + one hash table. */ + Hash = 5, + + /* This section holds information for dynamic linking. + An object file may have only one dynamic section. */ + Dynamic = 6, + + /* This section holds notes (ElfN_Nhdr). */ + Note = 7, + + /* A section of this type occupies no space in the + file but otherwise resembles SHT_PROGBITS. + Although this section contains no bytes, the + sh_offset member contains the conceptual file + offset. */ + NoBits = 8, + + /* This section holds relocation offsets without + explicit addends, such as type Elf32_Rel for the + 32-bit class of object files. An object file may + have multiple relocation sections. */ + Rel = 9, + + /* This section is reserved but has unspecified + semantics. */ + ShLib = 10, + + /* This section holds a minimal set of dynamic linking + symbols. An object file can also contain a + SHT_SYMTAB section. */ + DynSym = 11, + + GnuHash = 0x6FFFFFF6, +} + +bitflags! { + #[derive(Debug, Copy, Clone)] + pub struct ElfSectionFlags: u64 { + const WRITE = 0x1; + const ALLOC = 0x2; + const EXEC = 0x4; } -} \ No newline at end of file +} -- cgit 1.4.1