use std::cmp::{max, min};
pub(crate) trait Section {
fn virtual_address(&self) -> u32;
fn virtual_size(&self) -> u32;
fn raw_data_offset(&self) -> u32;
fn raw_data_size(&self) -> u32;
}
pub(crate) fn rva_to_offset(
rva: u32,
sections: &[impl Section],
file_alignment: u32,
section_alignment: u32,
) -> Option<u32> {
let lowest_section_rva =
sections.iter().map(|section| section.virtual_address()).min();
if matches!(lowest_section_rva, Some(x) if rva < x) {
return Some(rva);
}
let mut section_rva = 0;
let mut section_offset = 0;
let mut section_raw_size = 0;
for s in sections.iter() {
let size = max(s.virtual_size(), s.raw_data_size());
let start = s.virtual_address();
let end = start.saturating_add(size);
if section_rva <= s.virtual_address() && (start..end).contains(&rva) {
section_rva = s.virtual_address();
section_offset = s.raw_data_offset();
section_raw_size = s.raw_data_size();
let file_alignment = min(file_alignment, 0x200);
if let Some(rem) = section_offset.checked_rem(file_alignment) {
section_offset -= rem;
}
if section_alignment >= 0x1000 {
section_offset =
section_offset.saturating_sub(section_offset % 0x200);
}
}
}
if rva.saturating_sub(section_rva) >= section_raw_size {
return None;
}
let result = section_offset.saturating_add(rva - section_rva);
Some(result)
}
impl Section for crate::modules::protos::pe::Section {
fn virtual_address(&self) -> u32 {
self.virtual_address.unwrap()
}
fn virtual_size(&self) -> u32 {
self.virtual_size.unwrap()
}
fn raw_data_offset(&self) -> u32 {
self.raw_data_offset.unwrap()
}
fn raw_data_size(&self) -> u32 {
self.raw_data_size.unwrap()
}
}