2 use alloc::string::ToString;
6 use super::section_table;
8 use crate::pe::data_directories::DataDirectory;
13 pub fn is_in_range(rva: usize, r1: usize, r2: usize) -> bool {
17 // reference: Peter Ferrie. Reliable algorithm to extract overlay of a PE. https://bit.ly/2vBX2bR
19 fn aligned_pointer_to_raw_data(pointer_to_raw_data: usize) -> usize {
20 const PHYSICAL_ALIGN: usize = 0x1ff;
21 pointer_to_raw_data & !PHYSICAL_ALIGN
25 fn section_read_size(section: §ion_table::SectionTable, file_alignment: u32) -> usize {
26 fn round_size(size: usize) -> usize {
27 const PAGE_MASK: usize = 0xfff;
28 (size + PAGE_MASK) & !PAGE_MASK
31 // Paraphrased from https://reverseengineering.stackexchange.com/a/4326 (by Peter Ferrie).
33 // Handles the corner cases such as mis-aligned pointers (round down) and sizes (round up)
34 // Further rounding corner cases:
35 // - the physical pointer should be rounded down to a multiple of 512, regardless of the value in the header
36 // - the read size is rounded up by using a combination of the file alignment and 4kb
37 // - the virtual size is always rounded up to a multiple of 4kb, regardless of the value in the header.
39 // Reference C implementation:
41 // long pointerToRaw = section.get(POINTER_TO_RAW_DATA);
42 // long alignedpointerToRaw = pointerToRaw & ~0x1ff;
43 // long sizeOfRaw = section.get(SIZE_OF_RAW_DATA);
44 // long readsize = ((pointerToRaw + sizeOfRaw) + filealign - 1) & ~(filealign - 1)) - alignedpointerToRaw;
45 // readsize = min(readsize, (sizeOfRaw + 0xfff) & ~0xfff);
46 // long virtsize = section.get(VIRTUAL_SIZE);
50 // readsize = min(readsize, (virtsize + 0xfff) & ~0xfff);
53 let file_alignment = file_alignment as usize;
54 let size_of_raw_data = section.size_of_raw_data as usize;
55 let virtual_size = section.virtual_size as usize;
58 ((section.pointer_to_raw_data as usize + size_of_raw_data + file_alignment - 1)
59 & !(file_alignment - 1))
60 - aligned_pointer_to_raw_data(section.pointer_to_raw_data as usize);
61 cmp::min(read_size, round_size(size_of_raw_data))
64 if virtual_size == 0 {
67 cmp::min(read_size, round_size(virtual_size))
71 fn rva2offset(rva: usize, section: §ion_table::SectionTable) -> usize {
72 (rva - section.virtual_address as usize)
73 + aligned_pointer_to_raw_data(section.pointer_to_raw_data as usize)
76 fn is_in_section(rva: usize, section: §ion_table::SectionTable, file_alignment: u32) -> bool {
77 let section_rva = section.virtual_address as usize;
81 section_rva + section_read_size(section, file_alignment),
87 sections: &[section_table::SectionTable],
89 opts: &options::ParseOptions,
92 if file_alignment == 0 || file_alignment & (file_alignment - 1) != 0 {
95 for (i, section) in sections.iter().enumerate() {
97 "Checking {} for {:#x} ∈ {:#x}..{:#x}",
98 section.name().unwrap_or(""),
100 section.virtual_address,
101 section.virtual_address + section.virtual_size
103 if is_in_section(rva, §ion, file_alignment) {
104 let offset = rva2offset(rva, §ion);
106 "Found in section {}({}), remapped into offset {:#x}",
107 section.name().unwrap_or(""),
120 pub fn find_offset_or(
122 sections: &[section_table::SectionTable],
124 opts: &options::ParseOptions,
126 ) -> error::Result<usize> {
127 find_offset(rva, sections, file_alignment, opts)
128 .ok_or_else(|| error::Error::Malformed(msg.to_string()))
134 sections: &[section_table::SectionTable],
136 opts: &options::ParseOptions,
137 ) -> error::Result<&'a str> {
138 match find_offset(rva, sections, file_alignment, opts) {
139 Some(offset) => Ok(bytes.pread::<&str>(offset)?),
140 None => Err(error::Error::Malformed(format!(
141 "Cannot find name from rva {:#x} in sections: {:?}",
147 pub fn get_data<'a, T>(
149 sections: &[section_table::SectionTable],
150 directory: DataDirectory,
152 ) -> error::Result<T>
154 T: scroll::ctx::TryFromCtx<'a, scroll::Endian, Error = scroll::Error>,
161 &options::ParseOptions::default(),
165 pub fn get_data_with_opts<'a, T>(
167 sections: &[section_table::SectionTable],
168 directory: DataDirectory,
170 opts: &options::ParseOptions,
171 ) -> error::Result<T>
173 T: scroll::ctx::TryFromCtx<'a, scroll::Endian, Error = scroll::Error>,
175 let rva = directory.virtual_address as usize;
176 let offset = find_offset(rva, sections, file_alignment, opts)
177 .ok_or_else(|| error::Error::Malformed(directory.virtual_address.to_string()))?;
178 let result: T = bytes.pread_with(offset, scroll::LE)?;