1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use super::images::*;
use crate::error;
pub trait Pe {
fn image(&self) -> &[u8];
fn dos_header(&self) -> &IMAGE_DOS_HEADER {
unsafe { &*(self.image().as_ptr() as *const IMAGE_DOS_HEADER) }
}
fn nt_headers(&self) -> &IMAGE_NT_HEADERS {
unsafe {
&*(self
.image()
.as_ptr()
.offset(self.dos_header().e_lfanew as isize)
as *mut IMAGE_NT_HEADERS)
}
}
fn file_header(&self) -> &IMAGE_FILE_HEADER {
&self.nt_headers().FileHeader
}
fn opt_header(&self) -> &IMAGE_OPTIONAL_HEADER {
&self.nt_headers().OptionalHeader
}
fn section_headers(&self) -> &[IMAGE_SECTION_HEADER] {
unsafe {
let len = self.file_header().NumberOfSections as usize;
let data = (self.file_header() as *const _ as *const u8)
.offset(20)
.offset(self.file_header().SizeOfOptionalHeader as isize)
as *const IMAGE_SECTION_HEADER;
std::slice::from_raw_parts(data, len)
}
}
fn num_of_sections(&self) -> usize {
self.file_header().NumberOfSections as usize
}
fn rva_to_foa(&self, rva: Rva) -> error::Result<u32> {
if rva < self.opt_header().SizeOfHeaders {
return Ok(rva);
}
let sections = self.section_headers();
for sec in sections {
let sec: &IMAGE_SECTION_HEADER = sec;
let rva_end_bound = sec
.VirtualAddress
.wrapping_add(std::cmp::max(sec.SizeOfRawData, sec.VirtualSize));
if rva >= sec.VirtualAddress && rva < rva_end_bound {
if let None = sec.PointerToRawData.checked_add(sec.SizeOfRawData) {
return Err(error::Error::Overflow);
}
let sec_offset = rva - sec.VirtualAddress;
return if sec_offset < sec.SizeOfRawData {
Ok(sec_offset + sec.PointerToRawData)
} else if sec_offset < sec.VirtualSize {
Err(error::Error::ZeroFill)
} else {
Err(error::Error::Bounds)
};
}
}
Err(error::Error::Bounds)
}
fn foa_to_rva(&self, foa: u32) -> error::Result<Rva> {
if foa < self.opt_header().SizeOfHeaders {
return Ok(foa);
}
for sec in self.section_headers() {
let sec: &IMAGE_SECTION_HEADER = sec;
let foa_end_bound = sec.PointerToRawData.wrapping_add(sec.SizeOfRawData);
if foa >= sec.PointerToRawData && foa < foa_end_bound {
if let None = sec.VirtualAddress.checked_add(sec.VirtualSize) {
return Err(error::Error::Overflow);
}
let sec_offset = foa - sec.PointerToRawData;
return if sec_offset < sec.VirtualSize {
Ok(sec_offset + sec.VirtualAddress)
} else if sec_offset < sec.SizeOfRawData {
Err(error::Error::Unmapped)
} else {
Err(error::Error::Bounds)
};
}
}
Err(error::Error::Bounds)
}
}