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

PE: parse rich header and refactor DOS stub parser #406

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

kkent030315
Copy link
Contributor

@kkent030315 kkent030315 commented Apr 13, 2024

This PR adds parsing of Rich headers, as someone opened issue #400.

  • Added rich header goblin::pe::header::RichHeader goblin::pe::header::RichMetadata parsing if present, with success/fail/corrupted tests.
  • DOS stub is now non-fixed size of slice reference, and explicitly isolated from the DOS header.
    • The DOS stub is not always guaranteed to be 64-bytes long; there are some linkers (Borland C++) and PE packers generate application-specific DOS stub; and
    • The DOS stub includes the DOS header in definition. The DOS header and DOS stub are sometimes known to be separate, but also sometimes together. This is confusing stuff, and there are no official statement. By design, separating the header and the stub would be preferred. Concating them in the higher implementations (on the user side) are pretty easiest than making it together (otherwise user needs to mess with the raw buffer in the higher implementations.. bad).

I took the constant bytes in the test code from mthiesen/link-patcher (MIT). If this can potentially be license incompliance, I am happy to make own specimens for testing.

@kkent030315
Copy link
Contributor Author

I'm a bit tired, will fix the CI at the rest of today or tomorrow.

@kkent030315 kkent030315 marked this pull request as draft April 13, 2024 19:30
@m4b m4b marked this pull request as ready for review April 15, 2024 04:25
Copy link
Owner

@m4b m4b left a comment

Choose a reason for hiding this comment

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

unfortunately there are some breaking changes here, but some seem unavoidable; primarily I'd like to see DosStub have it's parse method move into an impl DosStub and the &[u8] be reverted back to the DosStub type that was there before. otherwise it's looking ok!

pub dos_header: DosHeader,
/// DOS program for legacy loaders
pub dos_stub: DosStub,
Copy link
Owner

Choose a reason for hiding this comment

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

breaking change, and unclear why it went from DosStub to &[u8]

@@ -1071,6 +1225,69 @@ mod tests {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];

static NO_RICH_HEADER: [u8; 262] = [
Copy link
Owner

Choose a reason for hiding this comment

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

this should be const not static

@@ -410,7 +410,7 @@ impl<'a> ctx::TryIntoCtx<scroll::Endian> for PE<'a> {
}
_ => None,
};
bytes.gwrite_with(self.header, &mut offset, ctx)?;
bytes.gwrite_with(self.header.clone(), &mut offset, ctx)?;
Copy link
Owner

Choose a reason for hiding this comment

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

i think keeping copy derive on self.header is fine, and also its a breaking change to remove

type Error = error::Error;

fn try_into_ctx(self, bytes: &mut [u8], ctx: scroll::Endian) -> Result<usize, Self::Error> {
let offset = &mut 0;
bytes.gwrite_with(self.dos_header, offset, ctx)?;
bytes.gwrite_with(self.dos_stub, offset, ctx)?;
bytes.gwrite_with(self.dos_stub, offset, ())?;
Copy link
Owner

Choose a reason for hiding this comment

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

i'd expect this to use the same ctx here but maybe there's a good reason

pub struct DosStub(pub [u8; 0x40]);
impl Default for DosStub {
pub struct DosStub<'a> {
pub data: &'a [u8],
Copy link
Owner

Choose a reason for hiding this comment

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

this is a breaking change, going from newtype struct to regular struct with named field

///
/// The DOS stub is a small program that prints the message "This program cannot be run in DOS mode" and exits; and
/// is not really read for the PECOFF file format. It's a relic from the MS-DOS era.
pub fn parse_dos_stub<'a>(bytes: &'a [u8], pe_pointer: u32) -> error::Result<&'a [u8]> {
Copy link
Owner

Choose a reason for hiding this comment

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

I would expect this fucntion to be pub fn new in the impl of DosStub?

@@ -792,15 +813,11 @@ pub struct Header {
pub optional_header: Option<optional_header::OptionalHeader>,
}

impl Header {
pub fn parse(bytes: &[u8]) -> error::Result<Self> {
impl<'a> Header<'a> {
Copy link
Owner

Choose a reason for hiding this comment

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

this is also technically a breaking change; i believe you message makes clear why this should now be borrowed/have a lifetime

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

2 participants