pe_parser/
coff.rs

1use bytemuck::{Pod, Zeroable};
2use num_derive::FromPrimitive;   
3use num_traits::FromPrimitive;
4use bitflags::bitflags;
5use core::{fmt, str};
6use crate::prelude::*;
7
8/// COFF File Header (Object and Image)
9#[derive(Copy, Clone, Pod, Zeroable, Default)]
10#[repr(C)]
11pub struct CoffFileHeader {
12    /// The number that identifies the type of target machine.
13    pub machine: u16,
14    /// The number of sections. This indicates the size of the section table, which immediately follows the headers.
15    pub number_of_sections: u16,
16    /// The low 32 bits of the number of seconds since 00:00 January 1, 1970 (a C run-time time_t value), which indicates when the file was created.
17    pub time_date_stamp: u32,
18    /// The file offset of the COFF symbol table, or zero if no COFF symbol table is present.
19    /// This value should be zero for an image because COFF debugging information is deprecated.
20    pub pointer_to_symbol_table: u32,
21    /// The number of entries in the symbol table. This data can be used to locate the string table, which immediately follows the symbol table.
22    /// This value should be zero for an image because COFF debugging information is deprecated.
23    pub number_of_symbols: u32,
24    /// The size of the optional header, which is required for executable files but not for object files. This value should be zero for an object file.
25    pub size_of_optional_header: u16,
26    /// The flags that indicate the attributes of the file.
27    pub characteristics: u16
28}
29
30impl fmt::Display for CoffFileHeader {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        let machine_type = self.get_machine_type()
33            .expect("Failed to get machine type");
34        let characteristics = self.get_characteristics()
35            .expect("Failed to get characteristics");
36        #[cfg(feature = "chrono")]
37        let time = self.get_time_date_stamp()
38            .expect("Failed to get time date stamp");
39        #[cfg(not(feature = "chrono"))]
40        let time = self.time_date_stamp;
41
42        writeln!(f, "COFF Header")?;
43        writeln!(f, "-----------")?;
44        writeln!(f, "Machine Type:            {:?}", machine_type)?;
45        writeln!(f, "Number of Sections:      {}", self.number_of_sections)?;
46        writeln!(f, "Time Date Stamp:         {}", time)?;
47        writeln!(f, "Pointer of Symbol Table: {:#010x}", self.pointer_to_symbol_table)?;
48        writeln!(f, "Number of Symbols:       {}", self.number_of_symbols)?;
49        writeln!(f, "Size of Optional Header: {}", self.size_of_optional_header)?;
50        writeln!(f, "Characteristics:         {}", characteristics)?;
51
52        Ok(())
53    }
54}
55
56/// The Machine field has one of the following values, which specify the CPU type. 
57/// An image file can be run only on the specified machine or on a system that emulates the specified machine.
58#[derive(FromPrimitive, Debug, PartialEq)]
59#[repr(u16)]
60pub enum MachineTypes {
61    /// The content of this field is assumed to be applicable to any machine type
62    Unknown = 0x0,
63    /// Alpha AXP, 32-bit address space
64    Alpha = 0x184,
65    /// Alpha 64/AXP 64, 64-bit address space
66    Alpha64 = 0x284,
67    /// Matsushita AM33
68    AM33 = 0x1d3,
69    /// x64
70    AMD64 = 0x8664,
71    /// ARM little endian
72    ARM = 0x1c0,
73    /// ARM64 little endian
74    ARM64 = 0xaa64,
75    /// ARM Thumb-2 little endian
76    ARMNT = 0x1c4,
77    /// EFI byte code
78    EBC = 0xebc,
79    /// Intel 386 or later processors and compatible processors
80    I386 = 0x14c,
81    /// Intel Itanium processor family
82    IA64 = 0x200,
83    /// LoongArch 32-bit processor family
84    LoongArch32 = 0x6232,
85    /// LoongArch 64-bit processor family
86    LoongArch64 = 0x6264,
87    /// Mitsubishi M32R little endian
88    M32R = 0x9041,
89    /// MIPS16
90    MIPS16 = 0x266,
91    /// MIPS with FPU
92    MIPSFPU = 0x366,
93    /// MIPS16 with FPU
94    MIPSFPU16 = 0x466,
95    /// Power PC little endian
96    PowerPC = 0x1f0,
97    /// Power PC with floating point support
98    PowerPCFP = 0x1f1,
99    /// MIPS little endian
100    R4000 = 0x166,
101    /// RISC-V 32-bit address space
102    RISCV32 = 0x5032,
103    /// RISC-V 64-bit address space
104    RISCV64 = 0x5064,
105    /// RISC-V 128-bit address space
106    RISCV128 = 0x5128,
107    /// Hitachi SH3
108    SH3 = 0x1a2,
109    /// Hitachi SH3 DSP
110    SH3DSP = 0x1a3,
111    /// Hitachi SH4
112    SH4 = 0x1a6,
113    /// Hitachi SH5
114    SH5 = 0x1a8,
115    /// Thumb
116    Thumb = 0x1c2,
117    /// MIPS little-endian WCE v2
118    WCEMIPSV2 = 0x169
119}
120
121bitflags! {
122    /// The Characteristics field contains flags that indicate attributes of the object or image file.
123    pub struct Characteristics: u16 {
124        /// Image only, Windows CE, and Microsoft Windows NT and later.
125        /// This indicates that the file does not contain base relocations and must therefore be loaded at its preferred base address.
126        /// If the base address is not available, the loader reports an error.
127        /// The default behavior of the linker is to strip base relocations from executable (EXE) files.
128        const IMAGE_FILE_RELOCS_STRIPPED = 0x0001;
129        /// Image only. This indicates that the image file is valid and can be run.
130        /// If this flag is not set, it indicates a linker error.
131        const IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002;
132        /// COFF line numbers have been removed. This flag is deprecated and should be zero.
133        const IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004;
134        /// COFF symbol table entries for local symbols have been removed. This flag is deprecated and should be zero.
135        const IMAGE_FILE_LOCAL_SYMS_STRIPPED = 0x0008;
136        /// Obsolete. Aggressively trim working set. This flag is deprecated for Windows 2000 and later and must be zero.
137        const IMAGE_FILE_AGGRESIVE_WS_TRIM = 0x0010;
138        /// Application can handle > 2-GB addresses.
139        const IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020;
140        /// This flag is reserved for future use.
141        const IMAGE_FILE_RESERVED1 = 0x0040;
142        /// Little endian: the least significant bit (LSB) precedes the most significant bit (MSB) in memory.
143        /// This flag is deprecated and should be zero.
144        const IMAGE_FILE_BYTES_RESERVED_LO = 0x0080;
145        /// Machine is based on a 32-bit-word architecture.
146        const IMAGE_FILE_32BIT_MACHINE = 0x0100;
147        /// Debugging information is removed from the image file.
148        const IMAGE_FILE_DEBUG_STRIPPED = 0x0200;
149        /// If the image is on removable media, fully load it and copy it to the swap file.
150        const IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 0x0400;
151        /// If the image is on network media, fully load it and copy it to the swap file.
152        const IMAGE_FILE_NET_RUN_FROM_SWAP = 0x0800;
153        /// The image file is a system file, not a user program.
154        const IMAGE_FILE_SYSTEM = 0x1000;
155        /// The image file is a dynamic-link library (DLL).
156        /// Such files are considered executable files for almost all purposes, although they cannot be directly run.
157        const IMAGE_FILE_DLL = 0x2000;
158        /// The file should be run only on a uniprocessor machine.
159        const IMAGE_FILE_UP_SYSTEM_ONLY = 0x4000;
160        /// Big endian: the MSB precedes the LSB in memory. 
161        /// This flag is deprecated and should be zero.
162        const IMAGE_FILE_BYTES_RESERVED_HI = 0x8000;
163    }
164}
165
166// Allow Characteristics flags to be easily printed
167impl fmt::Debug for Characteristics {
168    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
169        fmt::Debug::fmt(&self.0, f)
170    }
171}
172
173impl fmt::Display for Characteristics {
174    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
175        fmt::Display::fmt(&self.0, f)
176    }
177}
178
179impl str::FromStr for Characteristics {
180    type Err = bitflags::parser::ParseError;
181
182    fn from_str(flags: &str) -> Result<Self, Self::Err> {
183        Ok(Self(flags.parse()?))
184    }
185}
186
187impl CoffFileHeader {
188    /// Returns the machine type as an enum
189    pub fn get_machine_type(&self) -> Option<MachineTypes> {
190        MachineTypes::from_u16(self.machine)
191    }
192
193    /// Returns the Characteristics as bitflags
194    pub fn get_characteristics(&self) -> Option<Characteristics> {
195        Characteristics::from_bits(self.characteristics)
196    }
197
198    /// Returns the Unix epoch timestamp as a `DateTime<Utc>`
199    #[cfg(feature = "chrono")]
200    pub fn get_time_date_stamp(&self) -> Option<chrono::DateTime<chrono::Utc>> {
201        chrono::DateTime::from_timestamp(self.time_date_stamp.into(), 0)
202    }
203}