From 39b1829db96f450dcec23de7f3c6d9cb61b208d3 Mon Sep 17 00:00:00 2001 From: roblabla Date: Mon, 6 Aug 2018 22:20:03 +0200 Subject: [PATCH 1/4] Get proper name for over-8-character sections --- src/pe/mod.rs | 3 ++- src/pe/section_table.rs | 23 ++++++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/pe/mod.rs b/src/pe/mod.rs index b218f45fc..eec987c58 100644 --- a/src/pe/mod.rs +++ b/src/pe/mod.rs @@ -59,8 +59,9 @@ impl<'a> PE<'a> { let offset = &mut (header.dos_header.pe_pointer as usize + header::SIZEOF_COFF_HEADER + header.coff_header.size_of_optional_header as usize); let nsections = header.coff_header.number_of_sections as usize; let mut sections = Vec::with_capacity(nsections); + let string_table_offset = header.coff_header.pointer_to_symbol_table + header.coff_header.number_of_symbol_table * 18; for i in 0..nsections { - let section = section_table::SectionTable::parse(bytes, offset)?; + let section = section_table::SectionTable::parse(bytes, offset, string_table_offset as usize)?; debug!("({}) {:#?}", i, section); sections.push(section); } diff --git a/src/pe/section_table.rs b/src/pe/section_table.rs index b1fe3e441..9ceab71b5 100644 --- a/src/pe/section_table.rs +++ b/src/pe/section_table.rs @@ -2,9 +2,10 @@ use scroll::{self, Pread}; use error; #[repr(C)] -#[derive(Debug, PartialEq, Copy, Clone, Default)] +#[derive(Debug, PartialEq, Clone, Default)] pub struct SectionTable { pub name: [u8; 8], + pub real_name: Option, pub virtual_size: u32, pub virtual_address: u32, pub size_of_raw_data: u32, @@ -19,12 +20,13 @@ pub struct SectionTable { pub const SIZEOF_SECTION_TABLE: usize = 8 * 5; impl SectionTable { - pub fn parse(bytes: &[u8], offset: &mut usize) -> error::Result { + pub fn parse(bytes: &[u8], offset: &mut usize, string_table_offset: usize) -> error::Result { let mut table = SectionTable::default(); let mut name = [0u8; 8]; for i in 0..8 { name[i] = bytes.gread_with(offset, scroll::LE)?; } + table.name = name; table.virtual_size = bytes.gread_with(offset, scroll::LE)?; table.virtual_address = bytes.gread_with(offset, scroll::LE)?; @@ -35,10 +37,25 @@ impl SectionTable { table.number_of_relocations = bytes.gread_with(offset, scroll::LE)?; table.number_of_linenumbers = bytes.gread_with(offset, scroll::LE)?; table.characteristics = bytes.gread_with(offset, scroll::LE)?; + + // Based on https://github.com/llvm-mirror/llvm/blob/af7b1832a03ab6486c42a40d21695b2c03b2d8a3/lib/Object/COFFObjectFile.cpp#L1054 + if name[0] == b'/' { + let idx: usize = if name[1] == b'/' { + // TODO: Base-64 encoding + panic!("At the disco") + } else { + name[1..].pread::<&str>(0)?.parse().unwrap() + }; + table.real_name = Some(bytes.pread::<&str>(string_table_offset + idx)?.to_string()); + } Ok(table) } + pub fn name(&self) -> error::Result<&str> { - Ok(self.name.pread(0)?) + match self.real_name.as_ref() { + Some(s) => Ok(s.as_ref()), + None => Ok(self.name.pread(0)?) + } } } From 3ece54d7dc7863e1c4c2e4e61ecd90ad52c139e6 Mon Sep 17 00:00:00 2001 From: roblabla Date: Tue, 7 Aug 2018 21:53:55 +0200 Subject: [PATCH 2/4] Fix error handling and other code quality issues --- src/pe/mod.rs | 6 +++++- src/pe/section_table.rs | 8 +++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/pe/mod.rs b/src/pe/mod.rs index eec987c58..a0a3e3d8f 100644 --- a/src/pe/mod.rs +++ b/src/pe/mod.rs @@ -18,6 +18,9 @@ mod utils; use error; use container; +/// Size of a single symbol in the COFF Symbol Table. +const COFF_SYMBOL_SIZE: u32 = 18; + #[derive(Debug)] /// An analyzed PE32/PE32+ binary pub struct PE<'a> { @@ -59,7 +62,8 @@ impl<'a> PE<'a> { let offset = &mut (header.dos_header.pe_pointer as usize + header::SIZEOF_COFF_HEADER + header.coff_header.size_of_optional_header as usize); let nsections = header.coff_header.number_of_sections as usize; let mut sections = Vec::with_capacity(nsections); - let string_table_offset = header.coff_header.pointer_to_symbol_table + header.coff_header.number_of_symbol_table * 18; + // Note that if we are handling a BigCoff, the size of the symbol will be different! + let string_table_offset = header.coff_header.pointer_to_symbol_table + header.coff_header.number_of_symbol_table * COFF_SYMBOL_SIZE; for i in 0..nsections { let section = section_table::SectionTable::parse(bytes, offset, string_table_offset as usize)?; debug!("({}) {:#?}", i, section); diff --git a/src/pe/section_table.rs b/src/pe/section_table.rs index 9ceab71b5..c8c33db02 100644 --- a/src/pe/section_table.rs +++ b/src/pe/section_table.rs @@ -1,5 +1,5 @@ use scroll::{self, Pread}; -use error; +use error::{self, Error}; #[repr(C)] #[derive(Debug, PartialEq, Clone, Default)] @@ -44,7 +44,9 @@ impl SectionTable { // TODO: Base-64 encoding panic!("At the disco") } else { - name[1..].pread::<&str>(0)?.parse().unwrap() + let name = name.pread::<&str>(1)?; + name.parse().map_err(|err| + Error::Malformed(format!("Invalid indirect section name /{}: {}", name, err)))? }; table.real_name = Some(bytes.pread::<&str>(string_table_offset + idx)?.to_string()); } @@ -53,7 +55,7 @@ impl SectionTable { pub fn name(&self) -> error::Result<&str> { match self.real_name.as_ref() { - Some(s) => Ok(s.as_ref()), + Some(s) => Ok(s), None => Ok(self.name.pread(0)?) } } From 3478f94d974cded227257159677205f636699484 Mon Sep 17 00:00:00 2001 From: roblabla Date: Tue, 7 Aug 2018 21:54:25 +0200 Subject: [PATCH 3/4] Implement base64 section names --- src/pe/section_table.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/pe/section_table.rs b/src/pe/section_table.rs index c8c33db02..1fa0dbc14 100644 --- a/src/pe/section_table.rs +++ b/src/pe/section_table.rs @@ -19,6 +19,27 @@ pub struct SectionTable { pub const SIZEOF_SECTION_TABLE: usize = 8 * 5; +// Based on https://github.com/llvm-mirror/llvm/blob/af7b1832a03ab6486c42a40d21695b2c03b2d8a3/lib/Object/COFFObjectFile.cpp#L70 +// Decodes a string table entry in base 64 (//AAAAAA). Expects string without +// prefixed slashes. +fn base64_decode_string_entry(s: &str) -> Result { + assert!(s.len() <= 6, "String too long, possible overflow."); + + let mut val = 0; + for c in s.bytes() { + let v = match c { + b'A'..=b'Z' => c - b'A' + 00, // 00..=25 + b'a'..=b'z' => c - b'a' + 26, // 26..=51 + b'0'..=b'9' => c - b'0' + 52, // 52..=61 + b'+' => 62, // 62 + b'/' => 63, // 63 + _ => return Err(()) + }; + val = val * 64 + v as usize; + } + Ok(val) +} + impl SectionTable { pub fn parse(bytes: &[u8], offset: &mut usize, string_table_offset: usize) -> error::Result { let mut table = SectionTable::default(); @@ -41,8 +62,9 @@ impl SectionTable { // Based on https://github.com/llvm-mirror/llvm/blob/af7b1832a03ab6486c42a40d21695b2c03b2d8a3/lib/Object/COFFObjectFile.cpp#L1054 if name[0] == b'/' { let idx: usize = if name[1] == b'/' { - // TODO: Base-64 encoding - panic!("At the disco") + let b64idx = name.pread::<&str>(2)?; + base64_decode_string_entry(b64idx).map_err(|_| + Error::Malformed(format!("Invalid indirect section name //{}: base64 decoding failed", b64idx)))? } else { let name = name.pread::<&str>(1)?; name.parse().map_err(|err| From a15b6f6ec3cab78f69096fe798439a4e91b7cdf3 Mon Sep 17 00:00:00 2001 From: roblabla Date: Wed, 8 Aug 2018 13:14:47 +0200 Subject: [PATCH 4/4] avoid using newer rust features --- src/pe/section_table.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/pe/section_table.rs b/src/pe/section_table.rs index 1fa0dbc14..f9a6d577b 100644 --- a/src/pe/section_table.rs +++ b/src/pe/section_table.rs @@ -27,13 +27,18 @@ fn base64_decode_string_entry(s: &str) -> Result { let mut val = 0; for c in s.bytes() { - let v = match c { - b'A'..=b'Z' => c - b'A' + 00, // 00..=25 - b'a'..=b'z' => c - b'a' + 26, // 26..=51 - b'0'..=b'9' => c - b'0' + 52, // 52..=61 - b'+' => 62, // 62 - b'/' => 63, // 63 - _ => return Err(()) + let v = if b'A' <= c && c <= b'Z' { + c - b'A' + 00 // 00..=25 + } else if b'a' <= c && c <= b'z' { + c - b'a' + 26 // 26..=51 + } else if b'0' <= c && c <= b'9' { + c - b'0' + 52 // 52..=61 + } else if c == b'+' { + 62 // 62 + } else if c == b'/' { + 63 // 63 + } else { + return Err(()) }; val = val * 64 + v as usize; }