functionalize

This commit is contained in:
🪞👃🪞 2025-02-19 19:04:16 +02:00
parent b6451308e0
commit 10eb388c18
7 changed files with 445 additions and 534 deletions

View file

@ -6,8 +6,9 @@ edition = "2021"
[dependencies]
exe = "0.5.6"
goblin = "0.9.2"
clap = { version = "4.5.4", features = [ "derive" ] }
lancelot = "0.8.6"
clap = { version = "4.5.4", features = [ "cargo" ] }
#lancelot = "0.8.6
syscalls = "0.6.18"
elf = "0.7.4"
#falcon = "0.5.5"

View file

@ -5,27 +5,35 @@ use std::ffi::CString;
use std::str::FromStr;
static NAME: &'static [u8] = &[b'\0'];
impl Vestal {
pub fn execute_data (&self, data: &[u8]) -> Usually<()> {
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(())
}
pub fn execute_path (&self, path: impl AsRef<Path>) -> Usually<()> {
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);
}
}
})
}
}
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

View file

@ -1,23 +1,32 @@
use crate::*;
impl Vestal {
pub fn inspect_data (&self, path: impl AsRef<Path>) -> Usually<()> { Ok(()) }
pub fn inspect_path (&self, path: impl AsRef<Path>) -> Usually<()> {
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);
}
}
})
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 {

View file

@ -1,76 +1,172 @@
mod execute;
mod inspect;
//mod execute;
//mod inspect;
mod memrun;
mod parse;
pub(crate) use std::path::Path;
//mod parse;
mod vst;
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}};
use std::collections::HashMap;
use clap::Parser;
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<()> {
Vestal::parse().run()
let matches = command!()
.arg(arg!([path] "Path to VST DLL").value_parser(value_parser!(PathBuf)))
.arg(arg!(-i --inspect "Show info, don't run").required(false))
//.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)?)?;
Ok(())
} else {
panic!("Pass a path to a VST DLL.")
}
}
#[derive(Debug, Parser)]
#[command(version, about, long_about = None)]
pub enum 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 }
fn read_dll (context: &mut Context, name: &str, path: &PathBuf) -> Usually<()> {
let name = canonical_name(&name);
if context.contains_key(&name) {
return Ok(())
}
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() {
imports.push(import.dll.to_lowercase());
}
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(())
}
pub enum Arch {
ThirtyTwo,
SixtyFour,
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()
}
impl Vestal {
pub fn run (&self) -> Usually<()> {
match self {
Self::Inspect { path } => self.inspect_path(path.as_str()),
Self::Execute { path } => self.execute_path(path.as_str()),
Self::Loader { path } => self.execute_path(path.as_str()),
fn slice_shebang (buffer: &[u8]) -> &[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;
}
}
pub fn with_path (
path: &impl AsRef<Path>,
cb: impl Fn(&[u8], &PE, Option<&Export>, HashMap<String, Vec<&Import>>)
) -> Usually<()> {
println!("Path: {}", path.as_ref().display());
let buffer = std::fs::read(path.as_ref())?;
Self::with_data(buffer.as_slice(), cb)
}
pub fn with_data (
buffer: &[u8],
callback: impl Fn(&[u8], &PE, Option<&Export>, HashMap<String, Vec<&Import>>)
) -> Usually<()> {
println!("PE: {}b", buffer.len());
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 {
println!("VSTPluginMain: {:?} + {:?}", &export.rva, &export.offset);
main = Some(export);
break
}
}
callback(&buffer, pe, main, imports);
Ok(())
} else {
Err("not a PE".into())
}
if slice {
println!("Slice: {index}");
&buffer[index+1..]
} else {
buffer
}
}
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()),
//}
//}
//}

View file

@ -1,35 +1,25 @@
use crate::*;
impl Vestal {
pub fn from_path (
path: &impl AsRef<Path>,
cb: impl Fn(&[u8], &PE, Option<&Export>, HashMap<String, Vec<&Import>>)
) -> Usually<()> {
println!("Path: {}", path.as_ref().display());
let buffer = std::fs::read(path.as_ref())?;
Self::from_data(buffer.as_slice(), cb)
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_data (
mut buffer: &[u8],
callback: impl Fn(&[u8], &PE, Option<&Export>, HashMap<String, Vec<&Import>>)
) -> 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;
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();
@ -38,17 +28,133 @@ impl Vestal {
}
imports.get_mut(dll).unwrap().push(import);
}
let mut exports: Vec<_> = Default::default();
for export in pe.exports.iter() {
if let Some("VSTPluginMain") = export.name {
main = Some(export);
break
}
exports.push(export)
}
callback(&buffer, pe, main, imports);
Ok(())
Ok(Self { buffer, pe, imports, exports, entrypoint: None })
} else {
Err("not a PE".into())
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())
//}
//}
//}

84
crates/vestal/src/vst.rs Normal file
View file

@ -0,0 +1,84 @@
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 {
magic: [u8; 4],
/// ```c
/// typedef VstIntPtr (VSTCALLBACK *AEffectDispatcherProc) (AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt);
/// ```
dispatcher: fn(*const AEffect, i32, i32, i32, *mut c_void, f32) -> usize,
/// ```c
/// typedef void (VSTCALLBACK *AEffectProcessProc) (AEffect* effect, float** inputs, float** outputs, VstInt32 sampleFrames);
/// typedef void (VSTCALLBACK *AEffectProcessDoubleProc) (AEffect* effect, double** inputs, double** outputs, VstInt32 sampleFrames);
/// ```
process: usize,
/// ```c
/// typedef void (VSTCALLBACK *AEffectSetParameterProc) (AEffect* effect, VstInt32 index, float parameter);
/// ```
set_parameter: usize,
/// ```c
/// typedef float (VSTCALLBACK *AEffectGetParameterProc) (AEffect* effect, VstInt32 index);
/// ```
get_parameter: usize,
num_programs: i32,
num_params: i32,
num_inputs: i32,
num_outputs: i32,
flags: i32,
resvd1: usize,
resvd2: usize,
initial_delay: i32,
real_qualities: i32,
off_qualities: i32,
io_ratio: f32,
object: usize,
user: usize,
unique_id: i32,
version: i32,
process_replacing: usize,
process_double_replacing: usize,
_future: [u8;56],
}
impl AEffect {
fn null_dispatcher (_: *const AEffect, _: i32, _: i32, _: i32, _: *mut c_void, _: f32) -> usize {
0
}
fn host_callback (
_: *const AEffect, opcode: i32, index: i32, value: i32, ptr: *mut c_void, opt: f32
) -> usize {
0
}
pub fn run (address: usize) -> Self {
let effect = Self::default();
// call(address, host_callback)
effect
}
}
impl Default for AEffect {
fn default () -> Self {
Self {
magic: [ b'V', b's', b't', b'P'],
dispatcher: Self::null_dispatcher,
process: 0,
set_parameter: 0,
get_parameter: 0,
num_programs: 0,
num_params: 0,
num_inputs: 0,
num_outputs: 0,
flags: 0,
resvd1: 0,
resvd2: 0,
initial_delay: 0,
real_qualities: 0,
off_qualities: 0,
io_ratio: 0.0,
object: 0,
user: 0,
unique_id: 0,
version: 0,
process_replacing: 0,
process_double_replacing: 0,
_future: [0;56],
}
}
}