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

Fix parsing of PE32+ import tables #82

Merged
merged 6 commits into from
Mar 25, 2018
Merged

Conversation

kjempelodott
Copy link
Contributor

I noticed that only the first imported symbol from each library is being parsed in 64-bit PEs. This is one way to fix it.

src/pe/import.rs Outdated
@@ -26,41 +60,37 @@ impl<'a> HintNameTableEntry<'a> {
#[derive(Debug, Clone)]
pub enum SyntheticImportLookupTableEntry<'a> {
OrdinalNumber(u16),
HintNameTableRVA ((u32, HintNameTableEntry<'a>)), // [u8; 31] bitfield :/
HintNameTableRVA ((usize, HintNameTableEntry<'a>)), // [u8; 31] bitfield :/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this changed to usize?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind, I see it now. :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell, it didn't need to change, and u32 seems more correct to me, since it's never more than 32 bits even for P32+.

Copy link
Collaborator

@philipc philipc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR. From my reading of MSDN, the import address table parsing needs fixing. The rest are minor comments.

src/pe/import.rs Outdated
@@ -26,41 +60,37 @@ impl<'a> HintNameTableEntry<'a> {
#[derive(Debug, Clone)]
pub enum SyntheticImportLookupTableEntry<'a> {
OrdinalNumber(u16),
HintNameTableRVA ((u32, HintNameTableEntry<'a>)), // [u8; 31] bitfield :/
HintNameTableRVA ((usize, HintNameTableEntry<'a>)), // [u8; 31] bitfield :/
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell, it didn't need to change, and u32 seems more correct to me, since it's never more than 32 bits even for P32+.

src/pe/mod.rs Outdated
@@ -90,9 +90,16 @@ impl<'a> PE<'a> {
}
debug!("exports: {:#?}", exports);
if let &Some(import_table) = optional_header.data_directories.get_import_table() {
let id = import::ImportData::parse(bytes, &import_table, &sections)?;
let id = match is_64 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An if statement seems more natural here?

src/pe/import.rs Outdated
pub type ImportAddressTable = Vec<u32>;

pub const SIZEOF_IMPORT_ADDRESS_TABLE_ENTRY: usize = 4;
pub type ImportAddressTable = Vec<usize>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be u64, and the import address table parsing also needs fixing to read either u32 or u64 based on whether it is PE32+.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the comments. I changed ImportAddressTable to an enum that holds a Vec<u32> or Vec<u64>, and added a method in the Bitfield trait that converts Vec<T> to an ImportAddressTable. Not sure if this is the optimal solution though.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For unified 32-bit/64-bit types, I think the rest of the crate tends to convert the fields to u64, so I think a plain Vec<u64> is better. You can add a method in the Bitfield trait to convert a value to u64.

src/pe/import.rs Outdated
pub const IMPORT_RVA_MASK_32: u32 = 0x8fff_ffff;
pub const IMPORT_RVA_MASK_64: u64 = 0x0000_0000_8fff_ffff;
pub const SIZEOF_IMPORT_ADDRESS_TABLE_ENTRY_32: usize = 4;
pub const SIZEOF_IMPORT_ADDRESS_TABLE_ENTRY_64: usize = 8;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this value is only used for the import lookup table (not the address table), I think it would be better to use 'lookup' in the name, even though both tables have the same entry size (and sometimes the same entry format).

src/pe/import.rs Outdated
}

#[derive(Debug)]
pub struct ImportLookupTableEntry<'a> {
pub bitfield: u32,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're going to delete bitfield (which I think is fine to do), then there doesn't seem much point having this struct at all.

@philipc philipc merged commit 64a9566 into m4b:master Mar 25, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants