mirror of
https://codeberg.org/unspeaker/vestal.git
synced 2025-12-06 15:06:42 +01:00
reduce number of modules
This commit is contained in:
parent
1be712eeab
commit
50e271e71b
9 changed files with 550 additions and 622 deletions
|
|
@ -5,10 +5,9 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
exe = "0.5.6"
|
||||
goblin = "0.9.2"
|
||||
clap = { version = "4.5.4", features = [ "cargo" ] }
|
||||
#lancelot = "0.8.6
|
||||
|
||||
syscalls = "0.6.18"
|
||||
elf = "0.7.4"
|
||||
goblin = "0.9.3"
|
||||
clap = { version = "4.5.4", features = [ "cargo" ] }
|
||||
lancelot = "0.9.7"
|
||||
syscalls = "0.6.18"
|
||||
#falcon = "0.5.5"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,57 @@
|
|||
use crate::*;
|
||||
use exe::pe::{VecPE, PtrPE};
|
||||
#[derive(Default)]
|
||||
pub struct PEContext {
|
||||
dlls: HashMap<String, Dll>,
|
||||
}
|
||||
impl PEContext {
|
||||
pub fn load (&mut self, name: &str, path: &PathBuf) -> Usually<()> {
|
||||
let name = name.to_lowercase();
|
||||
if self.dlls.contains_key(&name) {
|
||||
return Ok(())
|
||||
}
|
||||
println!("\n(:= \"{}\" {:?})", name, path);
|
||||
let dll = Dll::new(name.as_str(), path)?;
|
||||
println!("(:= \"{}\" {:p}+{})", name, &dll.pe.buf, dll.pe.buf.len());
|
||||
let mut imports = vec![];
|
||||
for export in dll.goblin()?.imports.iter() {
|
||||
//println!(" - {:8} + {:?} = {:?}", &export.rva, &export.offset, &export.name);
|
||||
}
|
||||
for import in dll.goblin()?.imports.iter() {
|
||||
let dll = import.dll.to_lowercase();
|
||||
println!(" (-> {} {})", &dll, &import.name);
|
||||
imports.push(dll);
|
||||
}
|
||||
self.dlls.insert(name.to_string(), dll);
|
||||
for name in imports.iter() {
|
||||
let path = format!("/home/user/Lab/Cosmo/wineprefix/drive_c/windows/system32/{}", name);
|
||||
self.load(name, &PathBuf::from(path))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
struct Dll {
|
||||
name: String,
|
||||
path: PathBuf,
|
||||
bang: Vec<u8>,
|
||||
pe: PE,
|
||||
}
|
||||
impl Dll {
|
||||
fn new (name: &str, path: &PathBuf) -> Usually<Self> {
|
||||
let (bang, data) = slice_shebang(read(path)?.as_slice());
|
||||
let mut pe = PE::from_bytes(data.as_slice())?;
|
||||
apply_relocations(&mut pe)?;
|
||||
Ok(Self {
|
||||
bang,
|
||||
name: name.to_string(),
|
||||
path: path.into(),
|
||||
pe,
|
||||
})
|
||||
}
|
||||
fn goblin (&self) -> Usually<goblin::pe::PE> {
|
||||
Ok(goblin::pe::PE::parse(self.pe.buf.as_slice())?)
|
||||
}
|
||||
}
|
||||
use std::ffi::c_void;
|
||||
//typedef VstIntPtr (VSTCALLBACK *audioMasterCallback) (AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt);
|
||||
#[repr(C)] pub struct AEffect {
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
use crate::*;
|
||||
use elf::file::Elf64_Ehdr;
|
||||
use std::fmt::{Debug, Display};
|
||||
use syscalls::{Sysno, Errno, syscall};
|
||||
|
||||
|
|
@ -55,3 +57,35 @@ fn run (fd: usize) {
|
|||
Ok(_) => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn make_elf () -> Vec<u8> {
|
||||
let mut buffer = vec![0;1024*1024*1024];
|
||||
// https://wiki.osdev.org/ELF#ELF_Header
|
||||
buffer[0x00..0x40].copy_from_slice(any_as_u8_slice(&Elf64_Ehdr {
|
||||
e_ehsize: 0x40, // elf header size,
|
||||
e_ident: [ // identification data
|
||||
0x7f, b'E', b'L', b'F', // magic bytes
|
||||
0x02, // 64-bit, 0x01 is 32-bit
|
||||
0x01, // little-endian
|
||||
0x01, // ELF header version
|
||||
0x00, // SysV ABI
|
||||
0x00, 0x00, 0x00, 0x00, // unused
|
||||
0x00, 0x00, 0x00, 0x00, // unused
|
||||
],
|
||||
e_version: 0x01, // ELF version
|
||||
e_type: 0x02, // executable
|
||||
e_machine: 0x3e, // x86_64, 0x03 = x86
|
||||
e_flags: 0x00, // TODO machine flags,
|
||||
e_entry: 0x00, // TODO entry point (from wrapper?)
|
||||
|
||||
e_phnum: 0x00, // TODO program headers
|
||||
e_phentsize: 0x00, // TODO why is there phent in my elf?
|
||||
e_phoff: 0x00, // TODO program header table offset
|
||||
|
||||
e_shnum: 0x00, // TODO section headers
|
||||
e_shentsize: 0x00, // TODO section header entry size
|
||||
e_shoff: 0x00, // TODO section header table offset
|
||||
e_shstrndx: 0x00, // TODO section header table index something something
|
||||
}));
|
||||
buffer
|
||||
}
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
use crate::*;
|
||||
use syscalls::{Sysno, syscall};
|
||||
use elf::file::Elf64_Ehdr;
|
||||
use std::ffi::CString;
|
||||
use std::str::FromStr;
|
||||
static NAME: &'static [u8] = &[b'\0'];
|
||||
impl Vestal {
|
||||
pub fn execute_path (&self, path: impl AsRef<Path>) -> Usually<()> {
|
||||
self.inspect_path(path)?;
|
||||
//let mut not_found = vec![];
|
||||
//for (dll, imports) in deps.iter() {
|
||||
//if let Some(dll) = find_dll(dll)? {
|
||||
//Self::from_data_dll(dll, |dll_buffer, dll_pe, dll_imports, dll_deps|{
|
||||
//Ok(())
|
||||
//});
|
||||
//for import in imports.iter() {
|
||||
//println!(" {:8} + {:8} {:32}", import.rva, import.offset, import.name);
|
||||
//}
|
||||
//} else {
|
||||
//println!("- {dll} NOT FOUND");
|
||||
//not_found.push(dll);
|
||||
//}
|
||||
//}
|
||||
// TODO: call(main, AEffect::host_callback)
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn find_dll (dll: &str) -> Usually<Option<Vec<u8>>> {
|
||||
let dll = dll.to_lowercase();
|
||||
let path = format!("/home/user/Lab/Cosmo/wineprefix/drive_c/windows/system32/{}", dll);
|
||||
let buffer = std::fs::read::<String>(path.clone())?;
|
||||
println!(" Found: {path} {}b", buffer.len());
|
||||
Ok(Some(buffer))
|
||||
}
|
||||
|
||||
fn make_elf () -> Vec<u8> {
|
||||
let mut buffer = vec![0;1024*1024*1024];
|
||||
// https://wiki.osdev.org/ELF#ELF_Header
|
||||
buffer[0x00..0x40].copy_from_slice(any_as_u8_slice(&Elf64_Ehdr {
|
||||
e_ehsize: 0x40, // elf header size,
|
||||
e_ident: [ // identification data
|
||||
0x7f, b'E', b'L', b'F', // magic bytes
|
||||
0x02, // 64-bit, 0x01 is 32-bit
|
||||
0x01, // little-endian
|
||||
0x01, // ELF header version
|
||||
0x00, // SysV ABI
|
||||
0x00, 0x00, 0x00, 0x00, // unused
|
||||
0x00, 0x00, 0x00, 0x00, // unused
|
||||
],
|
||||
e_version: 0x01, // ELF version
|
||||
e_type: 0x02, // executable
|
||||
e_machine: 0x3e, // x86_64, 0x03 = x86
|
||||
e_flags: 0x00, // TODO machine flags,
|
||||
e_entry: 0x00, // TODO entry point (from wrapper?)
|
||||
|
||||
e_phnum: 0x00, // TODO program headers
|
||||
e_phentsize: 0x00, // TODO why is there phent in my elf?
|
||||
e_phoff: 0x00, // TODO program header table offset
|
||||
|
||||
e_shnum: 0x00, // TODO section headers
|
||||
e_shentsize: 0x00, // TODO section header entry size
|
||||
e_shoff: 0x00, // TODO section header table offset
|
||||
e_shstrndx: 0x00, // TODO section header table index something something
|
||||
}));
|
||||
buffer
|
||||
}
|
||||
/// From https://stackoverflow.com/a/42186553
|
||||
fn any_as_u8_slice<T: Sized>(p: &T) -> &[u8] {
|
||||
unsafe {
|
||||
::core::slice::from_raw_parts(
|
||||
(p as *const T) as *const u8,
|
||||
::core::mem::size_of::<T>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
use crate::*;
|
||||
|
||||
impl Vestal {
|
||||
pub fn inspect_path (&self, path: impl AsRef<Path>) -> Usually<crate::parse::Dll> {
|
||||
let pe = crate::parse::Dll::from_path(path)?;
|
||||
let pe = pe.with_entrypoint("VSTPluginMain")?;
|
||||
let main = pe.entrypoint.as_ref().unwrap();
|
||||
println!("VSTPluginMain: {:?} + {:?}", &main.rva, &main.offset);
|
||||
let deps = &pe.imports;
|
||||
// TODO: load Wine libs
|
||||
println!("Imports: {:#?}", deps.len());
|
||||
Ok((pe, buf))
|
||||
//Self::from_path(&path, |buffer, pe, main, deps|{
|
||||
|
||||
//if let Some(main) = main {
|
||||
//println!("VSTPluginMain: {:?} + {:?}", &main.rva, &main.offset);
|
||||
//} else {
|
||||
//panic!("VSTPluginMain not found. This is not a valid VST plugin.");
|
||||
//}
|
||||
//println!("Imports: {:#?}", &pe.imports.len());
|
||||
//println!("Dependencies: {:#?}", &deps.len());
|
||||
//for (dll, imports) in deps.iter() {
|
||||
//println!("- {dll}");
|
||||
//for import in imports.iter() {
|
||||
//println!(" {:8} + {:8} {:32}", import.rva, import.offset, import.name);
|
||||
//}
|
||||
//}
|
||||
//Ok(())
|
||||
//})
|
||||
//let image = VecPE::from_disk_file(path)?;
|
||||
//let import_directory = ImportDirectory::parse(&image)?;
|
||||
//for descriptor in import_directory.descriptors {
|
||||
//let name = descriptor.get_name(&image)?.as_str()?;
|
||||
//println!("\n{name}:");
|
||||
//for import in descriptor.get_imports(&image).unwrap() {
|
||||
//match import {
|
||||
//ImportData::Ordinal(x) => println!("{name} #{x}"),
|
||||
//ImportData::ImportByName(s) => println!("{name} {s}")
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +1,14 @@
|
|||
//mod execute;
|
||||
//mod inspect;
|
||||
mod reloc;
|
||||
mod memrun;
|
||||
//mod parse;
|
||||
mod vst;
|
||||
#![feature(slice_split_once)]
|
||||
mod dll;
|
||||
mod exec;
|
||||
pub(crate) use std::error::Error;
|
||||
pub(crate) use std::path::{Path, PathBuf};
|
||||
pub(crate) use std::collections::HashMap;
|
||||
pub(crate) use std::fs::{read, canonicalize};
|
||||
pub(crate) use goblin::{error, Object, pe::{PE, import::Import, export::Export}};
|
||||
pub(crate) use lancelot::loader::pe::{PE, reloc::apply_relocations};
|
||||
pub(crate) use goblin::{error, Object, pe::{import::Import, export::Export}};
|
||||
use clap::{arg, command, value_parser, ArgAction, Command};
|
||||
|
||||
type Usually<T> = Result<T, Box<dyn std::error::Error>>;
|
||||
|
||||
type Sources = HashMap<String, Vec<u8>>;
|
||||
type Context = HashMap<String, Dll>;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Dll {
|
||||
name: String,
|
||||
path: PathBuf,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
impl Dll {
|
||||
fn pe (&self) -> Usually<PE> {
|
||||
read_pe(slice_shebang(&self.data))
|
||||
}
|
||||
}
|
||||
|
||||
fn main () -> Usually<()> {
|
||||
let matches = command!()
|
||||
.arg(arg!([path] "Path to VST DLL").value_parser(value_parser!(PathBuf)))
|
||||
|
|
@ -35,141 +16,32 @@ fn main () -> Usually<()> {
|
|||
//.arg(arg!(-s --stub <VALUE> "Provide stub import").required(false))
|
||||
.get_matches();
|
||||
if let Some(path) = matches.get_one::<PathBuf>("path") {
|
||||
let mut context: Context = HashMap::new();
|
||||
read_dll(&mut context, "vestal", &canonicalize(&path)?)?;
|
||||
let mut context = crate::dll::PEContext::default();
|
||||
context.load("main", &canonicalize(&path)?)?;
|
||||
Ok(())
|
||||
} else {
|
||||
panic!("Pass a path to a VST DLL.")
|
||||
}
|
||||
}
|
||||
|
||||
fn read_dll (context: &mut Context, name: &str, path: &PathBuf) -> Usually<()> {
|
||||
let name = canonical_name(&name);
|
||||
if context.contains_key(&name) {
|
||||
return Ok(())
|
||||
/// From https://stackoverflow.com/a/42186553
|
||||
pub fn any_as_u8_slice<T: Sized>(p: &T) -> &[u8] {
|
||||
unsafe {
|
||||
::core::slice::from_raw_parts(
|
||||
(p as *const T) as *const u8,
|
||||
::core::mem::size_of::<T>(),
|
||||
)
|
||||
}
|
||||
println!("\n(:= \"{}\" {:?})", name, path);
|
||||
let dll = Dll { name: name.to_string(), data: read(path)?, path: path.into(), };
|
||||
println!("(:= \"{}\" {:p}+{})", name, &dll.data, dll.data.len());
|
||||
let mut imports = vec![];
|
||||
for export in dll.pe()?.exports.iter() {
|
||||
//println!(" - {:8} + {:?} = {:?}", &export.rva, &export.offset, &export.name);
|
||||
}
|
||||
for import in dll.pe()?.imports.iter() {
|
||||
let dll = import.dll.to_lowercase();
|
||||
println!(" (-> {} {})", &dll, &import.name);
|
||||
imports.push(dll);
|
||||
}
|
||||
context.insert(name.to_string(), dll);
|
||||
for name in imports.iter() {
|
||||
let path = format!("/home/user/Lab/Cosmo/wineprefix/drive_c/windows/system32/{}", name);
|
||||
read_dll(context, name, &PathBuf::from(path))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn canonical_name (path: impl AsRef<Path>) -> String {
|
||||
path.as_ref().to_path_buf().into_os_string().into_string()
|
||||
.expect("failed to convert path")
|
||||
.to_lowercase()
|
||||
}
|
||||
|
||||
fn slice_shebang (buffer: &[u8]) -> &[u8] {
|
||||
let mut index = 2;
|
||||
let mut slice = false;
|
||||
/// You can manually patch DLLs by prepending
|
||||
/// a `#!/usr/bin/env vestal` line to them.
|
||||
pub fn slice_shebang (buffer: &[u8]) -> (Vec<u8>, Vec<u8>) {
|
||||
if buffer.get(0) == Some(&b'#') && buffer.get(1) == Some(&b'!') {
|
||||
while let Some(c) = buffer.get(index) {
|
||||
if *c == 0x0a {
|
||||
slice = true;
|
||||
break
|
||||
}
|
||||
index += 1;
|
||||
if let Some((bang, data)) = buffer.split_once(|x|*x==0x0a) {
|
||||
(bang.to_vec(), data.to_vec())
|
||||
} else {
|
||||
(buffer.to_vec(), vec![])
|
||||
}
|
||||
}
|
||||
if slice {
|
||||
println!("Slice: {index}");
|
||||
&buffer[index+1..]
|
||||
} else {
|
||||
buffer
|
||||
(vec![], buffer.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
fn read_pe (buffer: &[u8]) -> Usually<PE> {
|
||||
if let Object::PE(pe) = Object::parse(buffer)? {
|
||||
Ok(pe)
|
||||
} else {
|
||||
panic!("not a PE")
|
||||
}
|
||||
}
|
||||
|
||||
fn find_main <'a> (pe: &'a PE<'a>) -> &'a Export<'a> {
|
||||
for export in pe.exports.iter() {
|
||||
if let Some("VSTPluginMain") = export.name {
|
||||
println!("VSTPluginMain found: {:?} + {:?}", export.rva, export.offset);
|
||||
return export
|
||||
}
|
||||
}
|
||||
panic!("no VSTPluginMain")
|
||||
}
|
||||
|
||||
fn resolve_imports (
|
||||
sources: &mut Sources,
|
||||
context: &mut Context,
|
||||
) -> Usually<usize> {
|
||||
let mut updated: Context = Default::default();
|
||||
for (name, dll) in context.iter() {
|
||||
//if let Some(dll) = dll {
|
||||
//let imports = &dll.pe.imports;
|
||||
//for import in dll.pe.imports.iter() {
|
||||
//let dep = import.dll.to_lowercase();
|
||||
//if context.get(&dep).is_none() {
|
||||
//updated.insert(dep, None);
|
||||
//}
|
||||
//}
|
||||
//} else {
|
||||
//let path = format!("/home/user/Lab/Cosmo/wineprefix/drive_c/windows/system32/{}", name);
|
||||
//let data = read(&path)?;
|
||||
//updated.insert(name.clone(), Some(Dll {
|
||||
//name: name.clone(),
|
||||
//path: path.into(),
|
||||
//data: data.clone(),
|
||||
//pe: read_pe(data.as_slice())?
|
||||
//}));
|
||||
//}
|
||||
}
|
||||
let count = updated.len();
|
||||
for (name, library) in updated.into_iter() {
|
||||
context.insert(name, library);
|
||||
}
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
fn find_dll (dll: &str) -> Option<String> {
|
||||
Some(format!("/home/user/Lab/Cosmo/wineprefix/drive_c/windows/system32/{}", dll))
|
||||
}
|
||||
|
||||
//#[derive(Debug, Parser)]
|
||||
//#[command(version, about, long_about = None)]
|
||||
//pub struct Vestal {
|
||||
///// Inspect a DLL
|
||||
//Inspect { path: String },
|
||||
///// Load a VST DLL into memory
|
||||
//Execute { path: String },
|
||||
///// Load a VST DLL from hashbang
|
||||
//Loader { path: String }
|
||||
//}
|
||||
|
||||
//pub enum Arch {
|
||||
//ThirtyTwo,
|
||||
//SixtyFour,
|
||||
//}
|
||||
|
||||
//impl Vestal {
|
||||
//pub fn run (&self) -> Usually<()> {
|
||||
//match self {
|
||||
//Self::Inspect { path } => { self.inspect_path(path.as_str())?; Ok(()) },
|
||||
//Self::Execute { path } => self.execute_path(path.as_str()),
|
||||
//Self::Loader { path } => self.execute_path(path.as_str()),
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -1,160 +0,0 @@
|
|||
use crate::*;
|
||||
|
||||
pub struct Dll<'a> {
|
||||
pub buffer: Vec<u8>,
|
||||
pub pe: PE<'a>,
|
||||
pub entrypoint: Option<&'a Export<'a>>,
|
||||
pub exports: Vec<&'a Export<'a>>,
|
||||
pub imports: HashMap<String, Vec<&'a Import<'a>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DllError {
|
||||
NotPE,
|
||||
NoEntry(String)
|
||||
}
|
||||
|
||||
impl<'a> Dll<'a> {
|
||||
pub fn from_path (path: impl AsRef<Path>) -> Usually<Self> {
|
||||
Self::from_buffer(std::fs::read(path.as_ref())?)
|
||||
}
|
||||
pub fn from_buffer (buffer: Vec<u8>) -> Usually<Self> {
|
||||
if let Object::PE(pe) = Object::parse(buffer.as_slice())? {
|
||||
let mut imports: HashMap<_, _> = Default::default();
|
||||
for import in pe.imports.iter() {
|
||||
let dll = import.dll.clone();
|
||||
if !imports.contains_key(dll) {
|
||||
imports.insert(dll.to_string(), vec![]);
|
||||
}
|
||||
imports.get_mut(dll).unwrap().push(import);
|
||||
}
|
||||
let mut exports: Vec<_> = Default::default();
|
||||
for export in pe.exports.iter() {
|
||||
exports.push(export)
|
||||
}
|
||||
Ok(Self { buffer, pe, imports, exports, entrypoint: None })
|
||||
} else {
|
||||
Err("not a pe".into())
|
||||
}
|
||||
}
|
||||
pub fn with_entrypoint (self, name: &str) -> Usually<Self> {
|
||||
for export in self.exports.iter() {
|
||||
if let Some(name) = export.name {
|
||||
self.entrypoint = Some(export);
|
||||
return Ok(self)
|
||||
}
|
||||
}
|
||||
return Err(format!("no entrypoint \"{name}\"").into())
|
||||
}
|
||||
}
|
||||
|
||||
fn slice_shebang (buffer: Vec<u8>) -> Vec<u8> {
|
||||
let mut index = 2;
|
||||
let mut slice = false;
|
||||
if buffer.get(0) == Some(&b'#') && buffer.get(1) == Some(&b'!') {
|
||||
while let Some(c) = buffer.get(index) {
|
||||
if *c == 0x0a {
|
||||
slice = true;
|
||||
break
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
println!("Slice: {slice} {index}");
|
||||
if slice { buffer[index+1..].to_vec() } else { buffer }
|
||||
}
|
||||
|
||||
//impl Vestal {
|
||||
|
||||
//pub fn from_path (
|
||||
//path: &impl AsRef<Path>,
|
||||
//cb: impl Fn(&[u8], &PE, Option<&Export>, HashMap<String, Vec<&Import>>)->Usually<()>
|
||||
//) -> Usually<()> {
|
||||
//println!("Path: {}", path.as_ref().display());
|
||||
//let buffer = std::fs::read(path.as_ref())?;
|
||||
//Self::from_data(buffer.as_slice(), cb)
|
||||
//}
|
||||
|
||||
//pub fn from_data_dll (
|
||||
//mut buffer: &[u8],
|
||||
//callback: impl Fn(&[u8], &PE, Option<&Export>, HashMap<String, Vec<&Import>>)->Usually<()>
|
||||
//) -> Usually<()> {
|
||||
//println!("PE: {}b", buffer.len());
|
||||
//let mut index = 2;
|
||||
//let mut slice = false;
|
||||
//if buffer.get(0) == Some(&b'#') && buffer.get(1) == Some(&b'!') {
|
||||
//while let Some(c) = buffer.get(index) {
|
||||
//if *c == 0x0a {
|
||||
//slice = true;
|
||||
//break
|
||||
//}
|
||||
//index += 1;
|
||||
//}
|
||||
//}
|
||||
//println!("Slice: {slice} {index}");
|
||||
//let buffer = if slice { &buffer[index+1..] } else { buffer };
|
||||
//if let Object::PE(ref pe) = Object::parse(buffer)? {
|
||||
//let mut main = None;
|
||||
//let mut imports: HashMap<_, _> = Default::default();
|
||||
//for import in pe.imports.iter() {
|
||||
//let dll = import.dll.clone();
|
||||
//if !imports.contains_key(dll) {
|
||||
//imports.insert(dll.to_string(), vec![]);
|
||||
//}
|
||||
//imports.get_mut(dll).unwrap().push(import);
|
||||
//}
|
||||
//for export in pe.exports.iter() {
|
||||
//if let Some("VSTPluginMain") = export.name {
|
||||
//main = Some(export);
|
||||
//break
|
||||
//}
|
||||
//}
|
||||
//callback(&buffer, pe, main, imports);
|
||||
//Ok(())
|
||||
//} else {
|
||||
//Err("not a PE".into())
|
||||
//}
|
||||
//}
|
||||
|
||||
//pub fn from_data (
|
||||
//mut buffer: &[u8],
|
||||
//callback: impl Fn(&[u8], &PE, Option<&Export>, HashMap<String, Vec<&Import>>)->Usually<()>
|
||||
//) -> Usually<()> {
|
||||
//println!("PE: {}b", buffer.len());
|
||||
//let mut index = 2;
|
||||
//let mut slice = false;
|
||||
//if buffer.get(0) == Some(&b'#') && buffer.get(1) == Some(&b'!') {
|
||||
//while let Some(c) = buffer.get(index) {
|
||||
//if *c == 0x0a {
|
||||
//slice = true;
|
||||
//break
|
||||
//}
|
||||
//index += 1;
|
||||
//}
|
||||
//}
|
||||
//println!("Slice: {slice} {index}");
|
||||
//let buffer = if slice { &buffer[index+1..] } else { buffer };
|
||||
//if let Object::PE(ref pe) = Object::parse(buffer)? {
|
||||
//let mut main = None;
|
||||
//let mut imports: HashMap<_, _> = Default::default();
|
||||
//for import in pe.imports.iter() {
|
||||
//let dll = import.dll.clone();
|
||||
//if !imports.contains_key(dll) {
|
||||
//imports.insert(dll.to_string(), vec![]);
|
||||
//}
|
||||
//imports.get_mut(dll).unwrap().push(import);
|
||||
//}
|
||||
//for export in pe.exports.iter() {
|
||||
//if let Some("VSTPluginMain") = export.name {
|
||||
//main = Some(export);
|
||||
//break
|
||||
//}
|
||||
//}
|
||||
//callback(&buffer, pe, main, imports);
|
||||
//Ok(())
|
||||
//} else {
|
||||
//Err("not a PE".into())
|
||||
//}
|
||||
//}
|
||||
|
||||
//}
|
||||
|
|
@ -1,174 +0,0 @@
|
|||
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