From 490944150c0f42dc53e0c30f2d97e9b19beb6b6e Mon Sep 17 00:00:00 2001 From: Nicolas Mazzon Date: Tue, 16 Apr 2024 17:45:05 +0200 Subject: [PATCH] More datastructures. --- binformat/src/elf.rs | 146 ++++++++++++++++++++++++++++++++++-- binformat/src/lib.rs | 26 +++++-- binformat/src/pe.rs | 2 - processor/src/blocks.rs | 82 +++++++++++++++++--- processor_shared/src/lib.rs | 8 ++ 5 files changed, 238 insertions(+), 26 deletions(-) diff --git a/binformat/src/elf.rs b/binformat/src/elf.rs index 96042c9..8452849 100644 --- a/binformat/src/elf.rs +++ b/binformat/src/elf.rs @@ -1,4 +1,5 @@ -use crate::RawSymbol; +use std::fmt; +use crate::{datastructure, RawSymbol}; use processor_shared::{AddressMap, Addressed, Section, SectionKind}; use object::elf; use object::read::elf::{ElfFile, FileHeader, SectionHeader}; @@ -144,7 +145,7 @@ fn parse_sections<'data, Elf: FileHeader>(obj: &'data ElfFile<'data, Elf>) -> Ve // Program data. elf::SHT_PROGBITS => (SectionKind::Raw, "PROGBITS"), // Symbol table. - elf::SHT_SYMTAB => (SectionKind::Raw, "SYMTAB"), // array of Elf64_Sym + elf::SHT_SYMTAB => (SectionKind::Raw, "SYMTAB"), // String table. elf::SHT_STRTAB => (SectionKind::CString, "STRTAB"), // Relocation entries with explicit addends. @@ -152,17 +153,25 @@ fn parse_sections<'data, Elf: FileHeader>(obj: &'data ElfFile<'data, Elf>) -> Ve // Symbol hash table. elf::SHT_HASH => (SectionKind::Raw, "HASH"), // Dynamic linking information. - elf::SHT_DYNAMIC => (SectionKind::Raw, "DYNAMIC"), // array of Elf64_Dyn + elf::SHT_DYNAMIC => if obj.is_64() { + (SectionKind::Elf64Dyn, "DYNAMIC") + } else { + (SectionKind::Elf32Dyn, "DYNAMIC") + }, // Notes. elf::SHT_NOTE => (SectionKind::Raw, "NOTE"), // Program space with no data (bss). elf::SHT_NOBITS => (SectionKind::Raw, "NOBITS"), // Relocation entries without explicit addends. - elf::SHT_REL => (SectionKind::Raw, "REL"), // array of Elf64_Dyn + elf::SHT_REL => (SectionKind::Raw, "REL"), // Reserved section type. elf::SHT_SHLIB => (SectionKind::Raw, "SHLIB"), // Dynamic linker symbol table. - elf::SHT_DYNSYM => (SectionKind::Raw, "DYNSYM"), + elf::SHT_DYNSYM => if obj.is_64() { + (SectionKind::Elf64Sym, "DYNSYM") + } else { + (SectionKind::Elf32Sym, "DYNSYM") + }, // Array of constructors. elf::SHT_INIT_ARRAY => (SectionKind::Raw, "INIT_ARRAY"), // Array of destructors. @@ -250,3 +259,130 @@ fn parse_sections<'data, Elf: FileHeader>(obj: &'data ElfFile<'data, Elf>) -> Ve sections } + +#[repr(u64)] +#[allow(non_camel_case_types)] +#[derive(Copy, Clone, Debug)] +pub enum DynTag { + DT_NULL = 0x0, + DT_NEEDED = 0x1, + DT_PLTRELSZ = 0x2, + DT_PLTGOT = 0x3, + DT_HASH = 0x4, + DT_STRTAB = 0x5, + DT_SYMTAB = 0x6, + DT_RELA = 0x7, + DT_RELASZ = 0x8, + DT_RELAENT = 0x9, + DT_STRSZ = 0xa, + DT_SYMENT = 0xb, + DT_INIT = 0xc, + DT_FINI = 0xd, + DT_SONAME = 0xe, + DT_RPATH = 0xf, + DT_SYMBOLIC = 0x10, + DT_REL = 0x11, + DT_RELSZ = 0x12, + DT_RELENT = 0x13, + DT_PLTREL = 0x14, + DT_DEBUG = 0x15, + DT_TEXTREL = 0x16, + DT_JMPREL = 0x17, + DT_BIND_NOW = 0x18, + DT_INIT_ARRAY = 0x19, + DT_FINI_ARRAY = 0x1a, + DT_INIT_ARRAYSZ = 0x1b, + DT_FINI_ARRAYSZ = 0x1c, + DT_RUNPATH = 0x1d, + DT_FLAGS = 0x1e, + DT_ENCODING = 0x1f, + DT_PREINIT_ARRAY = 0x20, + DT_PREINIT_ARRAYSZ = 0x21, + DT_LOOS = 0x6000000d, + DT_SUNW_RTLDINF = 0x6000000e, + DT_HIOS = 0x6ffff000, + DT_VALRNGLO = 0x6ffffd00, + DT_CHECKSUM = 0x6ffffdf8, + DT_PLTPADSZ = 0x6ffffdf9, + DT_MOVEENT = 0x6ffffdfa, + DT_MOVESZ = 0x6ffffdfb, + DT_FEATURE_1 = 0x6ffffdfc, + DT_POSFLAG_1 = 0x6ffffdfd, + DT_SYMINSZ = 0x6ffffdfe, + DT_SYMINENT = 0x6ffffdff, + DT_ADDRRNGLO = 0x6ffffe00, + DT_GNU_HASH = 0x6ffffef5, + DT_CONFIG = 0x6ffffefa, + DT_DEPAUDIT = 0x6ffffefb, + DT_AUDIT = 0x6ffffefc, + DT_PLTPAD = 0x6ffffefd, + DT_MOVETAB = 0x6ffffefe, + DT_SYMINFO = 0x6ffffeff, + DT_RELACOUNT = 0x6ffffff9, + DT_RELCOUNT = 0x6ffffffa, + DT_FLAGS_1 = 0x6ffffffb, + DT_VERDEF = 0x6ffffffc, + DT_VERDEFNUM = 0x6ffffffd, + DT_VERNEED = 0x6ffffffe, + DT_VERNEEDNUM = 0x6fffffff, + DT_VERSYM = 0x6ffffff0, + DT_MIPS_RLD_VERSION = 0x70000001, + DT_MIPS_TIME_STAMP = 0x70000002, + DT_MIPS_ICHECKSUM = 0x70000003, + DT_MIPS_IVERSION = 0x70000004, + DT_MIPS_FLAGS = 0x70000005, + DT_MIPS_BASE_ADDRESS = 0x70000006, + DT_MIPS_CONFLICT = 0x70000008, + DT_MIPS_LIBLIST = 0x70000009, + DT_MIPS_LOCAL_GOTNO = 0x7000000a, + DT_MIPS_CONFLICTNO = 0x7000000b, + DT_MIPS_LIBLISTNO = 0x70000010, + DT_MIPS_SYMTABNO = 0x70000011, + DT_MIPS_UNREFEXTNO = 0x70000012, + DT_MIPS_GOTSYM = 0x70000013, + DT_MIPS_HIPAGENO = 0x70000014, + DT_MIPS_RLD_MAP = 0x70000016, + DT_MIPS_RLD_MAP_REL = 0x70000035 +} + +impl fmt::LowerHex for DynTag { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_fmt(format_args!("{:?}", self)) + } +} + +datastructure! { + pub struct Elf32Sym { + st_name: u32, + st_value: u32, + st_size: u32, + st_info: u8, + st_other: u8, + st_shndx: u16, + } +} + +datastructure! { + pub struct Elf64Sym { + st_name: u32, + st_info: u8, + st_other: u8, + st_shndx: u16, + st_value: u64, + st_size: u64, + } +} + +datastructure! { + pub struct Elf64Dyn { + d_tag: DynTag, + d_val: u64, + } +} + +datastructure! { + pub struct Elf32Dyn { + d_tag: u32, + d_val: u32, + } +} diff --git a/binformat/src/lib.rs b/binformat/src/lib.rs index 2e7c238..f92dbfe 100644 --- a/binformat/src/lib.rs +++ b/binformat/src/lib.rs @@ -67,13 +67,21 @@ fn parse_section_generics<'data, Obj: ObjectSection<'data>>( (name.to_string(), bytes, start, end) } +pub struct Datastructure { + pub ident: &'static str, + pub fields: Vec<(usize, &'static str, &'static str, String)>, +} + +pub trait ToData { + fn to_fields(&self, addr: usize) -> Datastructure; +} + +// FIXME: This assumes little endianness. #[macro_export] macro_rules! datastructure { ( pub struct $name:ident { - $( - $field:ident: $ftype:ty, - )* + $($field:ident: $ftype:ty,)* } ) => { // Apply attributes to the struct @@ -83,9 +91,8 @@ macro_rules! datastructure { pub $($field: $ftype),* } - impl $name { - pub fn to_fields(&self, mut addr: usize) - -> Vec<(usize, &'static str, &'static str, String)> { + impl $crate::ToData for $name { + fn to_fields(&self, mut addr: usize) -> $crate::Datastructure { let mut fields = Vec::new(); $( fields.push(( @@ -97,8 +104,13 @@ macro_rules! datastructure { #[allow(unused_assignments)] { addr += ::std::mem::size_of::<$ftype>(); } )* - fields + $crate::Datastructure { + ident: stringify!($name), + fields, + } } } + + unsafe impl object::Pod for $name {} }; } diff --git a/binformat/src/pe.rs b/binformat/src/pe.rs index 4e766de..9e90023 100644 --- a/binformat/src/pe.rs +++ b/binformat/src/pe.rs @@ -14,8 +14,6 @@ datastructure! { } } -unsafe impl object::Pod for ExceptionDirectoryEntry {} - pub struct PeDebugInfo<'data, Pe: ImageNtHeaders> { /// Parsed PE32/64 header. obj: &'data PeFile<'data, Pe>, diff --git a/processor/src/blocks.rs b/processor/src/blocks.rs index d9b4342..f5031b1 100644 --- a/processor/src/blocks.rs +++ b/processor/src/blocks.rs @@ -1,10 +1,13 @@ use crate::Processor; +use binformat::elf::{Elf32Dyn, Elf32Sym, Elf64Dyn, Elf64Sym}; use binformat::pe::ExceptionDirectoryEntry; +use binformat::ToData; use commands::CONFIG; use debugvault::Symbol; use object::Endian; use processor_shared::{encode_hex_bytes_truncated, Section, SectionKind}; -use std::{mem::size_of, sync::Arc}; +use std::mem::size_of; +use std::sync::Arc; use tokenizing::{colors, Token, TokenStream}; const BYTES_BLOCK_SIZE: usize = 256; @@ -41,7 +44,8 @@ pub enum BlockContent { }, DataStructure { ident: &'static str, - fields: Vec<(usize, &'static str, &'static str, String)>, // (addr, field, type, value) + /// (addr, field, type, value). + fields: Vec<(usize, &'static str, &'static str, String)>, }, Bytes { bytes: Vec, @@ -82,7 +86,11 @@ impl Block { stream.push("section started", colors::WHITE); stream.push_owned(format!(" {} ", section.name), colors::BLUE); stream.push("{", colors::GRAY60); - stream.push_owned(format!("{:?}", section.kind), colors::MAGENTA); + if section.ident == "UNKNOWN" { + stream.push_owned(format!("{:?}", section.kind), colors::MAGENTA); + } else { + stream.push(section.ident, colors::MAGENTA); + } stream.push("} ", colors::GRAY60); stream.push_owned(format!("{:x}", section.start), colors::GREEN); stream.push("-", colors::GRAY60); @@ -251,15 +259,19 @@ impl Processor { SectionKind::Got64 => self.parse_got(addr, 4, section, &mut blocks), SectionKind::CString => self.parse_cstring(addr, section, &mut blocks), SectionKind::ExceptionDirEntry => { - if let Ok(entry) = section.read_at::(addr) { - blocks.push(Block { - addr, - content: BlockContent::DataStructure { - ident: "ExceptionDirectoryEntry", - fields: entry.to_fields(addr), - }, - }) - } + self.parse_datastructure::(addr, section, &mut blocks); + } + SectionKind::Elf32Sym => { + self.parse_datastructure::(addr, section, &mut blocks); + } + SectionKind::Elf64Sym => { + self.parse_datastructure::(addr, section, &mut blocks); + } + SectionKind::Elf32Dyn => { + self.parse_datastructure::(addr, section, &mut blocks); + } + SectionKind::Elf64Dyn => { + self.parse_datastructure::(addr, section, &mut blocks); } // For any other section kinds just assume they're made of bytes. // As a note, we calculate the byte boundaries in blocks of [`BYTES_BLOCK_SIZE`], @@ -276,6 +288,24 @@ impl Processor { blocks } + fn parse_datastructure( + &self, + addr: usize, + section: &Section, + blocks: &mut Vec, + ) { + if let Ok(datastructure) = section.read_at::(addr) { + let datastructure = datastructure.to_fields(addr); + blocks.push(Block { + addr, + content: BlockContent::DataStructure { + ident: datastructure.ident, + fields: datastructure.fields, + }, + }) + } + } + fn parse_got(&self, addr: usize, size: usize, section: &Section, blocks: &mut Vec) { let symbol = self.get_symbol_by_addr(addr, section).unwrap_or_default(); blocks.push(Block { @@ -449,6 +479,34 @@ impl Processor { addr += size_of::(); } } + SectionKind::Elf32Sym => { + let mut addr = section.start; + while addr < section.end { + boundaries.push(addr); + addr += size_of::(); + } + } + SectionKind::Elf64Sym => { + let mut addr = section.start; + while addr < section.end { + boundaries.push(addr); + addr += size_of::(); + } + } + SectionKind::Elf32Dyn => { + let mut addr = section.start; + while addr < section.end { + boundaries.push(addr); + addr += size_of::(); + } + } + SectionKind::Elf64Dyn => { + let mut addr = section.start; + while addr < section.end { + boundaries.push(addr); + addr += size_of::(); + } + } // For any other section kinds just assume they evenly // split in blocks of [`BYTES_BLOCK_SIZE`]. _ => { diff --git a/processor_shared/src/lib.rs b/processor_shared/src/lib.rs index d30cbcb..33253fd 100644 --- a/processor_shared/src/lib.rs +++ b/processor_shared/src/lib.rs @@ -30,6 +30,14 @@ pub enum SectionKind { CString, /// ExceptionDirectoryEntry's (PE only). ExceptionDirEntry, + /// Elf32Sym. + Elf32Sym, + /// Elf64Sym. + Elf64Sym, + /// Elf32Dyn. + Elf32Dyn, + /// Elf64Dyn. + Elf64Dyn, /// DWARF debug info. Debug, /// Zero sized special sections.