pe_parser/
section.rs

1use bytemuck::checked::try_from_bytes;
2use bytemuck::{Pod, Zeroable};
3use bitflags::bitflags;
4use core::{fmt, str};
5use core::writeln;
6use crate::prelude::*;
7
8/// Parse the section table from a byte array at a given offset.
9/// `number_of_sections` should be equal to number of sections
10/// defined in the COFF header.
11pub fn parse_section_table(binary: &[u8], offset: usize, number_of_sections: u16) -> Vec<SectionHeader> {
12    let mut offset = offset;
13    let mut headers: Vec<SectionHeader> = Vec::new();
14    let header_size = size_of::<SectionHeader>();
15
16    for _ in 0..number_of_sections {
17        if let Some(slice) = binary.get(offset..offset+header_size) {
18            if let Ok(header) = try_from_bytes::<SectionHeader>(slice) {
19                headers.push(*header);
20            }
21        }
22        offset += header_size;
23    }
24
25    headers
26}
27
28/// Contains information such as name, size, characteristics
29/// and location of a section in the binary
30#[derive(Copy, Clone, Pod, Zeroable, Default)]
31#[repr(C)]
32pub struct SectionHeader {
33    /// An 8-byte, null-padded UTF-8 encoded string. 
34    /// If the string is exactly 8 characters long, there is no terminating null. 
35    /// For longer names, this field contains a slash (/) that is followed by an ASCII representation of a decimal number that is an offset into the string table. 
36    /// Executable images do not use a string table and do not support section names longer than 8 characters. 
37    /// Long names in object files are truncated if they are emitted to an executable file.
38    pub name: [u8; 8],
39    /// The total size of the section when loaded into memory. 
40    /// If this value is greater than `size_of_raw_data`, the section is zero-padded. 
41    /// This field is valid only for executable images and should be set to zero for object files.
42    pub virtual_size: u32,
43    /// For executable images, the address of the first byte of the section relative to the image base when the section is loaded into memory.
44    /// For object files, this field is the address of the first byte before relocation is applied; for simplicity, compilers should set this to zero.
45    /// Otherwise, it is an arbitrary value that is subtracted from offsets during relocation.
46    pub virtual_address: u32,
47    /// The size of the section (for object files) or the size of the initialized data on disk (for image files).
48    /// For executable images, this must be a multiple of `file_alignment` from the optional header.
49    /// If this is less than `virtual_size`, the remainder of the section is zero-filled.
50    /// Because the `size_of_raw_data` field is rounded but the `virtual_size` field is not, it is possible for `size_of_raw_data` to be greater than `virtual_size` as well.
51    /// When a section contains only uninitialized data, this field should be zero.
52    pub size_of_raw_data: u32,
53    /// The file pointer to the first page of the section within the COFF file.
54    /// For executable images, this must be a multiple of `file_alignment` from the optional header.
55    /// For object files, the value should be aligned on a 4-byte boundary for best performance.
56    /// When a section contains only uninitialized data, this field should be zero.
57    pub pointer_to_raw_data: u32,
58    /// The file pointer to the beginning of relocation entries for the section.
59    /// This is set to zero for executable images or if there are no relocations.
60    pub pointer_to_relocations: u32,
61    /// The file pointer to the beginning of line-number entries for the section.
62    /// This is set to zero if there are no COFF line numbers.
63    /// This value should be zero for an image because COFF debugging information is deprecated.
64    pub pointer_to_line_numbers: u32,
65    /// The number of relocation entries for the section.
66    /// This is set to zero for executable images.
67    pub number_of_relocations: u16,
68    /// The number of line-number entries for the section.
69    /// This value should be zero for an image because COFF debugging information is deprecated.
70    pub number_of_line_numbers: u16,
71    /// The flags that describe the characteristics of the section.
72    pub characteristics: u32
73}
74
75impl fmt::Display for SectionHeader {
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77        let name = self.get_name()
78            .expect("Failed to get name");
79        let characteristics = self.get_characteristics()
80            .expect("Failed to get characteristics");
81
82        writeln!(f, "Section Header")?;
83        writeln!(f, "--------------")?;
84        writeln!(f, "Name:                    {:?}", name)?;
85        writeln!(f, "Virtual Size:            {}", self.virtual_size)?;
86        writeln!(f, "Virtual Address:         {:#010x}", self.virtual_address)?;
87        writeln!(f, "Size of Raw Data:        {}", self.size_of_raw_data)?;
88        writeln!(f, "Pointer to Raw Data:     {}", self.pointer_to_raw_data)?;
89        writeln!(f, "Pointer to Relocations:  {}", self.pointer_to_relocations)?;
90        writeln!(f, "Pointer to Line-numbers: {}", self.pointer_to_line_numbers)?;
91        writeln!(f, "Number of Relocations:   {}", self.number_of_relocations)?;
92        writeln!(f, "Number of Line-numbers:  {}", self.number_of_line_numbers)?;
93        writeln!(f, "Characteristics:         {}", characteristics)?;
94
95        Ok(())
96    }
97}
98
99bitflags! {
100    /// Bitflags that contain various information about
101    /// how a section should be loaded
102    pub struct SectionFlags: u32 {
103        /// Reserved for future use.
104        const IMAGE_SCN_RESERVED0 = 0x00000000;
105        /// Reserved for future use.
106        const IMAGE_SCN_RESERVED1 = 0x00000001;
107        /// Reserved for future use.
108        const IMAGE_SCN_RESERVED2 = 0x00000002;
109        /// Reserved for future use.
110        const IMAGE_SCN_RESERVED4 = 0x00000004;
111        /// The section should not be padded to the next boundary.
112        /// This flag is obsolete and is replaced by `align1Bytes`.
113        /// This is valid only for object files.
114        const IMAGE_SCN_TYPE_NO_PAD = 0x00000008;
115        /// Reserved for future use.
116        const IMAGE_SCN_RESERVED10 = 0x00000010;
117        /// The section contains executable code.
118        const IMAGE_SCN_CNT_CODE = 0x00000020;
119        /// The section contains initialized data.
120        const IMAGE_SCN_CNT_INITALIZED_DATA = 0x00000040;
121        /// The section contains uninitialized data.
122        const IMAGE_SCN_CNT_UNINITALIZED_DATA = 0x00000080;
123        /// Reserved for future use.
124        const IMAGE_SCN_LNK_OTHER = 0x00000100;
125        /// The section contains comments or other information.
126        /// The .drectve section has this type.
127        /// This is valid for object files only.
128        const IMAGE_SCN_LNK_INFO = 0x00000200;
129        /// Reserved for future use.
130        const IMAGE_SCN_RESERVED400 = 0x00000400;
131        /// The section will not become part of the image.
132        /// This is valid only for object files.
133        const IMAGE_SCN_LNK_REMOVE = 0x00000800;
134        /// The section contains COMDAT data. 
135        /// This is valid only for object files.
136        const IMAGE_SCN_LNK_COMDAT = 0x00001000;
137        /// The section contains data referenced through the global pointer (GP).
138        const IMAGE_SCN_GPREL = 0x00008000;
139        /// Reserved for future use.
140        const IMAGE_SCN_MEM_PURGABLE = 0x00020000;
141        /// Reserved for future use.
142        const IMAGE_SCN_MEM_16BIT = 0x00020000;
143        /// Reserved for future use.
144        const IMAGE_SCN_MEM_LOCKED = 0x00040000;
145        /// Reserved for future use.
146        const IMAGE_SCN_MEM_PRELOAD = 0x00080000;
147        /// Align data on a 1-byte boundary.
148        /// Valid only for object files.
149        const IMAGE_SCN_ALIGN_1BYTES = 0x00100000;
150        /// Align data on a 2-byte boundary.
151        /// Valid only for object files.
152        const IMAGE_SCN_ALIGN_2BYTES = 0x00200000;
153        /// Align data on a 4-byte boundary.
154        /// Valid only for object files.
155        const IMAGE_SCN_ALIGN_4BYTES = 0x00300000;
156        /// Align data on a 8-byte boundary.
157        /// Valid only for object files.
158        const IMAGE_SCN_ALIGN_8BYTES = 0x00400000;
159        /// Align data on a 16-byte boundary.
160        /// Valid only for object files.
161        const IMAGE_SCN_ALIGN_16BYTES = 0x00500000;
162        /// Align data on a 32-byte boundary.
163        /// Valid only for object files.
164        const IMAGE_SCN_ALIGN_32BYTES = 0x00600000;
165        /// Align data on a 64-byte boundary.
166        /// Valid only for object files.
167        const IMAGE_SCN_ALIGN_64BYTES = 0x00700000;
168        /// Align data on a 128-byte boundary.
169        /// Valid only for object files.
170        const IMAGE_SCN_ALIGN_128BYTES = 0x00800000;
171        /// Align data on a 256-byte boundary.
172        /// Valid only for object files.
173        const IMAGE_SCN_ALIGN_256BYTES = 0x00900000;
174        /// Align data on a 512-byte boundary.
175        /// Valid only for object files.
176        const IMAGE_SCN_ALIGN_512BYTES = 0x00A00000;
177        /// Align data on a 1024-byte boundary.
178        /// Valid only for object files.
179        const IMAGE_SCN_ALIGN_1024BYTES = 0x00B00000;
180        /// Align data on a 2048-byte boundary.
181        /// Valid only for object files.
182        const IMAGE_SCN_ALIGN_2048BYTES = 0x00C00000;
183        /// Align data on a 4096-byte boundary.
184        /// Valid only for object files.
185        const IMAGE_SCN_ALIGN_4096BYTES = 0x00D00000;
186        /// Align data on a 8192-byte boundary.
187        /// Valid only for object files.
188        const IMAGE_SCN_ALIGN_8192BYTES = 0x00E00000;
189        /// The section contains extended relocations.
190        /// `lnkNrelocOvfl` indicates that the count of relocations for the section exceeds the 16 bits that are reserved for it in the section header.
191        /// If the bit is set and the `number_of_relocations` field in the section header is 0xffff, the actual relocation count is stored in the 32-bit `virtual_address` field of the first relocation.
192        /// It is an error if `lnkNrelocOvfl` is set and there are fewer than 0xffff relocations in the section.
193        const IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000;
194        /// The section can be discarded as needed.
195        const IMAGE_SCN_MEM_DISCARDABLE = 0x02000000;
196        /// The section cannot be cached.
197        const IMAGE_SCN_MEM_NOT_CACHED = 0x04000000;
198        /// The section is not pageable.
199        const IMAGE_SCN_MEM_NOT_PAGED = 0x08000000;
200        /// The section can be shared in memory.
201        const IMAGE_SCN_MEM_SHARED = 0x10000000;
202        /// The section can be executed as code.
203        const IMAGE_SCN_MEM_EXECUTE = 0x20000000;
204        /// The section can be read.
205        const IMAGE_SCN_MEM_READ = 0x40000000;
206        /// The section can be written to.
207        const IMAGE_SCN_MEM_WRITE = 0x80000000;
208    }
209}
210
211// Allow SectionFlags flags to be easily printed
212impl fmt::Debug for SectionFlags {
213    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
214        fmt::Debug::fmt(&self.0, f)
215    }
216}
217
218impl fmt::Display for SectionFlags {
219    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
220        fmt::Display::fmt(&self.0, f)
221    }
222}
223
224impl str::FromStr for SectionFlags {
225    type Err = bitflags::parser::ParseError;
226
227    fn from_str(flags: &str) -> Result<Self, Self::Err> {
228        Ok(Self(flags.parse()?))
229    }
230}
231
232impl SectionHeader {
233    /// Get the name of a section as a string.
234    /// Note that this string may contain null characters.
235    pub fn get_name(&self) -> Option<String> {
236        String::from_utf8(self.name.to_vec()).ok()
237    }
238
239    /// Returns the Section Characteristics as bitflags
240    pub fn get_characteristics(&self) -> Option<SectionFlags> {
241        SectionFlags::from_bits(self.characteristics)
242    }
243}