mirror of
https://codeberg.org/unspeaker/vestal.git
synced 2025-12-06 12:56:41 +01:00
shebang loader
This commit is contained in:
parent
a22b17d6de
commit
b6451308e0
8 changed files with 207 additions and 26 deletions
|
|
@ -9,4 +9,5 @@ goblin = "0.9.2"
|
|||
clap = { version = "4.5.4", features = [ "derive" ] }
|
||||
lancelot = "0.8.6"
|
||||
syscalls = "0.6.18"
|
||||
elf = "0.7.4"
|
||||
#falcon = "0.5.5"
|
||||
|
|
|
|||
|
|
@ -1,25 +1,68 @@
|
|||
use crate::*;
|
||||
use syscalls::{Sysno, syscall};
|
||||
static NAME: &'static [char] = &['\0'];
|
||||
use elf::file::Elf64_Ehdr;
|
||||
use std::ffi::CString;
|
||||
use std::str::FromStr;
|
||||
static NAME: &'static [u8] = &[b'\0'];
|
||||
impl Vestal {
|
||||
pub fn execute (&self, path: impl AsRef<Path>) -> Usually<()> {
|
||||
Self::with_pe(&path, |buffer, pe, main, deps|{
|
||||
let fd = Self::get_fd();
|
||||
// TODO: compose in-memory ELF binary out of PE sections and Wine libraries
|
||||
Self::write(fd, buffer);
|
||||
println!("{fd}");
|
||||
pub fn execute_data (&self, data: &[u8]) -> Usually<()> {
|
||||
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 get_fd () -> usize {
|
||||
match unsafe { syscall!(Sysno::memfd_create, NAME.as_ptr(), 0x0001, 0) } {
|
||||
Err(no) => panic!("memfd_create failed: {no}"),
|
||||
Ok(fd) => fd,
|
||||
}
|
||||
}
|
||||
fn write (fd: usize, buffer: &[u8]) {
|
||||
match unsafe { syscall!(Sysno::write, fd, buffer.as_ptr()) } {
|
||||
Err(no) => panic!("write failed: {no}"),
|
||||
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
|
||||
}
|
||||
/// 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,8 +1,9 @@
|
|||
use crate::*;
|
||||
|
||||
impl Vestal {
|
||||
pub fn inspect (&self, path: impl AsRef<Path>) -> Usually<()> {
|
||||
Self::with_pe(&path, |buffer, pe, main, deps|{
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
mod execute;
|
||||
mod inspect;
|
||||
mod memrun;
|
||||
mod parse;
|
||||
pub(crate) use std::path::Path;
|
||||
pub(crate) use goblin::{error, Object, pe::{PE, import::Import, export::Export}};
|
||||
use std::collections::HashMap;
|
||||
|
|
@ -18,22 +20,37 @@ pub enum Vestal {
|
|||
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.as_str()),
|
||||
Self::Execute { path } => self.execute(path.as_str()),
|
||||
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()),
|
||||
}
|
||||
}
|
||||
pub fn with_pe (
|
||||
pub fn with_path (
|
||||
path: &impl AsRef<Path>,
|
||||
cb: impl Fn(&[u8], &PE, Option<&Export>, HashMap<String, Vec<&Import>>)
|
||||
) -> Usually<()> {
|
||||
println!("PE: {}", path.as_ref().display());
|
||||
println!("Path: {}", path.as_ref().display());
|
||||
let buffer = std::fs::read(path.as_ref())?;
|
||||
if let Object::PE(ref pe) = Object::parse(&buffer)? {
|
||||
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() {
|
||||
|
|
@ -50,7 +67,7 @@ impl Vestal {
|
|||
break
|
||||
}
|
||||
}
|
||||
cb(&buffer, pe, main, imports);
|
||||
callback(&buffer, pe, main, imports);
|
||||
Ok(())
|
||||
} else {
|
||||
Err("not a PE".into())
|
||||
|
|
|
|||
57
crates/vestal/src/memrun.rs
Normal file
57
crates/vestal/src/memrun.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
use std::fmt::{Debug, Display};
|
||||
use syscalls::{Sysno, Errno, syscall};
|
||||
|
||||
static EMPTY: &'static [u8] = &[b'\0'];
|
||||
static CMD: &'static [u8] = &[b'/',b'p',b'r',b'o',b'c',b'/',b's',b'e',b'l',b'f',b'/',b'f',b'd',b'/',b'3',b'\0'];
|
||||
static ARGS: &'static [u8] = &[b'\0',b'\0'];
|
||||
static ENVS: &'static [u8] = &[b'\0'];
|
||||
|
||||
pub struct MemRun(usize);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MemRunError {
|
||||
MemfdCreateFailed(Errno),
|
||||
ExecveFailed(Errno),
|
||||
}
|
||||
|
||||
impl MemRun {
|
||||
pub fn new () -> Result<Self, MemRunError> {
|
||||
unsafe { syscall!(Sysno::memfd_create, EMPTY.as_ptr(), 0x0001, 0) }
|
||||
.map_err(MemRunError::MemfdCreateFailed)
|
||||
.map(Self)
|
||||
}
|
||||
pub fn run (code: &[u8]) -> Result<(), MemRunError> {
|
||||
let cmd = b"/proc/self/fd/3\0";
|
||||
let arg = [b"custom process name\0"];
|
||||
let env = [b"\0"];
|
||||
unsafe { syscall!(Sysno::execve, CMD.as_ptr(), ARGS.as_ptr(), ENVS.as_ptr()) }
|
||||
.map_err(MemRunError::ExecveFailed)
|
||||
.map(|_|())
|
||||
}
|
||||
}
|
||||
|
||||
// From https://github.com/guitmz/memrun/
|
||||
fn get_fd () -> usize {
|
||||
match unsafe { syscall!(Sysno::memfd_create, EMPTY.as_ptr(), 0x0001, 0) } {
|
||||
Err(no) => panic!("memfd_create failed: {no}"),
|
||||
Ok(fd) => fd,
|
||||
}
|
||||
}
|
||||
// From https://github.com/guitmz/memrun/
|
||||
fn write (fd: usize, buffer: &[u8]) {
|
||||
match unsafe { syscall!(Sysno::write, fd, buffer.as_ptr()) } {
|
||||
Err(no) => panic!("write failed: {no}"),
|
||||
Ok(_) => (),
|
||||
}
|
||||
}
|
||||
// From https://github.com/guitmz/memrun/
|
||||
fn run (fd: usize) {
|
||||
println!("fd = {fd}");
|
||||
let cmd = b"/proc/self/fd/3\0";
|
||||
let arg = [b"it is i, leclerc\0"];
|
||||
let env = [b"\0"];
|
||||
match unsafe { syscall!(Sysno::execve, cmd.as_ptr(), arg.as_ptr(), env.as_ptr()) } {
|
||||
Err(no) => panic!("write failed: {no}"),
|
||||
Ok(_) => (),
|
||||
}
|
||||
}
|
||||
54
crates/vestal/src/parse.rs
Normal file
54
crates/vestal/src/parse.rs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
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 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;
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue