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