Skip to content

Commit

Permalink
pe: Added a feature to disable pe rva resolve for already mapped modu…
Browse files Browse the repository at this point in the history
…les (e.g. from a memory dump) (#188)
  • Loading branch information
ko1N authored and m4b committed Jan 31, 2021
1 parent c0a421f commit 050bc01
Show file tree
Hide file tree
Showing 7 changed files with 304 additions and 49 deletions.
53 changes: 49 additions & 4 deletions src/pe/debug.rs
Expand Up @@ -2,6 +2,7 @@ use crate::error;
use scroll::{Pread, Pwrite, SizeWith};

use crate::pe::data_directories;
use crate::pe::options;
use crate::pe::section_table;
use crate::pe::utils;

Expand All @@ -17,11 +18,27 @@ impl<'a> DebugData<'a> {
dd: data_directories::DataDirectory,
sections: &[section_table::SectionTable],
file_alignment: u32,
) -> error::Result<Self> {
Self::parse_with_opts(
bytes,
dd,
sections,
file_alignment,
&options::ParseOptions::default(),
)
}

pub fn parse_with_opts(
bytes: &'a [u8],
dd: data_directories::DataDirectory,
sections: &[section_table::SectionTable],
file_alignment: u32,
opts: &options::ParseOptions,
) -> error::Result<Self> {
let image_debug_directory =
ImageDebugDirectory::parse(bytes, dd, sections, file_alignment)?;
ImageDebugDirectory::parse_with_opts(bytes, dd, sections, file_alignment, opts)?;
let codeview_pdb70_debug_info =
CodeviewPDB70DebugInfo::parse(bytes, &image_debug_directory)?;
CodeviewPDB70DebugInfo::parse_with_opts(bytes, &image_debug_directory, opts)?;

Ok(DebugData {
image_debug_directory,
Expand Down Expand Up @@ -59,14 +76,31 @@ pub const IMAGE_DEBUG_TYPE_FIXUP: u32 = 6;
pub const IMAGE_DEBUG_TYPE_BORLAND: u32 = 9;

impl ImageDebugDirectory {
#[allow(unused)]
fn parse(
bytes: &[u8],
dd: data_directories::DataDirectory,
sections: &[section_table::SectionTable],
file_alignment: u32,
) -> error::Result<Self> {
Self::parse_with_opts(
bytes,
dd,
sections,
file_alignment,
&options::ParseOptions::default(),
)
}

fn parse_with_opts(
bytes: &[u8],
dd: data_directories::DataDirectory,
sections: &[section_table::SectionTable],
file_alignment: u32,
opts: &options::ParseOptions,
) -> error::Result<Self> {
let rva = dd.virtual_address as usize;
let offset = utils::find_offset(rva, sections, file_alignment).ok_or_else(|| {
let offset = utils::find_offset(rva, sections, file_alignment, opts).ok_or_else(|| {
error::Error::Malformed(format!(
"Cannot map ImageDebugDirectory rva {:#x} into offset",
rva
Expand Down Expand Up @@ -94,14 +128,25 @@ pub struct CodeviewPDB70DebugInfo<'a> {

impl<'a> CodeviewPDB70DebugInfo<'a> {
pub fn parse(bytes: &'a [u8], idd: &ImageDebugDirectory) -> error::Result<Option<Self>> {
Self::parse_with_opts(bytes, idd, &options::ParseOptions::default())
}

pub fn parse_with_opts(
bytes: &'a [u8],
idd: &ImageDebugDirectory,
opts: &options::ParseOptions,
) -> error::Result<Option<Self>> {
if idd.data_type != IMAGE_DEBUG_TYPE_CODEVIEW {
// not a codeview debug directory
// that's not an error, but it's not a CodeviewPDB70DebugInfo either
return Ok(None);
}

// ImageDebugDirectory.pointer_to_raw_data stores a raw offset -- not a virtual offset -- which we can use directly
let mut offset: usize = idd.pointer_to_raw_data as usize;
let mut offset: usize = match opts.resolve_rva {
true => idd.pointer_to_raw_data as usize,
false => idd.address_of_raw_data as usize,
};

// calculate how long the eventual filename will be, which doubles as a check of the record size
let filename_length = idd.size_of_data as isize - 24;
Expand Down
59 changes: 51 additions & 8 deletions src/pe/exception.rs
Expand Up @@ -49,6 +49,7 @@ use scroll::{self, Pread, Pwrite};
use crate::error;

use crate::pe::data_directories;
use crate::pe::options;
use crate::pe::section_table;
use crate::pe::utils;

Expand Down Expand Up @@ -666,6 +667,23 @@ impl<'a> ExceptionData<'a> {
directory: data_directories::DataDirectory,
sections: &[section_table::SectionTable],
file_alignment: u32,
) -> error::Result<Self> {
Self::parse_with_opts(
bytes,
directory,
sections,
file_alignment,
&options::ParseOptions::default(),
)
}

/// Parses exception data from the image at the given offset.
pub fn parse_with_opts(
bytes: &'a [u8],
directory: data_directories::DataDirectory,
sections: &[section_table::SectionTable],
file_alignment: u32,
opts: &options::ParseOptions,
) -> error::Result<Self> {
let size = directory.size as usize;

Expand All @@ -677,7 +695,7 @@ impl<'a> ExceptionData<'a> {
}

let rva = directory.virtual_address as usize;
let offset = utils::find_offset(rva, sections, file_alignment).ok_or_else(|| {
let offset = utils::find_offset(rva, sections, file_alignment, opts).ok_or_else(|| {
error::Error::Malformed(format!("cannot map exception_rva ({:#x}) into offset", rva))
})?;

Expand Down Expand Up @@ -761,31 +779,56 @@ impl<'a> ExceptionData<'a> {

/// Resolves unwind information for the given function entry.
pub fn get_unwind_info(
&self,
function: RuntimeFunction,
sections: &[section_table::SectionTable],
) -> error::Result<UnwindInfo<'a>> {
self.get_unwind_info_with_opts(function, sections, &options::ParseOptions::default())
}

/// Resolves unwind information for the given function entry.
pub fn get_unwind_info_with_opts(
&self,
mut function: RuntimeFunction,
sections: &[section_table::SectionTable],
opts: &options::ParseOptions,
) -> error::Result<UnwindInfo<'a>> {
while function.unwind_info_address % 2 != 0 {
let rva = (function.unwind_info_address & !1) as usize;
function = self.get_function_by_rva(rva, sections)?;
function = self.get_function_by_rva_with_opts(rva, sections, opts)?;
}

let rva = function.unwind_info_address as usize;
let offset = utils::find_offset(rva, sections, self.file_alignment).ok_or_else(|| {
error::Error::Malformed(format!("cannot map unwind rva ({:#x}) into offset", rva))
})?;
let offset =
utils::find_offset(rva, sections, self.file_alignment, opts).ok_or_else(|| {
error::Error::Malformed(format!("cannot map unwind rva ({:#x}) into offset", rva))
})?;

UnwindInfo::parse(self.bytes, offset)
}

#[allow(dead_code)]
fn get_function_by_rva(
&self,
rva: usize,
sections: &[section_table::SectionTable],
) -> error::Result<RuntimeFunction> {
let offset = utils::find_offset(rva, sections, self.file_alignment).ok_or_else(|| {
error::Error::Malformed(format!("cannot map exception rva ({:#x}) into offset", rva))
})?;
self.get_function_by_rva_with_opts(rva, sections, &options::ParseOptions::default())
}

fn get_function_by_rva_with_opts(
&self,
rva: usize,
sections: &[section_table::SectionTable],
opts: &options::ParseOptions,
) -> error::Result<RuntimeFunction> {
let offset =
utils::find_offset(rva, sections, self.file_alignment, opts).ok_or_else(|| {
error::Error::Malformed(format!(
"cannot map exception rva ({:#x}) into offset",
rva
))
})?;

self.get_function_by_offset(offset)
}
Expand Down
45 changes: 44 additions & 1 deletion src/pe/export.rs
Expand Up @@ -6,6 +6,7 @@ use log::debug;
use crate::error;

use crate::pe::data_directories;
use crate::pe::options;
use crate::pe::section_table;
use crate::pe::utils;

Expand Down Expand Up @@ -70,6 +71,22 @@ impl<'a> ExportData<'a> {
dd: data_directories::DataDirectory,
sections: &[section_table::SectionTable],
file_alignment: u32,
) -> error::Result<ExportData<'a>> {
Self::parse_with_opts(
bytes,
dd,
sections,
file_alignment,
&options::ParseOptions::default(),
)
}

pub fn parse_with_opts(
bytes: &'a [u8],
dd: data_directories::DataDirectory,
sections: &[section_table::SectionTable],
file_alignment: u32,
opts: &options::ParseOptions,
) -> error::Result<ExportData<'a>> {
let export_rva = dd.virtual_address as usize;
let size = dd.size as usize;
Expand All @@ -78,6 +95,7 @@ impl<'a> ExportData<'a> {
export_rva,
sections,
file_alignment,
opts,
&format!("cannot map export_rva ({:#x}) into offset", export_rva),
)?;
let export_directory_table =
Expand All @@ -94,6 +112,7 @@ impl<'a> ExportData<'a> {
export_directory_table.name_pointer_rva as usize,
sections,
file_alignment,
opts,
)
.map_or(vec![], |table_offset| {
let mut offset = table_offset;
Expand All @@ -114,6 +133,7 @@ impl<'a> ExportData<'a> {
export_directory_table.ordinal_table_rva as usize,
sections,
file_alignment,
opts,
)
.map_or(vec![], |table_offset| {
let mut offset = table_offset;
Expand All @@ -134,6 +154,7 @@ impl<'a> ExportData<'a> {
export_directory_table.export_address_table_rva as usize,
sections,
file_alignment,
opts,
)
.map_or(vec![], |table_offset| {
let mut offset = table_offset;
Expand All @@ -159,6 +180,7 @@ impl<'a> ExportData<'a> {
export_directory_table.name_rva as usize,
sections,
file_alignment,
opts,
)
.and_then(|offset| bytes.pread(offset).ok());

Expand Down Expand Up @@ -251,6 +273,7 @@ struct ExportCtx<'a> {
pub file_alignment: u32,
pub addresses: &'a ExportAddressTable,
pub ordinals: &'a ExportOrdinalTable,
pub opts: options::ParseOptions,
}

impl<'a, 'b> scroll::ctx::TryFromCtx<'a, ExportCtx<'b>> for Export<'a> {
Expand All @@ -265,11 +288,12 @@ impl<'a, 'b> scroll::ctx::TryFromCtx<'a, ExportCtx<'b>> for Export<'a> {
file_alignment,
addresses,
ordinals,
opts,
}: ExportCtx<'b>,
) -> Result<(Self, usize), Self::Error> {
use self::ExportAddressTableEntry::*;

let name = utils::find_offset(ptr as usize, sections, file_alignment)
let name = utils::find_offset(ptr as usize, sections, file_alignment, &opts)
.and_then(|offset| bytes.pread::<&str>(offset).ok());

if let Some(ordinal) = ordinals.get(idx) {
Expand All @@ -281,6 +305,7 @@ impl<'a, 'b> scroll::ctx::TryFromCtx<'a, ExportCtx<'b>> for Export<'a> {
rva,
sections,
file_alignment,
&opts,
&format!(
"cannot map RVA ({:#x}) of export ordinal {} into offset",
rva, ordinal
Expand All @@ -304,6 +329,7 @@ impl<'a, 'b> scroll::ctx::TryFromCtx<'a, ExportCtx<'b>> for Export<'a> {
rva,
sections,
file_alignment,
&opts,
&format!(
"cannot map RVA ({:#x}) of export ordinal {} into offset",
rva, ordinal
Expand Down Expand Up @@ -343,6 +369,22 @@ impl<'a> Export<'a> {
export_data: &ExportData,
sections: &[section_table::SectionTable],
file_alignment: u32,
) -> error::Result<Vec<Export<'a>>> {
Self::parse_with_opts(
bytes,
export_data,
sections,
file_alignment,
&options::ParseOptions::default(),
)
}

pub fn parse_with_opts(
bytes: &'a [u8],
export_data: &ExportData,
sections: &[section_table::SectionTable],
file_alignment: u32,
opts: &options::ParseOptions,
) -> error::Result<Vec<Export<'a>>> {
let pointers = &export_data.export_name_pointer_table;
let addresses = &export_data.export_address_table;
Expand All @@ -359,6 +401,7 @@ impl<'a> Export<'a> {
file_alignment,
addresses,
ordinals,
opts: *opts,
},
) {
exports.push(export);
Expand Down

0 comments on commit 050bc01

Please sign in to comment.