mirror of
https://codeberg.org/unspeaker/vestal.git
synced 2025-12-06 10:46:42 +01:00
drag in reloc.rs from lancelot by the ears
This commit is contained in:
parent
10eb388c18
commit
1be712eeab
2 changed files with 178 additions and 1 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
//mod execute;
|
//mod execute;
|
||||||
//mod inspect;
|
//mod inspect;
|
||||||
|
mod reloc;
|
||||||
mod memrun;
|
mod memrun;
|
||||||
//mod parse;
|
//mod parse;
|
||||||
mod vst;
|
mod vst;
|
||||||
|
|
@ -55,7 +56,9 @@ fn read_dll (context: &mut Context, name: &str, path: &PathBuf) -> Usually<()> {
|
||||||
//println!(" - {:8} + {:?} = {:?}", &export.rva, &export.offset, &export.name);
|
//println!(" - {:8} + {:?} = {:?}", &export.rva, &export.offset, &export.name);
|
||||||
}
|
}
|
||||||
for import in dll.pe()?.imports.iter() {
|
for import in dll.pe()?.imports.iter() {
|
||||||
imports.push(import.dll.to_lowercase());
|
let dll = import.dll.to_lowercase();
|
||||||
|
println!(" (-> {} {})", &dll, &import.name);
|
||||||
|
imports.push(dll);
|
||||||
}
|
}
|
||||||
context.insert(name.to_string(), dll);
|
context.insert(name.to_string(), dll);
|
||||||
for name in imports.iter() {
|
for name in imports.iter() {
|
||||||
|
|
|
||||||
174
crates/vestal/src/reloc.rs
Normal file
174
crates/vestal/src/reloc.rs
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
use crate::*;
|
||||||
|
/// From https://docs.rs/lancelot/latest/src/lancelot/loader/pe/reloc.rs.html#68-71
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum RelocType {
|
||||||
|
/// The base relocation is skipped. This type can be used to pad a block.
|
||||||
|
Abs = 0,
|
||||||
|
/// The base relocation adds the high 16 bits of the difference to the
|
||||||
|
/// 16-bit field at offset. The 16-bit field represents the high value of a
|
||||||
|
/// 32-bit word.
|
||||||
|
Hi = 1,
|
||||||
|
/// The base relocation adds the low 16 bits of the difference to the 16-bit
|
||||||
|
/// field at offset. The 16-bit field represents the low half of a 32-bit
|
||||||
|
/// word.
|
||||||
|
Lo = 2,
|
||||||
|
/// The base relocation applies all 32 bits of the difference to the 32-bit
|
||||||
|
/// field at offset.
|
||||||
|
HiLo = 3,
|
||||||
|
/// The base relocation adds the high 16 bits of the difference to the
|
||||||
|
/// 16-bit field at offset. The 16-bit field represents the high value of a
|
||||||
|
/// 32-bit word. The low 16 bits of the 32-bit value are stored in the
|
||||||
|
/// 16-bit word that follows this base relocation. This means that this base
|
||||||
|
/// relocation occupies two slots.
|
||||||
|
HiAdj = 4,
|
||||||
|
/// The base relocation applies the difference to the 64-bit field at
|
||||||
|
/// offset.
|
||||||
|
Dir64 = 10,
|
||||||
|
}
|
||||||
|
impl From<u16> for RelocType {
|
||||||
|
fn from(value: u16) -> Self {
|
||||||
|
match value {
|
||||||
|
0 => Self::Abs,
|
||||||
|
1 => Self::Hi,
|
||||||
|
2 => Self::Lo,
|
||||||
|
3 => Self::HiLo,
|
||||||
|
4 => Self::HiAdj,
|
||||||
|
10 => Self::Dir64,
|
||||||
|
_ => panic!("Invalid RelocType value: {}", value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub struct Relocation {
|
||||||
|
type_: RelocType,
|
||||||
|
address: VA,
|
||||||
|
}
|
||||||
|
pub struct RelocSectionData {
|
||||||
|
base_address: VA,
|
||||||
|
buf: Vec<u8>,
|
||||||
|
}
|
||||||
|
pub type VA = u64;
|
||||||
|
pub type RVA = u64;
|
||||||
|
impl RelocSectionData {
|
||||||
|
fn read_u16(&self, offset: usize) -> Usually<u16> {
|
||||||
|
if offset + 2 > self.buf.len() {
|
||||||
|
return Err("buffer too small".into())
|
||||||
|
}
|
||||||
|
Ok(u16::from_le_bytes([
|
||||||
|
self.buf[offset + 0],
|
||||||
|
self.buf[offset + 1],
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
fn read_u32(&self, offset: usize) -> Usually<u32> {
|
||||||
|
if offset + 4 > self.buf.len() {
|
||||||
|
return Err("buffer too small".into())
|
||||||
|
}
|
||||||
|
Ok(u32::from_le_bytes([
|
||||||
|
self.buf[offset + 0],
|
||||||
|
self.buf[offset + 1],
|
||||||
|
self.buf[offset + 2],
|
||||||
|
self.buf[offset + 3],
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
pub fn relocations(&self) -> Usually<Vec<Relocation>> {
|
||||||
|
let mut relocations = vec![];
|
||||||
|
let mut offset = 0x0;
|
||||||
|
while offset < self.buf.len() {
|
||||||
|
let rva = self.read_u32(offset)? as u64;
|
||||||
|
let size = self.read_u32(offset + 4)? as usize;
|
||||||
|
println!("(reloc-block rva={rva:x} size={size:x})");
|
||||||
|
const header_size: usize = 8;
|
||||||
|
const entry_size: usize = 2;
|
||||||
|
let entry_count = (size - header_size) / entry_size;
|
||||||
|
for entry_index in 0..entry_count {
|
||||||
|
let entry = self.read_u16(offset + header_size + (entry_index * entry_size))?;
|
||||||
|
let entry_type = RelocType::from(entry >> 12);
|
||||||
|
let entry_value = (entry & 0x0FFF) as u64;
|
||||||
|
let address = self.base_address + rva + entry_value;
|
||||||
|
println!("(reloc-entry addr={address:x} type={entry_type:?})");
|
||||||
|
relocations.push(Relocation {
|
||||||
|
type_: entry_type,
|
||||||
|
address,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
offset += size;
|
||||||
|
}
|
||||||
|
Ok(relocations)
|
||||||
|
}
|
||||||
|
pub fn from_pe(pe: &PE) -> Usually<Option<RelocSectionData>> {
|
||||||
|
let opt_header = match pe.header.optional_header {
|
||||||
|
None => return Ok(None),
|
||||||
|
Some(opt_header) => opt_header,
|
||||||
|
};
|
||||||
|
let reloc_table = match opt_header.data_directories.get_base_relocation_table() {
|
||||||
|
None => return Ok(None),
|
||||||
|
Some(reloc_table) => reloc_table,
|
||||||
|
};
|
||||||
|
println!(
|
||||||
|
"(reloc-table {:#x}-{:#x})",
|
||||||
|
pe.module.address_space.base_address + reloc_table.virtual_address as RVA,
|
||||||
|
pe.module.address_space.base_address + reloc_table.virtual_address as RVA + reloc_table.size as RVA
|
||||||
|
);
|
||||||
|
let buf = pe.module.address_space.read_bytes(
|
||||||
|
// goblin calls this a "virtual address", but its actually an RVA.
|
||||||
|
pe.module.address_space.base_address + reloc_table.virtual_address as RVA,
|
||||||
|
reloc_table.size as usize,
|
||||||
|
)?;
|
||||||
|
Ok(Some(RelocSectionData {
|
||||||
|
base_address: pe.module.address_space.base_address,
|
||||||
|
buf,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn apply_relocations(pe: &mut PE) -> Usually<()> {
|
||||||
|
let opt_header = match pe.optional_header {
|
||||||
|
None => return Ok(()),
|
||||||
|
Some(opt_header) => opt_header,
|
||||||
|
};
|
||||||
|
let wanted = opt_header.windows_fields.image_base;
|
||||||
|
let found = pe.module.address_space.base_address;
|
||||||
|
if wanted == found {
|
||||||
|
println!("# reloc: no relocations necessary");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let relocations = if let Ok(Some(reloc_data)) = RelocSectionData::from_pe(pe) {
|
||||||
|
reloc_data.relocations()?
|
||||||
|
} else {
|
||||||
|
println!("# reloc: no relocations found");
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
let delta = (found as i64) - (wanted as i64);
|
||||||
|
println!("# reloc: applying {} relocations", relocations.len());
|
||||||
|
for relocation in relocations.iter() {
|
||||||
|
match relocation.type_ {
|
||||||
|
// https://github.com/abhisek/Pe-Loader-Sample/blob/9aed4b3f6cd33ef75a0e01c21ea9f81608bf96cf/src/PeLdr.cpp#L44
|
||||||
|
RelocType::Abs => continue,
|
||||||
|
RelocType::Dir64 => {
|
||||||
|
println!("(reloc-dir64 {:x})", relocation.address);
|
||||||
|
let existing = pe.module.address_space.read_u64(relocation.address)?;
|
||||||
|
let updated = existing as i64 + delta;
|
||||||
|
pe.module.address_space.write_u64(relocation.address, updated as u64)?;
|
||||||
|
}
|
||||||
|
RelocType::HiLo => {
|
||||||
|
println!("(reloc-hi-lo)");
|
||||||
|
let existing = pe.module.address_space.read_u32(relocation.address)?;
|
||||||
|
let updated = existing + (delta & 0xFFFF_FFFF) as u32;
|
||||||
|
pe.module.address_space.write_u32(relocation.address, updated)?;
|
||||||
|
}
|
||||||
|
RelocType::Hi => {
|
||||||
|
println!("(reloc-hi)");
|
||||||
|
let existing = pe.module.address_space.read_u16(relocation.address)?;
|
||||||
|
let updated = existing + (((delta >> 16) & 0xFFFF) as u16);
|
||||||
|
pe.module.address_space.write_u16(relocation.address, updated)?;
|
||||||
|
}
|
||||||
|
RelocType::Lo => {
|
||||||
|
println!("(reloc-lo)");
|
||||||
|
let existing = pe.module.address_space.read_u16(relocation.address)?;
|
||||||
|
let updated = existing + ((delta & 0xFFFF) as u16);
|
||||||
|
pe.module.address_space.write_u16(relocation.address, updated)?;
|
||||||
|
}
|
||||||
|
_ => unimplemented!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue