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
118
119
120
121
122
123
124
use anyhow::Result;
use bitflags::bitflags;
use thiserror::Error;
use crate::{
aspace::{AbsoluteAddressSpace, AddressSpace},
pagemap::PageMapError::NotMapped,
RVA, VA,
};
#[derive(Error, Debug)]
pub enum ModuleError {
#[error("invalid address: {0:#x}")]
InvalidAddress(u64),
}
#[derive(Copy, Clone, Debug)]
pub enum Arch {
X32,
X64,
}
impl Arch {
pub fn pointer_size(&self) -> usize {
match self {
Arch::X32 => 4,
Arch::X64 => 8,
}
}
}
bitflags! {
pub struct Permissions: u8 {
const R = 0b0000_0001;
const W = 0b0000_0010;
const X = 0b0000_0100;
const RW = Self::R.bits | Self::W.bits;
const RX = Self::R.bits | Self::X.bits;
const WX = Self::W.bits | Self::X.bits;
const RWX = Self::R.bits | Self::W.bits | Self::X.bits;
}
}
#[derive(Debug, Clone)]
pub struct Section {
pub physical_range: std::ops::Range<RVA>,
pub virtual_range: std::ops::Range<VA>,
pub permissions: Permissions,
pub name: String,
}
#[derive(Clone)]
pub struct Module {
pub arch: Arch,
pub sections: Vec<Section>,
pub address_space: AbsoluteAddressSpace,
}
impl Module {
pub fn read_va_at_rva(&self, offset: RVA) -> Result<VA> {
match self.arch {
Arch::X32 => Ok(self.address_space.relative.read_u32(offset)? as VA),
Arch::X64 => Ok(self.address_space.relative.read_u64(offset)? as VA),
}
}
pub fn read_rva_at_rva(&self, offset: RVA) -> Result<RVA> {
match self.arch {
Arch::X32 => Ok(self.address_space.relative.read_u32(offset)? as RVA),
Arch::X64 => Ok(self.address_space.relative.read_u64(offset)? as RVA),
}
}
pub fn read_va_at_va(&self, offset: VA) -> Result<VA> {
match self.arch {
Arch::X32 => Ok(self.address_space.read_u32(offset)? as VA),
Arch::X64 => Ok(self.address_space.read_u64(offset)? as VA),
}
}
pub fn read_rva_at_va(&self, offset: VA) -> Result<RVA> {
match self.arch {
Arch::X32 => Ok(self.address_space.read_u32(offset)? as RVA),
Arch::X64 => Ok(self.address_space.read_u64(offset)? as RVA),
}
}
pub fn probe_va(&self, offset: VA, perm: Permissions) -> bool {
self.sections
.iter()
.any(|section| section.virtual_range.contains(&offset) && section.permissions.intersects(perm))
}
pub fn probe_rva(&self, offset: RVA, perm: Permissions) -> bool {
let va = self.address_space.base_address + offset;
self.probe_va(va, perm)
}
pub fn file_offset(&self, va: VA) -> Result<usize> {
if let Some(sec) = self.sections.iter().find(|&sec| sec.virtual_range.contains(&va)) {
let offset = va - sec.virtual_range.start;
Ok((offset + sec.physical_range.start) as usize)
} else {
Err(NotMapped.into())
}
}
pub fn virtual_address(&self, file_offset: u64) -> Result<VA> {
self.sections
.iter()
.find(|&sec| sec.physical_range.contains(&(file_offset as u64)))
.map(|sec| {
let section_offset = file_offset as u64 - sec.physical_range.start;
sec.virtual_range.start + section_offset
})
.ok_or_else(|| NotMapped.into())
}
}