rustbin/pe/
mod.rs

1pub mod dos;
2pub mod file;
3pub mod optional;
4pub mod section;
5pub mod import;
6pub mod export;
7pub mod relocs;
8pub mod rsrc;
9pub mod ser;
10
11use std::{
12    fmt::{Display, Write}, fs::File, io::{BufReader, Cursor}, string::{FromUtf16Error, FromUtf8Error}
13};
14
15use derivative::Derivative;
16
17use crate::{types::{BufReadExt, Header, HeaderField, ReadExtError}, Result};
18
19use self::{
20    dos::DosHeader, export::ExportDirectory, file::FileHeader, import::ImportDirectory, 
21    optional::{ parse_data_directories, x64::OptionalHeader64, x86::OptionalHeader32, DataDirectory, DirectoryType, OptionalHeader },
22    relocs::Relocations, 
23    rsrc::ResourceDirectory, 
24    section::{rva_to_section, SectionHeader, SectionTable}
25};
26
27/**
28Returns a `HeaderField` with `value`, `offset` and `rva` from parameters.  
29`offset` is incremented by `size_of_val` of the **value**.  
30If `rva` is not given `rva = offset` is assumed.
31*/
32#[macro_export]
33macro_rules! new_header_field {
34    ($value:expr, $offset:ident, $rva:expr) => {
35        #[allow(unused_assignments)]
36        {
37            use std::mem::size_of_val;
38
39            let old_offset = $offset;
40            let v = $value;
41            
42            $offset += size_of_val(&v) as u64;
43            
44            HeaderField{
45                value: v,
46                offset: old_offset,
47                rva: $rva
48            }
49        }
50    };
51    
52    ($value:expr, $offset:ident) => {
53        {
54            let old_offset = $offset;
55            new_header_field!($value, $offset, old_offset)
56        }
57    };
58}
59
60#[derive(Debug, thiserror::Error)]
61pub enum PeError {
62    #[error("not enough data for {target}; expected {expected}, got {actual}")]
63    #[non_exhaustive]
64    BufferTooSmall {
65        target: String,
66        expected: u64,
67        actual: u64,
68    },
69
70    #[error("invalid timestamp 0x{0:08x}")]
71    #[non_exhaustive]
72    InvalidTimestamp(u64),
73
74    #[error("invalid rva 0x{0:08x}")]
75    #[non_exhaustive]
76    InvalidRVA(u64),
77
78    #[error("invalid offset 0x{0:08x}")]
79    #[non_exhaustive]
80    InvalidOffset(u64),
81    
82    #[error("failed to parse {name} header at offset {offset:08x}; {reason}")]
83    #[non_exhaustive]
84    InvalidHeader {
85        name: String,
86        offset: u64,
87        reason: String,
88    },
89
90    #[error("can't find section for rva {0:08x}")]
91    #[non_exhaustive]
92    NoSectionForRVA(u64),
93
94    #[error("can't find section for offset {0:08x}")]
95    #[non_exhaustive]
96    NoSectionForOffset(u64),
97
98    #[error(transparent)]
99    ReadExt(#[from] ReadExtError),
100
101    #[error(transparent)]
102    IO(#[from] std::io::Error),
103
104    #[error("PE file must have optional header")]
105    MustHaveOptional,
106
107    #[error(transparent)]
108    FromUtf8 (#[from] FromUtf8Error),
109
110    #[error(transparent)]
111    FromUtf16 (#[from] FromUtf16Error),
112
113    #[error("{typ} {value:08x} is beyond {name} range [{start:08x}..{end:08x}]")]
114    #[non_exhaustive]
115    BeyondRange {
116        name: String,
117        typ: String,
118        value: u64,
119        start: u64,
120        end: u64,
121    }
122}
123
124
125pub const SECTION_HEADER_LENGTH: u64 = section::HEADER_LENGTH;
126
127#[derive(Derivative)]
128#[derivative(Debug)]
129pub struct PeImage {
130    pub dos: HeaderField<DosHeader>,
131    pub file: HeaderField<FileHeader>,
132    pub optional: HeaderField<OptionalHeader>,
133    pub data_dirs: HeaderField<Vec<HeaderField<DataDirectory>>>,
134    pub sections: HeaderField<SectionTable>,
135    pub imports: HeaderField<ImportDirectory>,
136    pub exports: HeaderField<ExportDirectory>,
137    pub relocations: HeaderField<Relocations>,
138    pub resources: HeaderField<ResourceDirectory>,
139
140    #[derivative(Debug="ignore")]
141    reader: Box<dyn BufReadExt>,
142}
143
144impl PeImage {
145    pub fn new(reader: Box<dyn BufReadExt>) -> Self {
146        Self { 
147            dos: Default::default(), 
148            file: Default::default(),
149            optional: Default::default(),
150            data_dirs: Default::default(),
151            sections: Default::default(),
152            imports: Default::default(),
153            exports: Default::default(),
154            relocations: Default::default(),
155            resources: Default::default(),
156            reader
157        }
158    }
159
160    pub fn directory_offset(&self, dir: DirectoryType) -> Option<u32> {
161        if let Some(dir) = self.directory(dir) {
162            let rva = dir.rva.value;
163            section::rva_to_offset(&self.sections.value, rva)
164        }
165        else {
166            None
167        }
168    }
169
170    pub fn directory_section(&self, dir: DirectoryType) -> Option<&SectionHeader> {
171        if let Some(dir) = self.directory(dir) {
172            let rva = dir.rva.value;
173            section::rva_to_section(&self.sections.value, rva)
174        }
175        else {
176            None
177        }
178    }
179
180    #[inline]
181    pub fn directory(&self, dir: DirectoryType) -> Option<&DataDirectory> {
182        let dir = &self.data_dirs.value[dir as usize].value;
183        if dir.rva.value == 0 {None} else {Some(&dir)}
184    }
185
186    #[inline]
187    pub fn rva_to_offset(&self, rva: u32) -> Option<u32> {
188        section::rva_to_offset(&self.sections.value, rva)
189    }
190
191    #[inline]
192    pub fn offset_to_rva(&self, offset: u64) -> Option<u32> {
193        section::offset_to_rva(&self.sections.value, offset as u32)
194    }
195
196    pub fn read_string_at_rva(&mut self, rva: u32) -> std::result::Result<String, PeError> {
197        let offset = self.rva_to_offset(rva).ok_or(PeError::InvalidRVA(rva.into()))?;
198        Ok(self.reader.read_string_at_offset(offset.into())?)
199    }
200
201    #[inline]
202    pub fn has_imports(&self) -> bool {
203        self.data_dirs.value[DirectoryType::Import as usize].value.rva.value != 0
204    }
205
206    pub fn parse_import_directory(&mut self) -> std::result::Result<(), PeError> {
207        if !self.has_imports() {
208            return Ok(());
209        }
210
211        let import_dd = &self.data_dirs.value[DirectoryType::Import as usize].value;
212        let import_rva = import_dd.rva.value;
213        let import_size = import_dd.size.value;
214        let import_offset = self.rva_to_offset(import_rva).ok_or(PeError::InvalidRVA(import_rva.into()))?;
215        
216        //let mut reader = FragmentReader::new(&self.reader);
217        let bytes = self.reader.read_bytes_at_offset(import_offset as u64, import_size as usize)?;
218    
219        let mut imp_dir = ImportDirectory::parse_bytes(bytes, import_rva as u64)?;
220
221        for i in 0..imp_dir.len() {
222            let id = &mut imp_dir[i].value;
223            id.update_name(&self.sections.value, &mut self.reader)?;
224            id.parse_imports(&self.sections.value, self.optional.value.get_image_type(), &mut self.reader)?;
225        }
226        self.imports = HeaderField{ value: imp_dir, offset:import_offset as u64, rva:import_rva as u64};
227        
228        Ok(())
229    }
230
231    #[inline]
232    pub fn has_exports(&self) -> bool {
233        self.data_dirs.value[DirectoryType::Export as usize].value.rva.value != 0
234    }
235
236    pub fn parse_exports(&mut self) -> Result<()> {
237        let dd_export = &self.data_dirs.value[DirectoryType::Export as usize].value;
238        if !self.has_exports() {
239            return Ok(());
240        }
241
242        let export_rva = dd_export.rva.value;
243        let export_offset = self.rva_to_offset(export_rva).ok_or(PeError::InvalidRVA(export_rva.into()))?;
244
245        //let mut reader = FragmentReader::new(&self.reader);
246        let bytes = self.reader.read_bytes_at_offset(export_offset.into(), export::HEADER_LENGTH as usize)?;
247        
248        let mut export_dir = ExportDirectory::parse_bytes(bytes, export_offset.into())?;
249        if !export_dir.is_valid() {
250            return Err(
251                PeError::InvalidHeader { name: "Export".into(), offset: export_offset.into(), reason: "structure is invalid".into() }
252            );
253        }
254
255        export_dir.parse_exports(&self.sections.value, &mut self.reader)?;
256        
257        self.exports = HeaderField {
258            value: export_dir, 
259            offset: export_offset.into(), 
260            rva: export_rva.into() 
261        };
262
263        Ok(())
264    }
265
266    #[inline]
267    pub fn has_relocations(&self) -> bool{
268        self.data_dirs.value[DirectoryType::Relocation as usize].value.rva.value != 0
269    }
270
271    pub fn parse_relocations(&mut self) -> Result<()> {
272        if !self.has_relocations() {
273            return Ok(());
274        }
275
276        let dd_relocs = &self.data_dirs.value[DirectoryType::Relocation as usize].value;
277        let relocs_rva = dd_relocs.rva.value;
278        let relocs_size = dd_relocs.size.value as usize;
279        let relocs_offset = self.rva_to_offset(relocs_rva.into()).ok_or(PeError::NoSectionForRVA(relocs_rva.into()))?;
280
281        //let mut reader = FragmentReader::new(&self.reader);
282        let bytes = self.reader.read_bytes_at_offset(relocs_offset.into(), relocs_size)?;
283
284        let mut relocs = Relocations::parse_bytes(bytes, relocs_offset.into())?;
285        relocs.fix_rvas(relocs_rva.into())?;
286        self.relocations = HeaderField {value: relocs, offset: relocs_offset.into(), rva: relocs_rva.into()};
287
288        Ok(())
289    }
290
291    #[inline]
292    pub fn has_rsrc(&self) -> bool {
293        self.data_dirs.value[DirectoryType::Resource as usize].value.rva.value != 0
294    }
295
296    pub fn parse_resources(&mut self) -> Result<()> {
297        if !self.has_rsrc() {
298            return Ok(())
299        }
300
301        let dd_rsrc = &self.data_dirs.value[DirectoryType::Resource as usize].value;
302        let rsrc_rva = dd_rsrc.rva.value;
303        let rsrc_offset = self.rva_to_offset(rsrc_rva.into()).ok_or(PeError::NoSectionForRVA(rsrc_rva.into()))?;
304        let rsrc_section = rva_to_section(&self.sections.value, rsrc_rva)
305            .ok_or(PeError::NoSectionForRVA(rsrc_rva.into()))?;
306        
307        let bytes = self.reader.read_bytes_at_offset(rsrc_offset.into(), rsrc::DIR_LENGTH as usize)?;
308
309        let mut rsrc_dir = ResourceDirectory::parse_bytes(bytes, rsrc_offset.into())?;
310        rsrc_dir.parse_rsrc(rsrc_section, &mut self.reader)?;
311        self.resources = HeaderField{value: rsrc_dir, offset: rsrc_offset.into(), rva: rsrc_rva.into()};
312
313        Ok(())
314    }
315
316    #[inline]
317    pub fn format_resource_tree(&self, f: &mut dyn Write, seperator: &String, level: u8) -> std::fmt::Result {
318        writeln!(f, "Resource Directory: {{")?;
319        rsrc::display_rsrc_tree(&self.resources.value, f, seperator, level)?;
320        writeln!(f, "}}")
321    }
322
323    pub fn format_basic_headers(&self, f: &mut dyn Write) -> std::fmt::Result {
324        writeln!(f, "DosHeader: {}", self.dos.value)?;
325        writeln!(f, "FileHeader: {}", self.file.value)?;
326        writeln!(f, "OptionalHeader: {}", self.optional.value)?;
327
328        Ok(())
329    }
330
331    pub fn format_data_dirs(&self, f: &mut dyn Write) -> std::fmt::Result {
332        //Data directories
333        writeln!(f, "DataDirectories: [")?;
334        for dir in &self.data_dirs.value {
335            if dir.value.rva.value != 0 {
336                write!(f, "  {}, ", dir)?;
337                let section = self.directory_section(dir.value.member);
338                if let Some(sec) = section {
339                    writeln!(f, " Section: {},", sec.name_str().unwrap_or_else(|err| format!("{err}")))?;
340                }
341                println!("");
342            }
343        }
344        writeln!(f, "]")
345    }
346
347    pub fn format_sections(&self, f: &mut dyn Write) -> std::fmt::Result {
348        writeln!(f, "Sections: [")?;
349        for sec in &self.sections.value {
350            write!(f, "  {sec}, ")?;
351            let dirs = sec.value.directories(&self.data_dirs.value);
352            if dirs.len() > 0 { writeln!(f, "Directories: {dirs:?},")?;} else {writeln!(f, "")?;}
353        }
354        writeln!(f, "]")
355    }
356
357    pub fn format_imports(&self, f: &mut dyn Write) -> std::fmt::Result {
358        if self.has_imports() && self.imports.value.is_valid() {
359            writeln!(f, "Import Directory: [")?;
360            let idir = &self.imports.value;
361            for idesc in idir {
362                writeln!(f, " {}\n [", idesc.value)?;
363                for imp_name in idesc.value.get_imports_str() {
364                    writeln!(f, "    {imp_name}",)?;
365                }
366                writeln!(f, "  ]")?;
367            }
368            writeln!(f, "]")?;
369        }
370
371        Ok(())
372    }
373
374    pub fn format_exports(&self, f: &mut dyn Write) -> std::fmt::Result {
375        if self.has_exports() && self.exports.value.is_valid() {
376            writeln!(f, "Export Directory: {{")?;
377            let export_dir = &self.exports.value;
378            writeln!(f, "  DLL Name: {}", export_dir.name)?;
379            writeln!(f, "  Exports: [")?;
380            
381            for export in &export_dir.exports {
382                writeln!(f, "    {export}")?;
383            }
384            
385            writeln!(f, "  ]")?;
386            writeln!(f, "}}")?;
387        }
388
389        Ok(())
390    }
391
392    pub fn format_relocations(&self, f: &mut dyn Write) -> std::fmt::Result {
393        if self.has_relocations() && self.relocations.value.is_valid() {
394            writeln!(f, "Relocation Directory: [")?;
395            for rb in &self.relocations.value.blocks {
396                writeln!(f, "  [{rb}")?;
397                for rc in &rb.value.relocs {
398                    writeln!(f, "    {}", rc.value)?;
399                }
400                writeln!(f, "  ]")?;
401            }
402            writeln!(f, "]")?;
403        }
404
405        Ok(())
406    }
407
408    ///Parse fixed sized header from `pos`.
409    pub(crate) fn parse_fixed_headers(&mut self, pos: u64) -> Result<u64> {
410        let mut offset = pos;
411
412        let mut buf = self.reader.read_bytes_at_offset(pos, dos::HEADER_LENGTH as usize)?;
413        self.dos = HeaderField{ value: DosHeader::parse_bytes(buf, pos)?, offset: offset, rva: offset };
414        offset += self.dos.value.e_lfanew.value as u64;
415
416        buf = self.reader.read_bytes_at_offset(offset, file::HEADER_LENGTH as usize)?;
417        self.file = HeaderField{ value: FileHeader::parse_bytes(buf, offset)?, offset: offset, rva: offset};
418        offset += file::HEADER_LENGTH;
419
420        buf = self.reader.read_bytes_at_offset(offset, self.file.value.optional_header_size.value as usize)?;
421
422        match buf.len() {
423            //(optional::x86::HEADER_LENGTH + DATA_DIR_LENGTH * 16)
424            0xE0 => {
425                let opt = OptionalHeader32::parse_bytes(buf.clone(), offset)?;
426                self.optional = HeaderField{ value: OptionalHeader::X86(opt), offset: offset, rva: offset};
427                offset += optional::x86::HEADER_LENGTH;
428
429                let dir_buf = &buf[optional::x86::HEADER_LENGTH as usize..];
430                let dirs = parse_data_directories(&dir_buf, 16, offset)?;
431                self.data_dirs = HeaderField{ value: dirs, offset: offset, rva: offset};
432                offset += 16 * 8;
433            },
434
435            //(optional::x64::HEADER_LENGTH + DATA_DIR_LENGTH * 16)
436            0xF0 => {
437                let opt = OptionalHeader64::parse_bytes(buf.clone(), offset)?;
438                self.optional = HeaderField {value: OptionalHeader::X64(opt), offset: offset, rva: offset};
439                offset += optional::x64::HEADER_LENGTH;
440
441                let dir_buf = &buf[optional::x64::HEADER_LENGTH as usize..];
442                let dirs = parse_data_directories(&dir_buf, 16, offset)?;
443                self.data_dirs = HeaderField{ value: dirs, offset: offset, rva: offset};
444                offset += 16 * 8;
445            },
446
447            _ => {
448                return Err(PeError::MustHaveOptional)
449            }
450        }
451
452        Ok(offset)
453    }
454
455    /// Parse section headers. 
456    /// These are fixed sized contigious values, and size is known from OptionalHeader.
457    pub(crate) fn parse_sections(&mut self, pos: u64) -> Result<u64> {
458        let mut offset = pos;
459        let sec_count = self.file.value.sections.value;
460        let size = section::HEADER_LENGTH * sec_count as u64;
461        
462        let buf = self.reader.read_bytes_at_offset(offset, size as usize)?;
463        let sections = section::parse_sections(&buf, sec_count, offset)?;
464        self.sections = HeaderField{ value:sections, offset: offset, rva: offset};
465        
466        offset += size;
467
468        Ok(offset)
469    }
470
471    /// Parse headers whose contents may be scattered.
472    /// Content offsets are derived from parsed header values.
473    pub(crate) fn parse_dynamic_headers(&mut self) -> Result<()> {
474        self.parse_import_directory()?;
475        self.parse_exports()?;
476        self.parse_relocations()?;
477        self.parse_resources()?;
478        Ok(())
479    }
480
481    pub(crate) fn parse_all_headers(&mut self, pos: u64) -> Result<()> {
482        let offset = self.parse_fixed_headers(pos)?;
483        self.parse_sections(offset)?;
484        self.parse_dynamic_headers()?;
485        Ok(())
486    }
487
488    ///Parse a 'readable' file from disk into PE Image.  
489    /// In case of error while reading or parsing file, a `dyn Error` is returned.  
490    /// Params:
491    /// - `f`: input file handle
492    /// - `pos`: starting `pos`ition of PE content in file. Use `0` (other values are not tested).
493    pub fn parse_file(file: File, pos: u64) -> crate::Result<Self> where Self: Sized {
494        let reader = Box::new(BufReader::new(file));
495        let mut pe = Self::new(reader);
496        
497        pe.parse_all_headers(pos)?;
498
499        Ok(pe)
500    }
501    
502    ///Parse an in-memory `[u8]` buffer into PE Image. The buffer must contain content for entire PE image.
503    /// In case of error while reading or parsing, a `dyn Error` is returned.
504    /// Params:
505    /// - `bytes`: `Vec` of `u8`
506    /// - `pos`: starting `pos`ition of PE content in `bytes`. Use `0` (other values are not tested).
507    pub fn parse_bytes(bytes: Vec<u8>, pos: u64) -> crate::Result<Self> where Self: Sized {
508        let reader = Box::new(Cursor::new(bytes));
509        let mut pe = Self::new(reader);
510
511        pe.parse_all_headers(pos)?;
512
513        Ok(pe)
514    }
515
516
517    ///Parse a PE Image from a `readable` type.  
518    /// In case of error while reading or parsing, a `dyn Error` is returned.  
519    /// **Params:**
520    /// - `reader`: readable source in `Box`, must implement `BuffReadExt` from this crate.
521    /// - `pos`: starting `pos`ition of PE content. Use `0` (other values are not tested).
522    pub fn parse_readable(reader: Box<dyn BufReadExt>, pos: u64) -> crate::Result<Self> where Self: Sized {
523        let mut pe = Self::new(reader);
524        
525        pe.parse_all_headers(pos)?;
526        
527        Ok(pe)
528    }
529}
530
531
532impl TryFrom<File> for PeImage{
533    type Error = PeError;
534
535    fn try_from(value: File) -> Result<Self> {
536        Self::parse_file(value, 0)
537    }
538}
539
540impl TryFrom<Vec<u8>> for PeImage {
541    type Error = PeError;
542
543    fn try_from(value: Vec<u8>) -> Result<Self> {
544        Self::parse_bytes(value, 0)
545    }
546}
547
548impl TryFrom<Box<dyn BufReadExt>> for PeImage{
549    type Error = PeError;
550
551    fn try_from(value: Box<dyn BufReadExt>) -> Result<Self> {
552        Self::parse_readable(value, 0)
553    }
554}
555
556
557impl Display for PeImage {
558    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
559       
560        //Basic headers
561        self.format_basic_headers(f)?;
562        //Data dirs
563        self.format_data_dirs(f)?;
564        //Sections
565        self.format_sections(f)?;
566        //Imports
567        if self.has_imports() { self.format_imports(f)?; }
568        //Exports
569        if self.has_exports() { self.format_exports(f)?; }
570        //Relocations
571        if self.has_relocations() { self.format_relocations(f)?; }
572        //Resources
573        if self.has_rsrc() && self.resources.value.is_valid() {
574            self.format_resource_tree(f, &String::from("  "), 1)?;
575        }
576
577        Ok(())
578    }
579}
580
581#[cfg(test)]
582mod tests {
583    //use std::assert_matches::assert_matches;
584
585    use std::io::Cursor;
586
587    use crate::{
588        pe::{optional::{DirectoryType, ImageType, OptionalHeader, MAX_DIRS}, section::Flags},
589        types::{Header, BufReadExt},
590    };
591
592    use super::PeImage;
593
594    const RAW_BYTES_64: [u8; 704] = [
595        0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
596        0x00, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
597        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
598        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
599        0xF0, 0x00, 0x00, 0x00, 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01,
600        0x4C, 0xCD, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D,
601        0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20,
602        0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A,
603        0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x93, 0xC1, 0x57, 0x47, 0xF2, 0xAF,
604        0x04, 0x47, 0xF2, 0xAF, 0x04, 0x47, 0xF2, 0xAF, 0x04, 0x4E, 0x8A, 0x3C, 0x04, 0x4B, 0xF2,
605        0xAF, 0x04, 0x2B, 0x86, 0xAE, 0x05, 0x45, 0xF2, 0xAF, 0x04, 0x2B, 0x86, 0xAA, 0x05, 0x51,
606        0xF2, 0xAF, 0x04, 0x2B, 0x86, 0xAB, 0x05, 0x4E, 0xF2, 0xAF, 0x04, 0x2B, 0x86, 0xAC, 0x05,
607        0x44, 0xF2, 0xAF, 0x04, 0x1C, 0x9A, 0xAE, 0x05, 0x4E, 0xF2, 0xAF, 0x04, 0x47, 0xF2, 0xAE,
608        0x04, 0xEB, 0xF2, 0xAF, 0x04, 0x47, 0xF2, 0xAF, 0x04, 0xDD, 0xF2, 0xAF, 0x04, 0x91, 0x86,
609        0xAD, 0x05, 0x46, 0xF2, 0xAF, 0x04, 0x52, 0x69, 0x63, 0x68, 0x47, 0xF2, 0xAF, 0x04, 0x00,
610        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
611        0x50, 0x45, 0x00, 0x00, 0x64, 0x86, 0x05, 0x00, 0x91, 0xC0, 0x02, 0x62, 0x00, 0x00, 0x00,
612        0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x22, 0x00, 0x0B, 0x02, 0x0E, 0x1C, 0x00, 0x2A,
613        0x04, 0x00, 0x00, 0x58, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0x1D, 0x04, 0x00, 0x00,
614        0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
615        0x00, 0x02, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,
616        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
617        0x00, 0x00, 0x03, 0x00, 0x60, 0x81, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
618        0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
619        0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
620        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x42, 0x05, 0x00, 0xB4, 0x00,
621        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x05, 0x00, 0xFC,
622        0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x05, 0x00,
623        0xF8, 0x05, 0x00, 0x00, 0x40, 0xC7, 0x04, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
624        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC9,
625        0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0xA0, 0xC7, 0x04, 0x00, 0x38, 0x01, 0x00, 0x00, 0x00,
626        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0x00, 0x08, 0x03, 0x00, 0x00,
627        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
628        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x74, 0x65, 0x78, 0x74, 0x00,
629        0x00, 0x00, 0x47, 0x29, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x2A, 0x04, 0x00, 0x00,
630        0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
631        0x20, 0x00, 0x00, 0x60, 0x2E, 0x72, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0xD6, 0x0D, 0x01,
632        0x00, 0x00, 0x40, 0x04, 0x00, 0x00, 0x0E, 0x01, 0x00, 0x00, 0x2E, 0x04, 0x00, 0x00, 0x00,
633        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x2E,
634        0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x68, 0x03, 0x00, 0x00, 0x00, 0x50, 0x05, 0x00,
635        0x00, 0x02, 0x00, 0x00, 0x00, 0x3C, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
636        0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0xC0, 0x2E, 0x70, 0x64, 0x61, 0x74, 0x61,
637        0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00, 0x00, 0x60, 0x05, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
638        0x3E, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
639        0x40, 0x00, 0x00, 0x40, 0x2E, 0x72, 0x65, 0x6C, 0x6F, 0x63, 0x00, 0x00, 0xF8, 0x05, 0x00,
640        0x00, 0x00, 0xA0, 0x05, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x7E, 0x05, 0x00, 0x00, 0x00,
641        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x42,
642    ];
643
644    #[test]
645    fn parse_valid_header_x64() {
646        let reader = Box::new(Cursor::new(RAW_BYTES_64.to_vec()));
647        let mut pe = PeImage::new(reader);
648        let offset = pe.parse_fixed_headers(0).unwrap();
649        pe.parse_sections(offset).unwrap();
650        assert!(pe.dos.value.is_valid());
651        assert_eq!(pe.dos.offset, 0);
652        assert_eq!(pe.dos.rva, 0);
653        assert!(pe.file.value.is_valid());
654        assert_eq!(pe.file.offset, 0xf0);
655        assert_eq!(pe.file.rva, 0xf0);
656        assert_eq!(pe.optional.offset, 0x108);
657        assert_eq!(pe.optional.rva, 0x108);
658        
659        if let OptionalHeader::X64(opt) = pe.optional.value {
660            assert_eq!(opt.magic.value, ImageType::PE64);
661        }
662        else {
663            assert!(false, "Didn't expect OptionalHeader32");
664        }
665
666        assert_eq!(pe.data_dirs.offset, 0x178);
667        assert_eq!(pe.data_dirs.value.len(), MAX_DIRS as usize);
668        assert_eq!(pe.data_dirs.value[DirectoryType::ImportAddressTable as usize].offset, 0x1d8);
669        assert_eq!(pe.data_dirs.value[DirectoryType::ImportAddressTable as usize].value.rva.value, 0x00044000);
670        assert_eq!(pe.data_dirs.value[DirectoryType::ImportAddressTable as usize].value.size.value, 0x00000308);
671        /*
672        Sections
673        0@1f8: .text,  VS: 42947, VA: 1000,  RS: 42A00, RA: 400,   CH: 60000020
674        1@220: .rdata, VS: 10dd6, VA: 44000, RS: 10E00, RA: 42E00, CH: 40000040
675        2@248: .data,  VS: 368,   VA: 55000, RS: 200,   RA: 53C00, CH: C0000040
676        3@270: .pdata, VS: 3FFC,  VA: 56000, RS: 4000,  RA: 53E00, CH: 40000040
677        4@298: .reloc, VS: 5f8,   VA: 5A000, RS: 600,   RA: 57E00, CH: 42000040
678        */
679
680        assert_eq!(pe.sections.value.len(), 5);
681        let sec_names = [
682            ".text",
683            ".rdata",
684            ".data",
685            ".pdata",
686            ".reloc"
687        ];
688        
689        let sec_flags = [
690            Flags::CODE | Flags::MEM_READ | Flags::MEM_EXECUTE,
691            Flags::INITIALIZED_DATA | Flags::MEM_READ,
692            Flags::INITIALIZED_DATA | Flags::MEM_READ | Flags::MEM_WRITE,
693            Flags::INITIALIZED_DATA | Flags::MEM_READ,
694            Flags::INITIALIZED_DATA | Flags::MEM_READ | Flags::MEM_DISCARDABLE,
695        ];
696
697        for i in 0..5 {
698            let sec = &pe.sections.value[i].value;
699            assert_eq!(sec.name_str().unwrap(), sec_names[i]);
700            assert_eq!(sec.flags().unwrap(), sec_flags[i]);
701        }
702    }
703
704    #[test]
705    fn read_string_at_offset() {
706        //let pe = PeImage::parse_bytes(RAW_BYTES_64.to_vec(), 0).unwrap();
707        let mut cursor = Cursor::new(&RAW_BYTES_64);
708        assert_eq!(cursor.read_string_at_offset(0x1f8).unwrap().as_str(), ".text");
709    }
710
711    const RAW_BYTES_32: [u8; 784] = [
712        0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
713        0x00, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
714        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
715        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
716        0x10, 0x01, 0x00, 0x00, 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01,
717        0x4C, 0xCD, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D,
718        0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20,
719        0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A,
720        0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x96, 0x94, 0xCA, 0x72, 0xF7, 0xFA,
721        0x99, 0x72, 0xF7, 0xFA, 0x99, 0x72, 0xF7, 0xFA, 0x99, 0xC6, 0x6B, 0x0B, 0x99, 0x78, 0xF7,
722        0xFA, 0x99, 0xC6, 0x6B, 0x09, 0x99, 0xF6, 0xF7, 0xFA, 0x99, 0xC6, 0x6B, 0x08, 0x99, 0x6A,
723        0xF7, 0xFA, 0x99, 0x49, 0xA9, 0xF9, 0x98, 0x60, 0xF7, 0xFA, 0x99, 0x49, 0xA9, 0xFF, 0x98,
724        0x51, 0xF7, 0xFA, 0x99, 0x49, 0xA9, 0xFE, 0x98, 0x60, 0xF7, 0xFA, 0x99, 0xAF, 0x08, 0x34,
725        0x99, 0x73, 0xF7, 0xFA, 0x99, 0xAF, 0x08, 0x31, 0x99, 0x75, 0xF7, 0xFA, 0x99, 0x72, 0xF7,
726        0xFB, 0x99, 0x06, 0xF7, 0xFA, 0x99, 0xE5, 0xA9, 0xF3, 0x98, 0x77, 0xF7, 0xFA, 0x99, 0xE0,
727        0xA9, 0x05, 0x99, 0x73, 0xF7, 0xFA, 0x99, 0x72, 0xF7, 0x6D, 0x99, 0x73, 0xF7, 0xFA, 0x99,
728        0xE5, 0xA9, 0xF8, 0x98, 0x73, 0xF7, 0xFA, 0x99, 0x52, 0x69, 0x63, 0x68, 0x72, 0xF7, 0xFA,
729        0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
730        0x00, 0x00, 0x50, 0x45, 0x00, 0x00, 0x4C, 0x01, 0x06, 0x00, 0xA0, 0x65, 0x08, 0x58, 0x00,
731        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x02, 0x01, 0x0B, 0x01, 0x0E, 0x00,
732        0x00, 0xBC, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x20, 0x00,
733        0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x10,
734        0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
735        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00,
736        0xF1, 0xE2, 0x01, 0x00, 0x02, 0x00, 0x40, 0x81, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00,
737        0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
738        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x26, 0x01, 0x00, 0x50,
739        0x00, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0xE8, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
740        0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x01, 0x00, 0xB8, 0x1E, 0x00, 0x00, 0x00, 0xD0, 0x01,
741        0x00, 0x98, 0x0F, 0x00, 0x00, 0x80, 0x1D, 0x01, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,
742        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
743        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x1D, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00,
744        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x74, 0x01, 0x00,
745        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
746        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x74, 0x65, 0x78, 0x74,
747        0x00, 0x00, 0x00, 0xEB, 0xBB, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xBC, 0x00, 0x00,
748        0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
749        0x00, 0x20, 0x00, 0x00, 0x60, 0x2E, 0x72, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x8E, 0x5F,
750        0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,
751        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40,
752        0x2E, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x78, 0x13, 0x00, 0x00, 0x00, 0x30, 0x01,
753        0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
754        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0xC0, 0x2E, 0x67, 0x66, 0x69, 0x64,
755        0x73, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00,
756        0x00, 0x28, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
757        0x00, 0x40, 0x00, 0x00, 0x40, 0x2E, 0x72, 0x73, 0x72, 0x63, 0x00, 0x00, 0x00, 0xE8, 0x64,
758        0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x2A, 0x01, 0x00, 0x00,
759        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40,
760        0x2E, 0x72, 0x65, 0x6C, 0x6F, 0x63, 0x00, 0x00, 0x98, 0x0F, 0x00, 0x00, 0x00, 0xD0, 0x01,
761        0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
762        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00,
763        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
764        0x00, 0x00, 0x00, 0x00,
765    ];
766
767    #[test]
768    fn parse_valid_header_x86() {
769        let reader = Box::new(Cursor::new(RAW_BYTES_32.to_vec()));
770        let mut pe = PeImage::new(reader);
771        
772        let offset = pe.parse_fixed_headers(0).unwrap();
773        pe.parse_sections(offset).unwrap();
774
775        assert!(pe.dos.value.is_valid());
776        assert_eq!(pe.dos.offset, 0);
777        assert_eq!(pe.dos.rva, 0);
778        assert!(pe.file.value.is_valid());
779        assert_eq!(pe.file.offset, 0x110);
780        assert_eq!(pe.file.rva, 0x110);
781        assert_eq!(pe.optional.offset, 0x128);
782        assert_eq!(pe.optional.rva, 0x128);
783
784        if let OptionalHeader::X86(opt) = pe.optional.value {
785            assert!(opt.is_valid());
786        }
787        else {
788            assert!(false, "Didn't expect OptionalHeader64");
789        }
790
791        assert_eq!(pe.data_dirs.offset, 0x188);
792        assert_eq!(pe.data_dirs.value.len(), MAX_DIRS as usize);
793        assert_eq!(pe.data_dirs.value[DirectoryType::ImportAddressTable as usize].offset, 0x1e8);
794        assert_eq!(pe.data_dirs.value[DirectoryType::ImportAddressTable as usize].value.rva.value,  0x0000D000);
795        assert_eq!(pe.data_dirs.value[DirectoryType::ImportAddressTable as usize].value.size.value, 0x00000174);
796
797        let sections = pe.sections.value;
798        assert_eq!(sections.len(), 6);
799        let names = [".text", ".rdata", ".data", ".gfids", ".rsrc", ".reloc"];
800        let sec_flags = [
801            Flags::CODE | Flags::MEM_READ | Flags::MEM_EXECUTE,
802            Flags::INITIALIZED_DATA | Flags::MEM_READ,
803            Flags::INITIALIZED_DATA | Flags::MEM_READ | Flags::MEM_WRITE,
804            Flags::INITIALIZED_DATA | Flags::MEM_READ,
805            Flags::INITIALIZED_DATA | Flags::MEM_READ,
806            Flags::INITIALIZED_DATA | Flags::MEM_READ | Flags::MEM_DISCARDABLE,
807        ];
808        for i in 0..6 {
809            let hf_section = &sections[i];
810            let sh = &hf_section.value;
811            assert!(sh.is_valid());
812            assert_eq!(sh.name_str().unwrap(), names[i]);
813            assert_eq!(sh.flags().unwrap(), sec_flags[i]);
814        }
815    }
816
817    #[test]
818    fn section_of_directories() {
819        let reader = Box::new(Cursor::new(RAW_BYTES_32.to_vec()));
820        let mut pe = PeImage::new(reader);
821        let offset = pe.parse_fixed_headers(0).unwrap();
822        pe.parse_sections(offset).unwrap();
823
824        assert_eq!(pe.directory_section(DirectoryType::Import).unwrap().name_str().unwrap(), ".rdata");
825        assert_eq!(pe.directory_section(DirectoryType::Resource).unwrap().name_str().unwrap(), ".rsrc");
826        assert_eq!(pe.directory_section(DirectoryType::Security).unwrap().name_str().unwrap(), ".rsrc");
827        assert_eq!(pe.directory_section(DirectoryType::Relocation).unwrap().name_str().unwrap(), ".reloc");
828        assert_eq!(pe.directory_section(DirectoryType::Debug).unwrap().name_str().unwrap(), ".rdata");
829        assert_eq!(pe.directory_section(DirectoryType::Configuration).unwrap().name_str().unwrap(), ".rdata");
830        assert_eq!(pe.directory_section(DirectoryType::ImportAddressTable).unwrap().name_str().unwrap(), ".rdata");
831    }
832}