Skip to main content

pe_assembler/types/dos/
mod.rs

1use gaia_binary::{LittleEndian, ReadBytesExt};
2use gaia_types::GaiaError;
3use serde::{Deserialize, Serialize};
4use std::io::Read;
5
6/// DOS header structure
7///
8/// Contains basic information about a DOS executable, the first structure in a PE file.
9/// Although modern Windows programs don't run in DOS mode, the PE format still retains this structure for compatibility.
10#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
11pub struct DosHeader {
12    /// DOS signature, usually 0x5A4D ("MZ")
13    pub e_magic: u16,
14    /// Number of bytes in the last page of the file
15    pub e_cblp: u16,
16    /// Total number of pages in the file
17    pub e_cp: u16,
18    /// Number of relocation items
19    pub e_crlc: u16,
20    /// Size of the header in paragraphs
21    pub e_cparhdr: u16,
22    /// Minimum number of paragraphs required
23    pub e_min_allocate: u16,
24    /// Maximum number of paragraphs required
25    pub e_max_allocate: u16,
26    /// Initial SS register value
27    pub e_ss: u16,
28    /// Initial SP register value
29    pub e_sp: u16,
30    /// Checksum
31    pub e_check_sum: u16,
32    /// Initial IP register value
33    pub e_ip: u16,
34    /// Initial CS register value
35    pub e_cs: u16,
36    /// File offset of the relocation table
37    pub e_lfarlc: u16,
38    /// Overlay number
39    pub e_ovno: u16,
40    /// Reserved fields, usually 0
41    pub e_res: [u16; 4],
42    /// OEM identifier
43    pub e_oem_id: u16,
44    /// OEM information
45    pub e_oem_info: u16,
46    /// Reserved fields, usually 0
47    pub e_res2: [u16; 10],
48    /// File offset of the PE header, pointing to the real PE structure
49    pub e_lfanew: u32,
50}
51
52impl Default for DosHeader {
53    fn default() -> Self {
54        Self {
55            e_magic: 0x5A4D, // "MZ"
56            e_cblp: 0x90,
57            e_cp: 0x03,
58            e_crlc: 0x00,
59            e_cparhdr: 0x04,
60            e_min_allocate: 0x00,
61            e_max_allocate: 0xFFFF,
62            e_ss: 0x00,
63            e_sp: 0xB8,
64            e_check_sum: 0x00,
65            e_ip: 0x00,
66            e_cs: 0x00,
67            e_lfarlc: 0x40,
68            e_ovno: 0x00,
69            e_res: [0; 4],
70            e_oem_id: 0x00,
71            e_oem_info: 0x00,
72            e_res2: [0; 10],
73            e_lfanew: 0x80, // PE header offset
74        }
75    }
76}
77
78impl DosHeader {
79    /// Read DOS header from binary reader
80    ///
81    /// # Arguments
82    /// * `reader` - Binary reader
83    ///
84    /// # Returns
85    /// Returns DOS header structure or error
86    pub fn read<R: Read>(mut reader: R) -> Result<Self, GaiaError> {
87        let e_magic = reader.read_u16::<LittleEndian>()?;
88        let e_cblp = reader.read_u16::<LittleEndian>()?;
89        let e_cp = reader.read_u16::<LittleEndian>()?;
90        let e_crlc = reader.read_u16::<LittleEndian>()?;
91        let e_cparhdr = reader.read_u16::<LittleEndian>()?;
92        let e_min_allocate = reader.read_u16::<LittleEndian>()?;
93        let e_max_allocate = reader.read_u16::<LittleEndian>()?;
94        let e_ss = reader.read_u16::<LittleEndian>()?;
95        let e_sp = reader.read_u16::<LittleEndian>()?;
96        let e_check_sum = reader.read_u16::<LittleEndian>()?;
97        let e_ip = reader.read_u16::<LittleEndian>()?;
98        let e_cs = reader.read_u16::<LittleEndian>()?;
99        let e_lfarlc = reader.read_u16::<LittleEndian>()?;
100        let e_ovno = reader.read_u16::<LittleEndian>()?;
101
102        let mut e_res = [0u16; 4];
103        for i in 0..4 {
104            e_res[i] = reader.read_u16::<LittleEndian>()?;
105        }
106
107        let e_oem_id = reader.read_u16::<LittleEndian>()?;
108        let e_oem_info = reader.read_u16::<LittleEndian>()?;
109
110        let mut e_res2 = [0u16; 10];
111        for i in 0..10 {
112            e_res2[i] = reader.read_u16::<LittleEndian>()?;
113        }
114
115        let e_lfanew = reader.read_u32::<LittleEndian>()?;
116
117        Ok(DosHeader {
118            e_magic,
119            e_cblp,
120            e_cp,
121            e_crlc,
122            e_cparhdr,
123            e_min_allocate,
124            e_max_allocate,
125            e_ss,
126            e_sp,
127            e_check_sum,
128            e_ip,
129            e_cs,
130            e_lfarlc,
131            e_ovno,
132            e_res,
133            e_oem_id,
134            e_oem_info,
135            e_res2,
136            e_lfanew,
137        })
138    }
139}
140
141impl DosHeader {
142    /// Create a standard DOS header with specified PE header offset
143    pub fn new(header_offset: u32) -> Self {
144        Self { e_lfanew: header_offset, ..Default::default() }
145    }
146}