rustbin/pe/ser/
min.rs

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') //has trailing NULL bytes
92                    .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') //magic has traling NULL bytes 
125                    .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') //section name usually has trailing NULL bytes.
278                    .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/** **V**alue **O**nly variant of `ImportLookup`s.  
291  For every member, takes only `value` form `HeaderField`. 
292*/
293#[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    //#[serde(flatten)]
337    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)]
377//#[serde(untagged)]
378pub 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;