1use chrono::{DateTime, Utc};
2use serde::Serialize;
3
4use crate::pe::{
5 dos::DosHeader,
6 export::ExportDirectory,
7 file::{self, FileHeader, MachineType},
8 import::{x64::ImportLookup64, x86::ImportLookup32, ImportDescriptor, ImportLookup},
9 optional::{self, x64::OptionalHeader64, x86::OptionalHeader32, OptionalHeader},
10 rsrc::{ResourceDirectory, ResourceEntry, ResourceNode, ResourceType},
11 section::{self, SectionHeader},
12 PeImage};
13
14use super::{DataDirValue, ExportValue, RelocBlockValue, ResourceDataValue, ResourceStringValue};
15
16
17#[derive(Debug, Serialize)]
18pub struct MinPeImage {
19 pub dos_header: MinDosHeader,
20 pub file_hedaer: MinFileHeader,
21 pub optional_header: MinOptionalHeader,
22 pub data_directories: Vec<DataDirValue>,
23 pub sections: Vec<MinSectionHeader>,
24 #[serde(skip_serializing_if="Option::is_none")]
25 pub import_directories: Option<Vec<MinImportDescriptor>>,
26 #[serde(skip_serializing_if="Option::is_none")]
27 pub export_directory: Option<MinExportDirectory>,
28 #[serde(skip_serializing_if="Option::is_none")]
29 pub relocations: Option<Vec<RelocBlockValue>>,
30 #[serde(skip_serializing_if="Option::is_none")]
31 pub resources: Option<MinRsrcDirectory>,
32}
33
34impl From<&PeImage> for MinPeImage {
35 fn from(value: &PeImage) -> Self {
36 Self {
37 dos_header: MinDosHeader::from(&value.dos.value),
38 file_hedaer: MinFileHeader::from(&value.file.value),
39 optional_header: MinOptionalHeader::from(&value.optional.value),
40
41 data_directories: value.data_dirs.value
42 .iter()
43 .filter(|dir| dir.value.size.value > 0)
44 .map(|dir| DataDirValue::from(&dir.value))
45 .collect::<Vec<DataDirValue>>(),
46
47 sections: value.sections.value
48 .iter()
49 .map(|s| MinSectionHeader::from(&s.value))
50 .collect(),
51
52 import_directories: if value.has_imports() {
53 Some(
54 value.imports.value
55 .iter()
56 .map(|id| MinImportDescriptor::from(&id.value))
57 .collect()
58 )} else { Option::None },
59
60 export_directory: if value.has_exports() {
61 Some(MinExportDirectory::from(&value.exports.value))
62 } else { Option::None },
63
64 relocations: if value.has_relocations() {
65 Some(
66 value.relocations.value.blocks
67 .iter()
68 .map(|rb| RelocBlockValue::from(&rb.value))
69 .collect()
70 )} else { Option::None },
71
72 resources: if value.has_rsrc() {
73 Some( MinRsrcDirectory::from(&value.resources.value))
74 } else { Option::None }
75 }
76 }
77}
78
79#[derive(Debug, Serialize)]
80#[serde(rename="dos_header")]
81pub struct MinDosHeader {
82 pub magic: String,
83 pub e_lfanew: u32,
84}
85
86impl From<&DosHeader> for MinDosHeader {
87 fn from(value: &DosHeader) -> Self {
88 Self {
89 magic: std::str::from_utf8(&value.e_magic.value.to_le_bytes())
90 .unwrap_or("ERR")
91 .trim_matches('\0') .to_string(),
93 e_lfanew: value.e_lfanew.value,
94 }
95 }
96}
97
98
99#[derive(Debug, Serialize)]
100#[serde(rename="file_header")]
101pub struct MinFileHeader {
102 pub magic: String,
103 #[serde(rename="machine_type")]
104 pub machine: MachineType,
105 #[serde(rename="number_of_sections")]
106 pub sections: u16,
107 pub timestamp: DateTime<Utc>,
108 #[serde(skip_serializing)]
109 #[serde(rename="pointer_to_symbol_table")]
110 pub sym_ptr: u32,
111 #[serde(skip_serializing)]
112 #[serde(rename="number_of_symbols")]
113 pub symbols: u32,
114 #[serde(rename="size_of_optional_header")]
115 pub optional_header_size: u16,
116 pub charactristics: file::Flags,
117}
118
119impl From<&FileHeader> for MinFileHeader {
120 fn from(value: &FileHeader) -> Self {
121 Self {
122 magic: std::str::from_utf8(&value.magic.value.to_le_bytes())
123 .unwrap_or("ERR")
124 .trim_matches('\0') .to_string(),
126 machine: value.machine.value,
127 sections: value.sections.value,
128 timestamp: value.timestamp.value,
129 sym_ptr: value.symbol_table_ptr.value,
130 symbols: value.symbols.value,
131 optional_header_size: value.optional_header_size.value,
132 charactristics: file::Flags::from_bits_truncate(value.charactristics.value),
133 }
134 }
135}
136
137
138#[derive(Debug, Serialize)]
139#[serde(rename="optional_header")]
140pub struct MinOptionalHeader32 {
141 pub magic: optional::ImageType,
142 pub major_linker_version: u8,
143 pub minor_linker_version: u8,
144 pub size_of_code: u32,
145 pub size_of_initialized_data: u32,
146 pub size_of_uninitialized_data: u32,
147 pub address_of_entry_point: u32,
148 pub base_of_code: u32,
149 pub base_of_data: u32,
150 pub image_base: u32,
151 pub major_os_version: u16,
152 pub minor_os_version: u16,
153 pub major_subsystem_version: u16,
154 pub minor_subsystem_version: u16,
155 pub size_of_image: u32,
156 pub size_of_headers: u32,
157 pub checksum: u32,
158 pub subsystem: optional::SubSystem,
159 pub dll_charactristics: optional::Flags,
160 pub number_of_rva_and_sizes: u32,
161}
162
163impl From<&OptionalHeader32> for MinOptionalHeader32 {
164 fn from(value: &OptionalHeader32) -> Self {
165 Self {
166 magic: value.magic.value,
167 major_linker_version: value.major_linker_ver.value,
168 minor_linker_version: value.minor_linker_ver.value,
169 size_of_code: value.sizeof_code.value,
170 size_of_initialized_data: value.sizeof_initiailized_data.value,
171 size_of_uninitialized_data: value.sizeof_uninitiailized_data.value,
172 address_of_entry_point: value.address_of_entry_point.value,
173 base_of_code: value.base_of_code.value,
174 base_of_data: value.base_of_data.value,
175 image_base: value.image_base.value,
176 major_os_version: value.major_os_version.value,
177 minor_os_version: value.minor_os_version.value,
178 major_subsystem_version: value.major_subsystem_version.value,
179 minor_subsystem_version: value.minor_subsystem_version.value,
180 size_of_image: value.sizeof_image.value,
181 size_of_headers: value.sizeof_headers.value,
182 checksum: value.checksum.value,
183 subsystem: value.subsystem.value,
184 dll_charactristics: optional::Flags::from_bits_retain(value.dll_charactristics.value),
185 number_of_rva_and_sizes: value.number_of_rva_and_sizes.value
186 }
187 }
188}
189
190#[derive(Debug, Serialize)]
191#[serde(rename="optional_header")]
192pub struct MinOptionalHeader64 {
193 pub magic: optional::ImageType,
194 pub major_linker_version: u8,
195 pub minor_linker_version: u8,
196 pub size_of_code: u32,
197 pub size_of_initialized_data: u32,
198 pub size_of_uninitialized_data: u32,
199 pub address_of_entry_point: u32,
200 pub base_of_code: u32,
201 pub image_base: u64,
202 pub major_os_version: u16,
203 pub minor_os_version: u16,
204 pub major_subsystem_version: u16,
205 pub minor_subsystem_version: u16,
206 pub size_of_image: u32,
207 pub size_of_headers: u32,
208 pub checksum: u32,
209 pub subsystem: optional::SubSystem,
210 pub dll_charactristics: optional::Flags,
211 pub number_of_rva_and_sizes: u32,
212}
213
214impl From<&OptionalHeader64> for MinOptionalHeader64 {
215 fn from(value: &OptionalHeader64) -> Self {
216 Self {
217 magic: value.magic.value,
218 major_linker_version: value.major_linker_ver.value,
219 minor_linker_version: value.minor_linker_ver.value,
220 size_of_code: value.sizeof_code.value,
221 size_of_initialized_data: value.sizeof_initiailized_data.value,
222 size_of_uninitialized_data: value.sizeof_uninitiailized_data.value,
223 address_of_entry_point: value.address_of_entry_point.value,
224 base_of_code: value.base_of_code.value,
225 image_base: value.image_base.value,
226 major_os_version: value.major_os_version.value,
227 minor_os_version: value.minor_os_version.value,
228 major_subsystem_version: value.major_subsystem_version.value,
229 minor_subsystem_version: value.minor_subsystem_version.value,
230 size_of_image: value.sizeof_image.value,
231 size_of_headers: value.sizeof_headers.value,
232 checksum: value.checksum.value,
233 subsystem: value.subsystem.value,
234 dll_charactristics: optional::Flags::from_bits_retain(value.dll_charactristics.value),
235 number_of_rva_and_sizes: value.number_of_rva_and_sizes.value
236 }
237 }
238}
239
240#[derive(Debug, Serialize)]
241#[serde(rename="optional_header")]
242pub enum MinOptionalHeader {
243 #[serde(untagged)]
244 X86(MinOptionalHeader32),
245 #[serde(untagged)]
246 X64(MinOptionalHeader64),
247}
248
249
250impl From<&OptionalHeader> for MinOptionalHeader {
251 fn from(value: &OptionalHeader) -> Self {
252 match value {
253 OptionalHeader::X86(opt) => Self::X86(MinOptionalHeader32::from(opt)),
254 OptionalHeader::X64(opt) => Self::X64(MinOptionalHeader64::from(opt)),
255 }
256 }
257}
258
259#[derive(Debug, Serialize)]
260#[serde(rename="section")]
261pub struct MinSectionHeader {
262 pub name: String,
263 pub virtual_size: u32,
264 pub virtual_address: u32,
265 #[serde(rename="size_of_raw_data")]
266 pub sizeof_raw_data: u32,
267 #[serde(rename="pointer_to_raw_data")]
268 pub raw_data_ptr: u32,
269 pub charactristics: section::Flags,
270}
271
272impl From<&SectionHeader> for MinSectionHeader {
273 fn from(value: &SectionHeader) -> Self {
274 Self {
275 name: String::from_utf8(value.name.value.to_vec())
276 .unwrap_or("ERR".to_string())
277 .trim_end_matches('\0') .to_string(),
279 virtual_size: value.virtual_size.value,
280 virtual_address: value.virtual_address.value,
281 sizeof_raw_data: value.sizeof_raw_data.value,
282 raw_data_ptr: value.raw_data_ptr.value,
283 charactristics: section::Flags::from_bits_retain(value.charactristics.value),
284 }
285 }
286}
287
288
289
290#[derive(Debug, Serialize)]
294#[serde(untagged)]
295pub enum ImportLookupVO {
296 Ordinal(u16),
297 Name(String),
298}
299
300impl From<&ImportLookup32> for ImportLookupVO{
301 fn from(value: &ImportLookup32) -> Self {
302 if let Some(iname) = &value.iname {
303 Self::Name(iname.value.name.value.clone())
304 }
305 else {
306 Self::Ordinal(value.ordinal.unwrap_or_default())
307 }
308 }
309}
310
311impl From<&ImportLookup64> for ImportLookupVO{
312 fn from(value: &ImportLookup64) -> Self {
313 if let Some(iname) = &value.iname {
314 Self::Name(iname.value.name.value.clone())
315 }
316 else {
317 Self::Ordinal(value.ordinal.unwrap_or_default())
318 }
319 }
320}
321
322impl From<&ImportLookup> for ImportLookupVO {
323 fn from(value: &ImportLookup) -> Self {
324 match value {
325 ImportLookup::X86(import) => Self::from(import),
326 ImportLookup::X64(import) => Self::from(import),
327 }
328 }
329}
330
331
332#[derive(Debug, Serialize)]
333#[serde(rename="import_descriptor")]
334pub struct MinImportDescriptor {
335 pub dll_name: String,
336 pub functions: Vec<ImportLookupVO>,
338}
339
340impl From<&ImportDescriptor> for MinImportDescriptor {
341 fn from(value: &ImportDescriptor) -> Self {
342 Self {
343 dll_name: value.name.clone().unwrap_or(String::from("ERR")),
344 functions: value.imports
345 .iter()
346 .map(|i| ImportLookupVO::from(i))
347 .collect()
348 }
349 }
350}
351
352
353#[derive(Debug, Serialize)]
354#[serde(rename="export_directory")]
355pub struct MinExportDirectory {
356 pub timestamp: DateTime<Utc>,
357 pub name: String,
358 pub exports: Vec<ExportValue>,
359}
360
361impl From<&ExportDirectory> for MinExportDirectory {
362 fn from(value: &ExportDirectory) -> Self {
363 Self {
364 timestamp: value.timestamp.value,
365 name: value.name.clone(),
366 exports: value.exports
367 .iter()
368 .map(|ex| ExportValue::from(ex))
369 .collect(),
370 }
371 }
372}
373
374
375
376#[derive(Debug, Serialize)]
377pub enum MinRsrcNode {
379 Str(ResourceStringValue),
380 Data(ResourceDataValue),
381 Dir(MinRsrcDirectory)
382}
383
384impl From<&ResourceNode> for MinRsrcNode {
385 fn from(value: &ResourceNode) -> Self {
386 match value {
387 ResourceNode::Str(str) => Self::Str(ResourceStringValue::from(str)),
388 ResourceNode::Data(data) => Self::Data(ResourceDataValue::from(data)),
389 ResourceNode::Dir(dir) => Self::Dir(MinRsrcDirectory::from(dir)),
390 }
391 }
392}
393
394
395#[derive(Debug, Serialize)]
396#[serde(rename="Entry")]
397pub struct MinRsrcEntry {
398 pub id: ResourceType,
399 #[serde(flatten)]
400 pub data: MinRsrcNode,
401}
402
403impl From<&ResourceEntry> for MinRsrcEntry {
404 fn from(rsrc_entry: &ResourceEntry) -> Self {
405 Self { id: rsrc_entry.id, data: MinRsrcNode::from(&rsrc_entry.data) }
406 }
407}
408
409
410#[derive(Debug, Serialize)]
411#[serde(rename="resource_directory")]
412pub struct MinRsrcDirectory {
413 #[serde(rename="number_of_named_entries")]
414 pub named_entry_count: u16,
415 #[serde(rename="number_of_id_entries")]
416 pub id_entry_count: u16,
417 pub entries: Vec<MinRsrcEntry>,
418}
419
420
421impl From<&ResourceDirectory> for MinRsrcDirectory {
422 fn from(rsrc_dir: &ResourceDirectory) -> Self {
423 Self {
424 named_entry_count: rsrc_dir.named_entry_count.value,
425 id_entry_count: rsrc_dir.id_entry_count.value,
426 entries: rsrc_dir.entries
427 .iter()
428 .map(|e| MinRsrcEntry::from(e))
429 .collect(),
430 }
431 }
432}
433
434#[cfg(test)]
435mod tests;