Struct goblin::pe::header::DosHeader

source ·
#[repr(C)]
pub struct DosHeader {
Show 19 fields pub signature: u16, pub bytes_on_last_page: u16, pub pages_in_file: u16, pub relocations: u16, pub size_of_header_in_paragraphs: u16, pub minimum_extra_paragraphs_needed: u16, pub maximum_extra_paragraphs_needed: u16, pub initial_relative_ss: u16, pub initial_sp: u16, pub checksum: u16, pub initial_ip: u16, pub initial_relative_cs: u16, pub file_address_of_relocation_table: u16, pub overlay_number: u16, pub reserved: [u16; 4], pub oem_id: u16, pub oem_info: u16, pub reserved2: [u16; 10], pub pe_pointer: u32,
}
Expand description

In winnt.h and pe.h, it’s IMAGE_DOS_HEADER. It’s a DOS header present in all PE binaries.

The DOS header is a relic from the MS-DOS era. It used to be useful to display an error message if the binary is run in MS-DOS by utilizing the DOS stub.

Nowadays, only two fields from the DOS header are used on Windows: signature (aka e_magic) and pe_pointer (aka e_lfanew).

§Position in a modern PE file

The DOS header is located at the beginning of the PE file and is usually followed by the DosStub.

§Note on the archaic “formatted header”

The subset of the structure spanning from its start to the overlay_number (aka e_ovno) field included (i.e. till the offset 0x1C) used to be commonly known as “formatted header”, since their position and contents were fixed. Optional information used by overlay managers could have followed the formatted header. In the absence of optional information, the formatted header was followed by the “relocation pointer table”.

Overlays were sections of a program that remained on disk until the program actually required them. Different overlays could thus share the same memory area. The overlays were loaded and unloaded by special code provided by the program or its run-time library.

Source.

Fields§

§signature: u16

Magic number: [0x5A, 0x4D]. In little endian ASCII, it reads “MZ” for Mark Zbikowski).

§Non-MZ DOS executables

  • For IBM OS/2, the value was “NE”.
  • For IBM OS/2 LE, the value was “LE”.
  • For NT, the value was “PE00”.

Sources:

§bytes_on_last_page: u16

In winnt.h and pe.h, it’s e_cblp.

It used to specify the number of bytes actually used in the last “page”. Page used to refer to a segment of memory, usually of 512 bytes size.

The case of full page was represented by 0x0000 (since the last page is never empty).

For example, assuming a page size of 512 bytes, this value would be 0x0000 for a 1024 byte file, and 0x0001 for a 1025 byte file (since it only contains one valid byte). Source.

Typically, this field is set to 0. Source.

§pages_in_file: u16

In winnt.h and pe.h, it’s e_cp.

It used to specify the number of pages required to hold a file. For example, if the file contained 1024 bytes, and the file had pages of a size of 512 bytes, this word would contain 0x0002 (2 pages); if the file contained 1025 bytes, this word would contain 0x0003 (3 pages). Source.

Typically, this field is set to 0. Source.

§relocations: u16

In winnt.h and pe.h, it’s e_crlc.

It used to specify the number of “relocation items”, i.e. the number of entries that existed in the “relocation pointer table”. If there were no relocations, this field would contain 0x0000. Source.

§On relocation items and relocation pointer table

When a program is compiled, memory addresses are often hard-coded into the binary code. These addresses are usually relative to the base address where the program expects to be loaded into memory. However, when the program is loaded into memory, it might not be loaded at its preferred base address due to various reasons such as memory fragmentation or other programs already occupying that space.

Relocation items, also known as fixups or relocations, are pieces of data embedded within the executable file that indicate which memory addresses need to be adjusted when the program is loaded at a different base address. These relocations specify the location and type of adjustment needed.

The relocation pointer table is a data structure that contains pointers to the locations within the executable file where relocations need to be applied. It allows the operating system’s loader to efficiently locate and process the relocation data during the loading process.


Typically, this field is set to 0. Source.

§size_of_header_in_paragraphs: u16

In winnt.h and pe.h, it’s e_cparhdr.

It used to specify the size of the “executable header” in terms of “paragraphs” (16 byte chunks). It used to indicate the offset of the program’s compiled/assembled and linked image (the load module) within the executable file. The size of the load module could have been deduced by substructing this value (converted to bytes) from the overall size that could have been derived from combining the value of pages_in_file (aka e_cp) and the value of bytes_on_last_page (aka e_cblp). The header used to always span an even number of paragraphs. Source.

The “executable header” in this context refers to the DOS header itself.

Typically, this field is set to 4. Source. This is because the modern DOS header is 64 bytes long, and 64 / 16 = 4.

§minimum_extra_paragraphs_needed: u16

In winnt.h and pe.h, it’s e_minalloc.

It used to specify the minimum number of extra paragraphs needed to be allocated to begin execution. This is in addition to the memory required to hold the load module. This value normally represented the total size of any uninitialized data and/or stack segments that were linked at the end of the program. This space was not directly included in the load module, since there were no particular initializing values and it would simply waste disk space. Source.

If both the minimum_extra_paragraphs_needed (aka e_minalloc) and maximum_extra_paragraphs_needed (aka e_maxalloc) fields were set to 0x0000, the program would be allocated as much memory as available. Source

Typically, this field is set to 0x10. Source.

§maximum_extra_paragraphs_needed: u16

In winnt.h and pe.h, it’s e_maxalloc.

It used to specify the maximum number of extra paragraphs needed to be allocated by to begin execution. This indicated additional memory over and above that required by the load module and the value specified in minimum_extra_paragraphs_needed (aka e_minalloc). If the request could not be satisfied, the program would be allocated as much memory as available. Source.

If both the minimum_extra_paragraphs_needed (aka e_minalloc) and maximum_extra_paragraphs_needed (aka e_maxalloc) fields were set to 0x0000, the program would be allocated as much memory as available. Source

Typically, this field is set to 0xFFFF. Source.

§initial_relative_ss: u16

In winnt.h and pe.h, it’s e_ss.

It used to specify the initial SS (“stack segment”) value. SS value was a paragraph address of the stack segment relative to the start of the load module. At load time, the value was relocated by adding the address of the start segment of the program to it, and the resulting value was placed in the SS register before the program is started. To read more about x86 memory segmentation and SS register, see the wikipedia article on this topic. In DOS, the start segment boundary of the program was the first segment boundary in memory after Program Segment Prefix (PSP). Source.

The Program Segment Prefix (PSP) was a data structure used in DOS (Disk Operating System) environments. It was located at the beginning of the memory allocated for a running program and it contained various pieces of information about the program, including command-line arguments, environment variables, and pointers to various system resources.

According to Wikipedia, the stack segment contains the call stack, a LIFO structure, typically located in the higher parts of memory. A “stack pointer” register tracks the top of the stack; it is adjusted each time a value is “pushed” onto the stack. The set of values pushed for one function call is termed a “stack frame”.

Typically, this field is set to 0. Source.

§initial_sp: u16

In winnt.h and pe.h, it’s e_sp.

It used to specify the initial SP (“stack pointer”) value. SP value was the absolute value that must have been loaded into the SP register before the program is given control. Since the actual stack segment was determined by the loader, and this was merely a value within that segment, it didn’t need to be relocated.

According to Wikipedia, the stack segment contains the call stack, a LIFO structure, typically located in the higher parts of memory. A “stack pointer” register tracks the top of the stack; it is adjusted each time a value is “pushed” onto the stack. The set of values pushed for one function call is termed a “stack frame”. Source.

Typically, this field is set to 0xB8. Source.

§checksum: u16

In winnt.h and pe.h, it’s e_csum.

It used to specify the checksum of the contents of the executable file It used to ensure the integrity of the data within the file. For full details on how this checksum was calculated, see http://www.tavi.co.uk/phobos/exeformat.html#checksum. Source.

Typically, this field is set to 0. Source.

§initial_ip: u16

In winnt.h and pe.h, it’s e_ip.

It used to specify the initial IP (“instruction pointer”) value. IP value was the absolute value that must have been loaded into the IP register in order to transfer control to the program. Since the actual code segment was determined by the loader and, and this was merely a value within that segment, it didn’t need to be relocated. Source.

Typically, this field is set to 0. Source.

§initial_relative_cs: u16

In winnt.h and pe.h, it’s e_cs.

It used to specify the pre-relocated initial CS (“code segment”) value relative to the start of the load module, that should have been placed in the CS register in order to transfer control to the program. At load time, this value was relocated by adding the address of the start segment of the program to it, and the resulting value was placed in the CS register when control is transferred. Source.

Typically, this field is set to 0. Source.

§file_address_of_relocation_table: u16

In winnt.h and pe.h, it’s e_lfarlc.

It used to specify the logical file address of the relocation table, or more specifically, the offset from the start of the file to the relocation pointer table. This value must have been used to locate the relocation table (rather than assuming a fixed location) because variable-length information pertaining to program overlays could have occurred before this table, causing its position to vary. A value of 0x40 in this field generally indicated a different kind of executable, not a DOS ‘MZ’ type. Source.

Typically, this field is set to 0x40. Source.

§overlay_number: u16

In winnt.h and pe.h, it’s e_ovno.

It used to specify the overlay number, which was normally set to 0x0000, because few programs actually had overlays. It changed only in files containing programs that used overlays. Source.

Overlays were sections of a program that remained on disk until the program actually required them. Different overlays could thus share the same memory area. The overlays were loaded and unloaded by special code provided by the program or its run-time library.

Typically, this field is set to 0. Source.

§reserved: [u16; 4]

In winnt.h and pe.h, it’s e_res[4].

It used to specify the reserved words for the program, i.e. an array reserved for future use. Usually, the array was zeroed by the linker. Source.

Typically, this field is set to 0. Source.

§oem_id: u16

In winnt.h and pe.h, it’s e_oemid.

It used to specify the identifier for the OEM (“Original Equipment Manufacturer”) for oem_info aka e_oeminfo. Source.

More specifically, it used to specify the OEM of the system or hardware platform for which the executable file was created. This field was used to specify certain characteristics or requirements related to the hardware environment in which the executable was intended to run.

Typically, this field is set to 0. Source.

§oem_info: u16

In winnt.h and pe.h, it’s e_oeminfo.

It used to specify the extra information, the kind of which was specific to the OEM identified by oem_id aka e_oemid.

§reserved2: [u16; 10]

In winnt.h and pe.h, it’s e_res2[10].

It used to specify the reserved words for the program, i.e. an array reserved for future use. Usually, the array was zeroed by the linker. Source.

Typically, this field is set to 0. Source.

§pe_pointer: u32

In winnt.h and pe.h, it’s e_lfanew.

Today, it specifies the logcal file address of the of the new exe header. In particular, it is a 4-byte offset into the file where the PE file header is located. It is necessary to use this offset to locate the PE header in the file.

Typically, this field is set to 0x3c (PE_POINTER_OFFSET).

Implementations§

source§

impl DosHeader

source

pub fn parse(bytes: &[u8]) -> Result<Self>

Trait Implementations§

source§

impl Clone for DosHeader

source§

fn clone(&self) -> DosHeader

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for DosHeader

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for DosHeader

source§

fn default() -> DosHeader

Returns the “default value” for a type. Read more
source§

impl PartialEq for DosHeader

source§

fn eq(&self, other: &DosHeader) -> bool

This method tests for self and other values to be equal, and is used by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
source§

impl<'a> TryIntoCtx<Endian> for &'a DosHeader

§

type Error = Error

source§

fn try_into_ctx(self, dst: &mut [u8], ctx: Endian) -> Result<usize, Self::Error>

source§

impl TryIntoCtx<Endian> for DosHeader

§

type Error = Error

source§

fn try_into_ctx(self, dst: &mut [u8], ctx: Endian) -> Result<usize, Self::Error>

source§

impl Copy for DosHeader

source§

impl StructuralPartialEq for DosHeader

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.