From e8f7fae77a410671e5e5bcad36d0d970e89b8f08 Mon Sep 17 00:00:00 2001 From: 7ap <109433659+7ap@users.noreply.github.com> Date: Sat, 18 Nov 2023 21:27:08 -0800 Subject: [PATCH] feat: add patcher --- Cargo.toml | 8 ++++++++ src/main.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index da51a13..5f8691b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,4 +4,12 @@ version = "0.0.0" edition = "2021" publish = false +[profile.release] +strip = true +opt-level = "z" +lto = true +codegen-units = 1 + [dependencies] +clap = { version = "4.4", features = ["derive"] } +winreg = "0.51" diff --git a/src/main.rs b/src/main.rs index e7a11a9..49cdd38 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,57 @@ +use std::fs; +use std::path::PathBuf; +use std::time::Instant; + +use clap::Parser; +use winreg::{enums::HKEY_CLASSES_ROOT, RegKey}; + +const SIGNATURE: &[u8] = &[ + 0x41, 0x80, 0xbe, 0x50, 0x01, 0x00, 0x00, 0x00, 0x74, 0x05, 0xe8, +]; + +const PATCH: &[u8] = &[ + 0x41, 0x80, 0xbe, 0x50, 0x01, 0x00, 0x00, 0x00, 0x90, 0x90, 0xe8, +]; + +#[derive(Parser)] +#[command(author, version, about, long_about = None)] +struct Cli { + input: Option, + output: Option, +} + +fn patch(input: &PathBuf, output: &PathBuf) { + let mut binary = fs::read(input).expect("Could not read input file."); + + let offset = binary + .windows(SIGNATURE.len()) + .position(|window| window == SIGNATURE) + .expect("Could not find signature."); + + binary[offset..offset + PATCH.len()].copy_from_slice(PATCH); + fs::write(output, binary).expect("Could not write output file."); +} + fn main() { - println!("Hello, world!"); + let Cli { input, output } = Cli::parse(); + + #[rustfmt::skip] + let input = input.unwrap_or_else(|| { + let path: String = RegKey::predef(HKEY_CLASSES_ROOT) + .open_subkey("roblox-studio").unwrap() + .open_subkey("DefaultIcon").unwrap() + .get_value("").unwrap(); + + PathBuf::from(path) + }); + + let output = if cfg!(debug_assertions) { + output.unwrap_or_else(|| input.with_file_name("RobloxStudioBeta_INTERNAL.exe")) + } else { + output.unwrap_or_else(|| input.clone()) // TODO: Is convenience really worth it? + }; + + let now = Instant::now(); + patch(&input, &output); + println!("Patched in {:?}.", now.elapsed()); }