diff --git a/src/cli/build.rs b/src/cli/build.rs index 99c64e7..156191a 100644 --- a/src/cli/build.rs +++ b/src/cli/build.rs @@ -8,6 +8,11 @@ use tokio::{ use anyhow::Result; use mlua::Compiler as LuaCompiler; +// The signature which separates indicates the presence of bytecode to execute +// If a binary contains this magic signature as the last 8 bytes, that must mean +// it is a standalone binary +pub const MAGIC: &[u8; 8] = b"cr3sc3nt"; + /** Compiles and embeds the bytecode of a requested lua file to form a standalone binary, then writes it to an output file, with the required permissions. @@ -32,10 +37,6 @@ pub async fn build_standalone>( let mut patched_bin = fs::read(env::current_exe()?).await?; let base_bin_offset = u64::try_from(patched_bin.len())?; - // The signature which separates indicates the presence of bytecode to execute - // If a binary contains this signature, that must mean it is a standalone binary - let signature: Vec = vec![0x4f, 0x3e, 0xf8, 0x41, 0xc3, 0x3a, 0x52, 0x16]; - // Compile luau input into bytecode let bytecode = LuaCompiler::new() .set_optimization_level(2) @@ -45,18 +46,18 @@ pub async fn build_standalone>( println!(" {bytecode_prefix} {script_path}"); - patched_bin.append(&mut bytecode.clone()); + patched_bin.extend(&bytecode); - let mut meta = base_bin_offset.to_ne_bytes().to_vec(); + let mut meta = base_bin_offset.to_ne_bytes().to_vec(); // Start with the base bytecode offset // Include metadata in the META chunk, each field is 8 bytes - meta.append(&mut (bytecode.len() as u64).to_ne_bytes().to_vec()); // Size of bytecode, used to calculate end offset at runtime - meta.append(&mut 1_u64.to_ne_bytes().to_vec()); // Number of files, padded with null bytes - for future use + meta.extend((bytecode.len() as u64).to_ne_bytes()); // Size of bytecode, used to calculate end offset at runtime + meta.extend(1_u64.to_ne_bytes()); // Number of files, padded with null bytes - for future use - patched_bin.append(&mut meta); + patched_bin.extend(meta); - // Append the signature to the base binary - patched_bin.append(&mut signature.clone()); + // Append the magic signature to the base binary + patched_bin.extend(MAGIC); // Write the compiled binary to file #[cfg(target_family = "unix")] diff --git a/src/executor.rs b/src/executor.rs index 18e025e..dac4e0c 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -1,5 +1,6 @@ use std::{env, ops::ControlFlow, process::ExitCode}; +use crate::cli::build::MAGIC; use lune::Lune; use anyhow::Result; @@ -9,10 +10,7 @@ use tokio::fs::read as read_to_vec; Returns information about whether the execution environment is standalone or not, the standalone binary signature, and the contents of the binary. */ -pub async fn check_env() -> (bool, Vec, Vec) { - // Signature which is only present in standalone lune binaries - let signature: Vec = vec![0x4f, 0x3e, 0xf8, 0x41, 0xc3, 0x3a, 0x52, 0x16]; - +pub async fn check_env() -> (bool, Vec) { // Read the current lune binary to memory let bin = if let Ok(contents) = read_to_vec( env::current_exe().expect("failed to get path to current running lune executable"), @@ -24,20 +22,21 @@ pub async fn check_env() -> (bool, Vec, Vec) { Vec::new() }; - let is_standalone = !bin.is_empty() && bin[bin.len() - signature.len()..bin.len()] == signature; + let is_standalone = + !bin.is_empty() && bin[bin.len() - MAGIC.len()..bin.len()] == MAGIC.to_vec(); - (is_standalone, signature, bin) + (is_standalone, bin) } /** Discovers, loads and executes the bytecode contained in a standalone binary. */ -pub async fn run_standalone(signature: Vec, bin: Vec) -> Result { +pub async fn run_standalone(bin: Vec) -> Result { let mut bytecode_offset = 0; let mut bytecode_size = 0; // standalone binary structure (reversed, 8 bytes per field) - // [0] => signature + // [0] => magic signature // ---------------- // -- META Chunk -- // [1] => file count @@ -47,21 +46,21 @@ pub async fn run_standalone(signature: Vec, bin: Vec) -> Result bytecode (variable size) // ---------------- - // NOTE: All integers are 8 byte unsigned 64 bit (u64's). + // NOTE: All integers are 8 byte, padded, unsigned & 64 bit (u64's). // The rchunks will have unequally sized sections in the beginning // but that doesn't matter to us because we don't need anything past the // middle chunks where the bytecode is stored - bin.rchunks(signature.len()) + bin.rchunks(MAGIC.len()) .enumerate() .try_for_each(|(idx, chunk)| { if bytecode_offset != 0 && bytecode_size != 0 { return ControlFlow::Break(()); } - if idx == 0 && chunk != signature { + if idx == 0 && chunk != MAGIC { // Binary is guaranteed to be standalone, we've confirmed this before - unreachable!("expected proper signature for standalone binary") + unreachable!("expected proper magic signature for standalone binary") } if idx == 3 { @@ -78,16 +77,19 @@ pub async fn run_standalone(signature: Vec, bin: Vec) -> Result>(); + let bytecode = + &bin[usize::try_from(bytecode_offset)?..usize::try_from(bytecode_offset + bytecode_size)?]; + + // println!("bytecode: {:?}", bytecode); let result = Lune::new() .with_args(args) - .run( - "STANDALONE", - &bin[usize::try_from(bytecode_offset)? - ..usize::try_from(bytecode_offset + bytecode_size)?], - ) + .run("STANDALONE", bytecode) .await; Ok(match result { diff --git a/src/main.rs b/src/main.rs index 1febe40..3cdb821 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,12 +28,12 @@ async fn main() -> ExitCode { .with_level(true) .init(); - let (is_standalone, signature, bin) = executor::check_env().await; + let (is_standalone, bin) = executor::check_env().await; if is_standalone { // It's fine to unwrap here since we don't want to continue // if something fails - return executor::run_standalone(signature, bin).await.unwrap(); + return executor::run_standalone(bin).await.unwrap(); } match Cli::parse().run().await {