rustbin/pe/
section.rs

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>, //Not using Misc.PhysicalAddress
53    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(&section.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 = &sections[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 = &sections[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(&sections, 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(&sections, 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(&sections, ".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}