1 use crate::error;
2 use alloc::string::ToString;
3 use scroll::Pread;
4
5 use super::options;
6 use super::section_table;
7
8 use crate::pe::data_directories::DataDirectory;
9 use core::cmp;
10
11 use log::debug;
12
is_in_range(rva: usize, r1: usize, r2: usize) -> bool13 pub fn is_in_range(rva: usize, r1: usize, r2: usize) -> bool {
14 r1 <= rva && rva < r2
15 }
16
17 // reference: Peter Ferrie. Reliable algorithm to extract overlay of a PE. https://bit.ly/2vBX2bR
18 #[inline]
aligned_pointer_to_raw_data(pointer_to_raw_data: usize) -> usize19 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
22 }
23
24 #[inline]
section_read_size(section: §ion_table::SectionTable, file_alignment: u32) -> usize25 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
29 }
30
31 let file_alignment = file_alignment as usize;
32 let size_of_raw_data = section.size_of_raw_data as usize;
33 let virtual_size = section.virtual_size as usize;
34 let read_size = {
35 let read_size = (section.pointer_to_raw_data as usize + size_of_raw_data + file_alignment
36 - 1)
37 & !(file_alignment - 1);
38 cmp::min(read_size, round_size(size_of_raw_data))
39 };
40
41 if virtual_size == 0 {
42 read_size
43 } else {
44 cmp::min(read_size, round_size(virtual_size))
45 }
46 }
47
rva2offset(rva: usize, section: §ion_table::SectionTable) -> usize48 fn rva2offset(rva: usize, section: §ion_table::SectionTable) -> usize {
49 (rva - section.virtual_address as usize)
50 + aligned_pointer_to_raw_data(section.pointer_to_raw_data as usize)
51 }
52
is_in_section(rva: usize, section: §ion_table::SectionTable, file_alignment: u32) -> bool53 fn is_in_section(rva: usize, section: §ion_table::SectionTable, file_alignment: u32) -> bool {
54 let section_rva = section.virtual_address as usize;
55 is_in_range(
56 rva,
57 section_rva,
58 section_rva + section_read_size(section, file_alignment),
59 )
60 }
61
find_offset( rva: usize, sections: &[section_table::SectionTable], file_alignment: u32, opts: &options::ParseOptions, ) -> Option<usize>62 pub fn find_offset(
63 rva: usize,
64 sections: &[section_table::SectionTable],
65 file_alignment: u32,
66 opts: &options::ParseOptions,
67 ) -> Option<usize> {
68 if opts.resolve_rva {
69 for (i, section) in sections.iter().enumerate() {
70 debug!(
71 "Checking {} for {:#x} ∈ {:#x}..{:#x}",
72 section.name().unwrap_or(""),
73 rva,
74 section.virtual_address,
75 section.virtual_address + section.virtual_size
76 );
77 if is_in_section(rva, §ion, file_alignment) {
78 let offset = rva2offset(rva, §ion);
79 debug!(
80 "Found in section {}({}), remapped into offset {:#x}",
81 section.name().unwrap_or(""),
82 i,
83 offset
84 );
85 return Some(offset);
86 }
87 }
88 None
89 } else {
90 Some(rva)
91 }
92 }
93
find_offset_or( rva: usize, sections: &[section_table::SectionTable], file_alignment: u32, opts: &options::ParseOptions, msg: &str, ) -> error::Result<usize>94 pub fn find_offset_or(
95 rva: usize,
96 sections: &[section_table::SectionTable],
97 file_alignment: u32,
98 opts: &options::ParseOptions,
99 msg: &str,
100 ) -> error::Result<usize> {
101 find_offset(rva, sections, file_alignment, opts)
102 .ok_or_else(|| error::Error::Malformed(msg.to_string()))
103 }
104
try_name<'a>( bytes: &'a [u8], rva: usize, sections: &[section_table::SectionTable], file_alignment: u32, opts: &options::ParseOptions, ) -> error::Result<&'a str>105 pub fn try_name<'a>(
106 bytes: &'a [u8],
107 rva: usize,
108 sections: &[section_table::SectionTable],
109 file_alignment: u32,
110 opts: &options::ParseOptions,
111 ) -> error::Result<&'a str> {
112 match find_offset(rva, sections, file_alignment, opts) {
113 Some(offset) => Ok(bytes.pread::<&str>(offset)?),
114 None => Err(error::Error::Malformed(format!(
115 "Cannot find name from rva {:#x} in sections: {:?}",
116 rva, sections
117 ))),
118 }
119 }
120
get_data<'a, T>( bytes: &'a [u8], sections: &[section_table::SectionTable], directory: DataDirectory, file_alignment: u32, ) -> error::Result<T> where T: scroll::ctx::TryFromCtx<'a, scroll::Endian, Error = scroll::Error>,121 pub fn get_data<'a, T>(
122 bytes: &'a [u8],
123 sections: &[section_table::SectionTable],
124 directory: DataDirectory,
125 file_alignment: u32,
126 ) -> error::Result<T>
127 where
128 T: scroll::ctx::TryFromCtx<'a, scroll::Endian, Error = scroll::Error>,
129 {
130 get_data_with_opts(
131 bytes,
132 sections,
133 directory,
134 file_alignment,
135 &options::ParseOptions::default(),
136 )
137 }
138
get_data_with_opts<'a, T>( bytes: &'a [u8], sections: &[section_table::SectionTable], directory: DataDirectory, file_alignment: u32, opts: &options::ParseOptions, ) -> error::Result<T> where T: scroll::ctx::TryFromCtx<'a, scroll::Endian, Error = scroll::Error>,139 pub fn get_data_with_opts<'a, T>(
140 bytes: &'a [u8],
141 sections: &[section_table::SectionTable],
142 directory: DataDirectory,
143 file_alignment: u32,
144 opts: &options::ParseOptions,
145 ) -> error::Result<T>
146 where
147 T: scroll::ctx::TryFromCtx<'a, scroll::Endian, Error = scroll::Error>,
148 {
149 let rva = directory.virtual_address as usize;
150 let offset = find_offset(rva, sections, file_alignment, opts)
151 .ok_or_else(|| error::Error::Malformed(directory.virtual_address.to_string()))?;
152 let result: T = bytes.pread_with(offset, scroll::LE)?;
153 Ok(result)
154 }
155