1#![allow(non_camel_case_types)]
2
3use std::{io::{Cursor, Read}, string::FromUtf8Error, fmt::Display};
4use bitflags::bitflags;
5use byteorder::{ReadBytesExt, LittleEndian};
6use serde::Serialize;
7
8use crate::{new_header_field, types::{Header, HeaderField}, utils::flags_to_str};
9
10use super::{optional::{DataDirectory, DirectoryType}, PeError};
11
12pub const HEADER_LENGTH: u64 = 40;
13
14bitflags! {
15 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy, Serialize)]
16 pub struct Flags: u32 {
17 const UNKNOWN = 0x00000000;
18 const NO_PAD = 0x00000008;
19 const CODE = 0x00000020;
20 const INITIALIZED_DATA= 0x00000040;
21 const UNINITIALIZED_DATA = 0x00000080;
22 const LNK_OTHER = 0x00000100;
23 const LNK_INFO = 0x00000200;
24 const LNK_REMOVE = 0x00000800;
25 const LNK_COMDAT = 0x00001000;
26 const NO_DEFER_SPEC_EXC = 0x00004000;
27 const GPREL = 0x00008000;
28 const MEM_PURGEABLE = 0x00020000;
29 const MEM_LOCKED = 0x00040000;
30 const MEM_PRELOAD = 0x00080000;
31 const LNK_NRELOC_OVFL = 0x01000000;
32 const MEM_DISCARDABLE = 0x02000000;
33 const MEM_NOT_CACHED = 0x04000000;
34 const MEM_NOT_PAGED = 0x08000000;
35 const MEM_SHARED = 0x10000000;
36 const MEM_EXECUTE = 0x20000000;
37 const MEM_READ = 0x40000000;
38 const MEM_WRITE = 0x80000000;
39 }
40}
41
42
43impl Display for Flags {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 write!(f, "{}", flags_to_str(self))
46 }
47}
48
49#[derive(Debug, Default)]
50pub struct SectionHeader {
51 pub name: HeaderField<[u8; 8]>,
52 pub virtual_size: HeaderField<u32>, pub virtual_address: HeaderField<u32>,
54 pub sizeof_raw_data: HeaderField<u32>,
55 pub raw_data_ptr: HeaderField<u32>,
56 pub relocs_ptr: HeaderField<u32>,
57 pub line_num_ptr: HeaderField<u32>,
58 pub relocs_count: HeaderField<u16>,
59 pub line_num_count: HeaderField<u16>,
60 pub charactristics: HeaderField<u32>,
61}
62
63impl SectionHeader {
64 pub fn flags(&self) -> Option<Flags> {
65 Flags::from_bits(self.charactristics.value)
66 }
67
68 pub fn contains_rva(&self, rva: u32) -> bool {
69 let end_va = self.virtual_address.value + self.virtual_size.value;
70 rva >= self.virtual_address.value && rva <= end_va
71 }
72
73 pub fn contains_va(&self, va: u64, base: u64) -> bool {
74 let rva = va - base;
75 self.contains_rva(rva as u32)
76 }
77
78 pub fn rva_to_offset(&self, rva: u32) -> Option<u32> {
79 if !self.contains_rva(rva) {
80 return None;
81 }
82
83 let offset = rva - self.virtual_address.value + self.raw_data_ptr.value;
84 Some(offset)
85 }
86
87 pub fn offset_to_rva(&self, offset: u32) -> Option<u32> {
88 if self.contains_offset(offset) {
89 let section_offset = offset - self.raw_data_ptr.value;
90 let rva = self.virtual_address.value + section_offset;
91 return Some(rva);
92 }
93 None
94 }
95
96 pub fn contains_offset(&self, offset: u32) -> bool {
97 if self.raw_data_ptr.value <= offset{
98 if self.raw_data_ptr.value + self.sizeof_raw_data.value > offset{
99 return true;
100 }
101 }
102 false
103 }
104
105 pub fn name_str(&self) -> std::result::Result<String, FromUtf8Error> {
106 let str = String::from_utf8(self.name.value.to_vec())?;
107 Ok(str.trim_matches(char::from(0)).to_string())
108 }
109
110 pub fn directories(&self, dirs: &Vec<HeaderField<DataDirectory>>) -> Vec<DirectoryType> {
111 let mut dtypes = Vec::<DirectoryType>::new();
112 for dir in dirs {
113 let rva = dir.value.rva.value;
114 if self.contains_rva(rva) {
115 dtypes.push(dir.value.member);
116 }
117 }
118 dtypes
119 }
120}
121
122impl Header for SectionHeader {
123 fn parse_bytes(bytes: Vec<u8>, pos: u64) -> crate::Result<Self> {
124 let bytes_len = bytes.len() as u64;
125
126 if bytes_len < HEADER_LENGTH {
127 return Err (
128 PeError::BufferTooSmall { target: "SectionHeader".into(), expected: HEADER_LENGTH, actual: bytes_len }
129 );
130 }
131
132 let mut hdr = Self { ..Default::default() };
133 let mut cursor = Cursor::new(bytes);
134 let mut offset = pos;
135
136 let mut name: [u8; 8] = [0; 8];
137 cursor.read(&mut name)?;
138 hdr.name = new_header_field!(name, offset);
139 hdr.virtual_size = new_header_field!(cursor.read_u32::<LittleEndian>()?, offset);
140 hdr.virtual_address = new_header_field!(cursor.read_u32::<LittleEndian>()?, offset);
141 hdr.sizeof_raw_data = new_header_field!(cursor.read_u32::<LittleEndian>()?, offset);
142 hdr.raw_data_ptr = new_header_field!(cursor.read_u32::<LittleEndian>()?, offset);
143 hdr.relocs_ptr = new_header_field!(cursor.read_u32::<LittleEndian>()?, offset);
144 hdr.line_num_ptr = new_header_field!(cursor.read_u32::<LittleEndian>()?, offset);
145 hdr.relocs_count = new_header_field!(cursor.read_u16::<LittleEndian>()?, offset);
146 hdr.line_num_count = new_header_field!(cursor.read_u16::<LittleEndian>()?, offset);
147 hdr.charactristics = new_header_field!(cursor.read_u32::<LittleEndian>()?, offset);
148
149 Ok(hdr)
150 }
151
152 fn is_valid(&self) -> bool {
153 self.line_num_count.value < 0xffff && self.relocs_count.value < 0xffff
154 }
155
156 fn length() -> usize {
157 HEADER_LENGTH as usize
158 }
159}
160
161impl Display for SectionHeader {
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 write!(f, "{{ {}, RVA: {:#08x}, Size: {:#08x}, RawAddr: {:#08x}, RawSize: {:#08x}, Flags: {} }}",
164 self.name_str().unwrap_or("Err".into()), self.virtual_address.value, self.virtual_size.value,
165 self.raw_data_ptr.value, self.sizeof_raw_data.value, self.flags().unwrap_or(Flags::UNKNOWN))
166 }
167}
168
169pub type SectionTable = Vec<HeaderField<SectionHeader>>;
170
171pub fn parse_sections(bytes: &[u8], count: u16, pos: u64) -> crate::Result<SectionTable> {
172 let mut sections = Vec::with_capacity(count as usize);
173 let bytes_len = bytes.len() as u64;
174 let expected = HEADER_LENGTH * count as u64;
175
176 if bytes_len < expected {
177 return Err (
178 PeError::BufferTooSmall { target: format!("{count} SectionHeaders"), expected, actual: bytes_len }
179 );
180 }
181
182 let mut offset = pos;
183 let mut slice_start = 0u64;
184 let mut slice_end = HEADER_LENGTH;
185
186 for _ in 0..count {
187 let buf = &bytes[slice_start as usize..slice_end as usize];
188 let section = SectionHeader::parse_bytes(buf.to_vec(), offset)?;
189 offset += HEADER_LENGTH;
190 slice_start = slice_end;
191 slice_end += HEADER_LENGTH;
192 sections.push(HeaderField { value: section, offset: slice_start, rva: slice_start});
193 }
194 Ok(sections)
195}
196
197pub fn rva_to_offset(sections: &SectionTable, rva: u32) -> Option<u32> {
198 for s in sections {
199 if let Some(offset) = s.value.rva_to_offset(rva) {
200 return Some(offset);
201 }
202 }
203 None
204}
205
206pub fn rva_to_section(sections: &SectionTable, rva: u32) -> Option<&SectionHeader> {
207 for s in sections {
208 if s.value.contains_rva(rva) {
209 return Some(&s.value);
210 }
211 }
212 None
213}
214
215pub fn offset_to_rva(sections: &SectionTable, offset: u32) -> Option<u32> {
216 for s in sections {
217 if let Some(rva) = s.value.offset_to_rva(offset) {
218 return Some(rva);
219 }
220 }
221 None
222}
223
224pub fn section_by_name(sections: &SectionTable, name: String) -> crate::Result<Option<&SectionHeader>> {
225 for section in sections.iter() {
226 if section.value.name_str()? == name {
227 return Ok(Some(§ion.value));
228 }
229 }
230 return Ok(None)
231}
232
233#[cfg(test)]
234mod tests {
235 use crate::{types::Header, pe::section::{rva_to_offset, offset_to_rva}};
236
237 use super::{parse_sections, section_by_name, Flags, SectionHeader, HEADER_LENGTH};
238
239 const RAW_BYTES: [u8; 240] = [
240 0x2E, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0xEB, 0xBB, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
241 0x00, 0xBC, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
242 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x60, 0x2E, 0x72, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00,
243 0x8E, 0x5F, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00,
244 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40,
245 0x2E, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x78, 0x13, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00,
246 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
247 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0xC0, 0x2E, 0x67, 0x66, 0x69, 0x64, 0x73, 0x00, 0x00,
248 0xDC, 0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00,
249 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40,
250 0x2E, 0x72, 0x73, 0x72, 0x63, 0x00, 0x00, 0x00, 0xE8, 0x64, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00,
251 0x00, 0x66, 0x00, 0x00, 0x00, 0x2A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
252 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x2E, 0x72, 0x65, 0x6C, 0x6F, 0x63, 0x00, 0x00,
253 0x98, 0x0F, 0x00, 0x00, 0x00, 0xD0, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00,
254 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x42
255 ];
256
257 #[test]
258 fn parse_one_section() {
259 let bytes = &RAW_BYTES[0..HEADER_LENGTH as usize];
260 let sh = SectionHeader::parse_bytes(bytes.to_vec(), 0x208).unwrap();
261 assert!(sh.is_valid());
262 assert_eq!(sh.name_str().unwrap(), String::from(".text"));
263 assert_eq!(sh.name.offset, 0x208);
264 assert_eq!(sh.virtual_size.value, 0xbbeb);
265 assert_eq!(sh.virtual_size.offset, 0x210);
266 assert_eq!(sh.virtual_address.value, 0x00001000);
267 assert_eq!(sh.virtual_address.offset, 0x214);
268 assert_eq!(sh.sizeof_raw_data.value, 0x0000bc00);
269 assert_eq!(sh.sizeof_raw_data.offset, 0x218);
270 assert_eq!(sh.raw_data_ptr.value, 0x00000400);
271 assert_eq!(sh.raw_data_ptr.offset, 0x21c);
272 assert_eq!(sh.relocs_ptr.value, 0);
273 assert_eq!(sh.relocs_ptr.offset, 0x220);
274 assert_eq!(sh.line_num_ptr.value, 0);
275 assert_eq!(sh.line_num_ptr.offset, 0x224);
276 assert_eq!(sh.relocs_count.value, 0);
277 assert_eq!(sh.relocs_count.offset, 0x228);
278 assert_eq!(sh.line_num_count.value, 0);
279 assert_eq!(sh.line_num_count.offset, 0x22a);
280 assert_eq!(sh.flags().unwrap(), Flags::CODE | Flags::MEM_EXECUTE | Flags::MEM_READ);
281 }
282
283 #[test]
284 fn parse_all_sections() {
285 let sections = parse_sections(&RAW_BYTES, 6, 0x208).unwrap();
286 assert_eq!(sections.len(), 6);
287 let names = [".text", ".rdata", ".data", ".gfids", ".rsrc", ".reloc"];
288 let sec_flags = [
289 Flags::CODE | Flags::MEM_READ | Flags::MEM_EXECUTE,
290 Flags::INITIALIZED_DATA | Flags::MEM_READ,
291 Flags::INITIALIZED_DATA | Flags::MEM_READ | Flags::MEM_WRITE,
292 Flags::INITIALIZED_DATA | Flags::MEM_READ,
293 Flags::INITIALIZED_DATA | Flags::MEM_READ,
294 Flags::INITIALIZED_DATA | Flags::MEM_READ | Flags::MEM_DISCARDABLE,
295 ];
296 for i in 0..6 {
297 let hf_section = §ions[i];
298 let sh = &hf_section.value;
299 assert!(sh.is_valid());
300 assert_eq!(sh.name_str().unwrap(), String::from(names[i]));
301 assert_eq!(sh.flags().unwrap(), sec_flags[i]);
302 }
303 }
304
305 #[test]
306 fn oep_in_text_section() {
307 let oep = 0x0000209B;
308 let sections = parse_sections(&RAW_BYTES, 6, 0x208).unwrap();
309 let txt_section = §ions[0].value;
310 assert_eq!(txt_section.name_str().unwrap(), String::from(".text"));
311 assert!(txt_section.contains_rva(oep));
312 }
313
314 #[test]
315 fn oep_to_offset() {
316 let offset: u32 = 0x0000149B;
317 let oep: u32 = 0x0000209B;
318 let sections = parse_sections(&RAW_BYTES, 6, 0x208).unwrap();
319 assert_eq!(rva_to_offset(§ions, oep).unwrap(), offset);
320 }
321
322 #[test]
323 fn oep_from_offset() {
324 let offset: u32 = 0x0000149B;
325 let oep: u32 = 0x0000209B;
326 let sections = parse_sections(&RAW_BYTES, 6, 0x208).unwrap();
327 assert_eq!(offset_to_rva(§ions, offset).unwrap(), oep);
328 }
329
330 #[test]
331 fn section_from_name() {
332 let sections = parse_sections(&RAW_BYTES, 6, 0x208).unwrap();
333
334 let sh = section_by_name(§ions, ".text".into()).unwrap().unwrap();
335
336 assert_eq!(sh.name_str().unwrap(), String::from(".text"));
337 assert_eq!(sh.name.offset, 0x208);
338 assert_eq!(sh.virtual_size.value, 0xbbeb);
339 assert_eq!(sh.virtual_size.offset, 0x210);
340 assert_eq!(sh.virtual_address.value, 0x00001000);
341 assert_eq!(sh.virtual_address.offset, 0x214);
342 assert_eq!(sh.sizeof_raw_data.value, 0x0000bc00);
343 assert_eq!(sh.sizeof_raw_data.offset, 0x218);
344 assert_eq!(sh.raw_data_ptr.value, 0x00000400);
345 assert_eq!(sh.raw_data_ptr.offset, 0x21c);
346 assert_eq!(sh.relocs_ptr.value, 0);
347 assert_eq!(sh.relocs_ptr.offset, 0x220);
348 assert_eq!(sh.line_num_ptr.value, 0);
349 assert_eq!(sh.line_num_ptr.offset, 0x224);
350 assert_eq!(sh.relocs_count.value, 0);
351 assert_eq!(sh.relocs_count.offset, 0x228);
352 assert_eq!(sh.line_num_count.value, 0);
353 assert_eq!(sh.line_num_count.offset, 0x22a);
354 assert_eq!(sh.flags().unwrap(), Flags::CODE | Flags::MEM_EXECUTE | Flags::MEM_READ);
355 }
356}