Skip to content

Commit

Permalink
read: Add PE resource navigation
Browse files Browse the repository at this point in the history
Add helpers for navigating a PE file resource directory
  • Loading branch information
Guiguiprim committed Feb 15, 2022
1 parent f6279b9 commit 6cc16ab
Show file tree
Hide file tree
Showing 6 changed files with 389 additions and 2 deletions.
52 changes: 52 additions & 0 deletions crates/examples/src/readobj/pe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ fn print_pe<Pe: ImageNtHeaders>(p: &mut Printer<'_>, data: &[u8]) {
print_export_dir(p, data, &sections, &data_directories);
print_import_dir::<Pe>(p, data, &sections, &data_directories);
print_reloc_dir(p, data, machine, &sections, &data_directories);
print_resource_dir(p, data, &sections, &data_directories);
}
}
}
Expand Down Expand Up @@ -308,6 +309,57 @@ fn print_import_dir<Pe: ImageNtHeaders>(
Some(())
}

fn print_resource_dir(
p: &mut Printer<'_>,
data: &[u8],
sections: &SectionTable,
data_directories: &DataDirectories,
) -> Option<()> {
let rsc_table = data_directories
.resource_directory_table(data, sections)
.print_err(p)??;
p.group("ResourceDirectory", |p| print_resource_table(p, &rsc_table));
Some(())
}

fn print_resource_table(p: &mut Printer<'_>, table: &ResourceDirectoryTable<'_>) {
p.group("Directory", |p| {
p.field(
"Number of named entries",
table.table.number_of_named_entries.get(LE),
);
p.field(
"Number of ID entries",
table.table.number_of_id_entries.get(LE),
);
p.group("Entries", |p| {
for e in table.iter() {
match e.name() {
ResourceNameOrId::Name(name) => match name.to_string_lossy() {
Ok(name) => p.field("Name", name),
Err(_) => p.field("Name", "Invalid"),
},
ResourceNameOrId::Id(id) => {
p.field("Name ID", id);
}
}

match e.data() {
Ok(ResourceDirectoryEntryData::Directory(table)) => {
print_resource_table(p, &table)
}
Ok(ResourceDirectoryEntryData::Entry(rsc)) => {
p.field_hex("VirtualAddress", rsc.offset_to_data.get(LE));
p.field("Size", rsc.size.get(LE));
p.field("Code page", rsc.code_page.get(LE));
}
_ => p.field("Data", "Invalid"),
}
}
});
})
}

fn print_sections(
p: &mut Printer<'_>,
data: &[u8],
Expand Down
26 changes: 26 additions & 0 deletions crates/examples/testfiles/pe/base-gnu.exe.readobj
Original file line number Diff line number Diff line change
Expand Up @@ -15687,3 +15687,29 @@ ImageBaseRelocation {
Type: IMAGE_REL_BASED_DIR64 (0xA)
Addend: 0x140001690
}
ResourceDirectory {
Directory {
Number of named entries: 0
Number of ID entries: 1
Entries {
Name ID: 24
Directory {
Number of named entries: 0
Number of ID entries: 1
Entries {
Name ID: 1
Directory {
Number of named entries: 0
Number of ID entries: 1
Entries {
Name ID: 0
VirtualAddress: 0x10058
Size: 1167
Code page: 0
}
}
}
}
}
}
}
1 change: 0 additions & 1 deletion src/pe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2001,7 +2001,6 @@ pub struct ImageResourceDirectory {
pub minor_version: U16<LE>,
pub number_of_named_entries: U16<LE>,
pub number_of_id_entries: U16<LE>,
// DirectoryEntries[ImageResourceDirectoryEntry];
}

pub const IMAGE_RESOURCE_NAME_IS_STRING: u32 = 0x8000_0000;
Expand Down
20 changes: 19 additions & 1 deletion src/read/pe/data_directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use core::slice;
use crate::read::{Error, ReadError, ReadRef, Result};
use crate::{pe, LittleEndian as LE};

use super::{ExportTable, ImportTable, RelocationBlockIterator, SectionTable};
use super::{
ExportTable, ImportTable, RelocationBlockIterator, ResourceDirectoryTable, SectionTable,
};

/// The table of data directories in a PE file.
#[derive(Debug, Clone, Copy)]
Expand Down Expand Up @@ -120,6 +122,22 @@ impl<'data> DataDirectories<'data> {
let reloc_data = data_dir.data(data, sections)?;
Ok(Some(RelocationBlockIterator::new(reloc_data)))
}

/// Returns the root resource directory table.
///
/// `data` must be the entire file data.
pub fn resource_directory_table<R: ReadRef<'data>>(
&self,
data: R,
sections: &SectionTable<'data>,
) -> Result<Option<ResourceDirectoryTable<'data>>> {
let data_dir = match self.get(pe::IMAGE_DIRECTORY_ENTRY_RESOURCE) {
Some(data_dir) => data_dir,
None => return Ok(None),
};
let rsc_data = data_dir.data(data, sections)?;
ResourceDirectoryTable::parse(rsc_data).map(Some)
}
}

impl pe::ImageDataDirectory {
Expand Down
3 changes: 3 additions & 0 deletions src/read/pe/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ pub use import::*;
mod relocation;
pub use relocation::*;

mod resource;
pub use resource::*;

mod rich;
pub use rich::*;

Expand Down
Loading

0 comments on commit 6cc16ab

Please sign in to comment.