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}