Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

read/pe: style changes for resource parsing #427

Merged
merged 1 commit into from
Feb 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 76 additions & 27 deletions crates/examples/src/readobj/pe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,48 +315,74 @@ fn print_resource_dir(
sections: &SectionTable,
data_directories: &DataDirectories,
) -> Option<()> {
let rsc_table = data_directories
.resource_directory_table(data, sections)
let directory = data_directories
.resource_directory(data, sections)
.print_err(p)??;
p.group("ResourceDirectory", |p| print_resource_table(p, &rsc_table));
let root = directory.root().print_err(p)?;
print_resource_table(p, directory, root, 0);
Some(())
}

fn print_resource_table(p: &mut Printer<'_>, table: &ResourceDirectoryTable<'_>) {
p.group("Directory", |p| {
fn print_resource_table(
p: &mut Printer<'_>,
directory: ResourceDirectory<'_>,
table: ResourceDirectoryTable<'_>,
level: usize,
) {
p.group("ImageResourceDirectory", |p| {
p.field("Characteristics", table.header.characteristics.get(LE));
p.field("TimeDateStamp", table.header.time_date_stamp.get(LE));
p.field("MajorVersion", table.header.major_version.get(LE));
p.field("MinorVersion", table.header.minor_version.get(LE));
p.field(
"Number of named entries",
table.table.number_of_named_entries.get(LE),
"NumberOfNamedEntries",
table.header.number_of_named_entries.get(LE),
);
p.field(
"Number of ID entries",
table.table.number_of_id_entries.get(LE),
"NumberOfIdEntries",
table.header.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"),
},
for entry in table.entries {
p.group("ImageResourceDirectoryEntry", |p| {
match entry.name_or_id() {
ResourceNameOrId::Name(name) => {
let offset = entry.name_or_id.get(LE);
if let Some(name) = name.to_string_lossy(directory).print_err(p) {
p.field_name("NameOrId");
writeln!(p.w, "\"{}\" (0x{:X})", name, offset).unwrap();
} else {
p.field_hex("NameOrId", offset);
}
}
ResourceNameOrId::Id(id) => {
p.field("Name ID", id);
if level == 0 {
p.field_enum("NameOrId", id, FLAGS_RT);
} else {
p.field("NameOrId", id);
}
}
}
p.field_hex(
"OffsetToDataOrDirectory",
entry.offset_to_data_or_directory.get(LE),
);

match e.data() {
Ok(ResourceDirectoryEntryData::Directory(table)) => {
print_resource_table(p, &table)
match entry.data(directory).print_err(p) {
Some(ResourceDirectoryEntryData::Table(table)) => {
print_resource_table(p, directory, table, level + 1)
}
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));
Some(ResourceDirectoryEntryData::Data(data_entry)) => {
p.group("ImageResourceDataEntry", |p| {
p.field_hex("VirtualAddress", data_entry.offset_to_data.get(LE));
p.field("Size", data_entry.size.get(LE));
p.field("CodePage", data_entry.code_page.get(LE));
p.field_hex("Reserved", data_entry.reserved.get(LE));
});
}
_ => p.field("Data", "Invalid"),
None => {}
}
}
});
});
}
})
}

Expand Down Expand Up @@ -1074,3 +1100,26 @@ static FLAGS_IMAGE_REL_RISCV_BASED: &[Flag<u16>] = &flags!(
IMAGE_REL_BASED_RISCV_LOW12I,
IMAGE_REL_BASED_RISCV_LOW12S,
);
static FLAGS_RT: &[Flag<u16>] = &flags!(
RT_CURSOR,
RT_BITMAP,
RT_ICON,
RT_MENU,
RT_DIALOG,
RT_STRING,
RT_FONTDIR,
RT_FONT,
RT_ACCELERATOR,
RT_RCDATA,
RT_MESSAGETABLE,
RT_GROUP_CURSOR,
RT_GROUP_ICON,
RT_VERSION,
RT_DLGINCLUDE,
RT_PLUGPLAY,
RT_VXD,
RT_ANICURSOR,
RT_ANIICON,
RT_HTML,
RT_MANIFEST,
);
50 changes: 33 additions & 17 deletions crates/examples/testfiles/pe/base-gnu.exe.readobj
Original file line number Diff line number Diff line change
Expand Up @@ -15687,25 +15687,41 @@ 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
ImageResourceDirectory {
Characteristics: 0
TimeDateStamp: 0
MajorVersion: 0
MinorVersion: 0
NumberOfNamedEntries: 0
NumberOfIdEntries: 1
ImageResourceDirectoryEntry {
NameOrId: RT_MANIFEST (0x18)
OffsetToDataOrDirectory: 0x80000018
ImageResourceDirectory {
Characteristics: 0
TimeDateStamp: 0
MajorVersion: 0
MinorVersion: 0
NumberOfNamedEntries: 0
NumberOfIdEntries: 1
ImageResourceDirectoryEntry {
NameOrId: 1
OffsetToDataOrDirectory: 0x80000030
ImageResourceDirectory {
Characteristics: 0
TimeDateStamp: 0
MajorVersion: 0
MinorVersion: 0
NumberOfNamedEntries: 0
NumberOfIdEntries: 1
ImageResourceDirectoryEntry {
NameOrId: 0
OffsetToDataOrDirectory: 0x48
ImageResourceDataEntry {
VirtualAddress: 0x10058
Size: 1167
Code page: 0
CodePage: 0
Reserved: 0x0
}
}
}
Expand Down
46 changes: 46 additions & 0 deletions src/pe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2062,12 +2062,58 @@ pub struct ImageResourceDirStringU {
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct ImageResourceDataEntry {
/// RVA of the data.
pub offset_to_data: U32<LE>,
pub size: U32<LE>,
pub code_page: U32<LE>,
pub reserved: U32<LE>,
}

// Resource type: https://docs.microsoft.com/en-us/windows/win32/menurc/resource-types

/// ID for: Hardware-dependent cursor resource.
pub const RT_CURSOR: u16 = 1;
/// ID for: Bitmap resource.
pub const RT_BITMAP: u16 = 2;
/// ID for: Hardware-dependent icon resource.
pub const RT_ICON: u16 = 3;
/// ID for: Menu resource.
pub const RT_MENU: u16 = 4;
/// ID for: Dialog box.
pub const RT_DIALOG: u16 = 5;
/// ID for: String-table entry.
pub const RT_STRING: u16 = 6;
/// ID for: Font directory resource.
pub const RT_FONTDIR: u16 = 7;
/// ID for: Font resource.
pub const RT_FONT: u16 = 8;
/// ID for: Accelerator table.
pub const RT_ACCELERATOR: u16 = 9;
/// ID for: Application-defined resource (raw data).
pub const RT_RCDATA: u16 = 10;
/// ID for: Message-table entry.
pub const RT_MESSAGETABLE: u16 = 11;
/// ID for: Hardware-independent cursor resource.
pub const RT_GROUP_CURSOR: u16 = 12;
/// ID for: Hardware-independent icon resource.
pub const RT_GROUP_ICON: u16 = 14;
/// ID for: Version resource.
pub const RT_VERSION: u16 = 16;
/// ID for: Allows a resource editing tool to associate a string with an .rc file.
pub const RT_DLGINCLUDE: u16 = 17;
/// ID for: Plug and Play resource.
pub const RT_PLUGPLAY: u16 = 19;
/// ID for: VXD.
pub const RT_VXD: u16 = 20;
/// ID for: Animated cursor.
pub const RT_ANICURSOR: u16 = 21;
/// ID for: Animated icon.
pub const RT_ANIICON: u16 = 22;
/// ID for: HTML resource.
pub const RT_HTML: u16 = 23;
/// ID for: Side-by-Side Assembly Manifest.
pub const RT_MANIFEST: u16 = 24;

//
// Code Integrity in loadconfig (CI)
//
Expand Down
14 changes: 6 additions & 8 deletions src/read/pe/data_directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ use core::slice;
use crate::read::{Error, ReadError, ReadRef, Result};
use crate::{pe, LittleEndian as LE};

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

/// The table of data directories in a PE file.
#[derive(Debug, Clone, Copy)]
Expand Down Expand Up @@ -123,20 +121,20 @@ impl<'data> DataDirectories<'data> {
Ok(Some(RelocationBlockIterator::new(reloc_data)))
}

/// Returns the root resource directory table.
/// Returns the resource directory.
///
/// `data` must be the entire file data.
pub fn resource_directory_table<R: ReadRef<'data>>(
pub fn resource_directory<R: ReadRef<'data>>(
&self,
data: R,
sections: &SectionTable<'data>,
) -> Result<Option<ResourceDirectoryTable<'data>>> {
) -> Result<Option<ResourceDirectory<'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)
let rsrc_data = data_dir.data(data, sections)?;
Ok(Some(ResourceDirectory::new(rsrc_data)))
}
}

Expand Down
Loading