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}