diff --git a/Cargo.lock b/Cargo.lock index 621caf2..848ab2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,6 +37,16 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "base62" +version = "0.1.0" +dependencies = [ + "aes", + "cbc", + "regex", + "sha2", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -613,6 +623,7 @@ name = "ush-obfuscate" version = "0.1.0" dependencies = [ "aes", + "base62", "block-padding 0.4.2", "cbc", "getrandom", diff --git a/Cargo.toml b/Cargo.toml index 18808f0..a45acd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,8 @@ members = [ "ush-payload", # Libraries - "ush-obfuscate" + "ush-obfuscate", + "base62" ] [features] diff --git a/base62/Cargo.toml b/base62/Cargo.toml new file mode 100644 index 0000000..4414f72 --- /dev/null +++ b/base62/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "base62" +version = "0.1.0" +edition = "2024" + +[dependencies] +aes = "0.8.4" +cbc = "0.1.2" +regex = "1.12.3" +sha2 = "0.10.9" diff --git a/ush-obfuscate/src/crypt/aes_decrypt.rs b/base62/src/aes_decrypt.rs similarity index 94% rename from ush-obfuscate/src/crypt/aes_decrypt.rs rename to base62/src/aes_decrypt.rs index 70bd868..adb0b34 100644 --- a/ush-obfuscate/src/crypt/aes_decrypt.rs +++ b/base62/src/aes_decrypt.rs @@ -1,3 +1,8 @@ +use aes::cipher::{BlockDecryptMut, KeyIvInit, block_padding::Pkcs7}; +use regex::Regex; + +use crate::{Base62, hash}; + pub fn decrypt_aes(input: &str, key_str: &str, iv: [u8; 16]) -> Result { // Hash the env key to get a 32-byte (256-bit) AES key let mut key = hash(key_str.as_bytes()); diff --git a/ush-obfuscate/src/crypt/aes_encrypt.rs b/base62/src/aes_encrypt.rs similarity index 97% rename from ush-obfuscate/src/crypt/aes_encrypt.rs rename to base62/src/aes_encrypt.rs index 59e1346..9820c58 100644 --- a/ush-obfuscate/src/crypt/aes_encrypt.rs +++ b/base62/src/aes_encrypt.rs @@ -1,4 +1,4 @@ -use crate::crypt::{base62::Base62, hash}; +use crate::{base62::Base62, hash}; use aes::cipher::{BlockEncryptMut, KeyIvInit}; use cbc::cipher::block_padding::Pkcs7; diff --git a/ush-obfuscate/src/crypt/base62.rs b/base62/src/base62.rs similarity index 99% rename from ush-obfuscate/src/crypt/base62.rs rename to base62/src/base62.rs index e2504f0..eda55f4 100644 --- a/ush-obfuscate/src/crypt/base62.rs +++ b/base62/src/base62.rs @@ -1,4 +1,4 @@ -use crate::crypt::{STATIC_BYTE_MAP, hash}; +use crate::{STATIC_BYTE_MAP, hash}; // Randomly mapped Base62 characters pub struct Base62 { diff --git a/ush-obfuscate/src/crypt/mod.rs b/base62/src/lib.rs similarity index 89% rename from ush-obfuscate/src/crypt/mod.rs rename to base62/src/lib.rs index f8a53c2..b364d01 100644 --- a/ush-obfuscate/src/crypt/mod.rs +++ b/base62/src/lib.rs @@ -1,9 +1,12 @@ -pub mod aes_encrypt; +mod aes_decrypt; +mod aes_encrypt; #[allow(dead_code)] -pub mod base62; +mod base62; -pub const ENV_KEY_NAME: &str = "OBFUSCATION_KEY"; -pub const BACKUP_ENV_KEY: &str = "OBFUSCATION_KEY_DO_NOT_USE"; +// Exports +pub use aes_decrypt::{decrypt_aes, decrypt_aes_lines}; +pub use aes_encrypt::{encrypt_aes, encrypt_aes_lines}; +pub use base62::Base62; pub const STATIC_IV: [u8; 16] = [ 0x6d, 0x79, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x69, 0x76, 0x5f, 0x30, 0x31, 0x32, diff --git a/ush-obfuscate/Cargo.toml b/ush-obfuscate/Cargo.toml index 47ce283..1a6ea04 100644 --- a/ush-obfuscate/Cargo.toml +++ b/ush-obfuscate/Cargo.toml @@ -21,7 +21,7 @@ hex-literal = "1.1.0" regex = "1.12.2" sha2 = "0.10.9" -# unshell-crypt = {path = "../unshell-crypt"} +base62 = {path = "../base62"} # Common static_init = { workspace = true } diff --git a/ush-obfuscate/src/env.rs b/ush-obfuscate/src/env.rs new file mode 100644 index 0000000..4eb5a56 --- /dev/null +++ b/ush-obfuscate/src/env.rs @@ -0,0 +1,9 @@ +const ENV_KEY_NAME: &str = "OBFUSCATION_KEY"; +const BACKUP_ENV_KEY: &str = "OBFUSCATION_KEY_DO_NOT_USE"; + +pub fn get_encryption_key() -> String { + std::env::var(ENV_KEY_NAME).unwrap_or({ + println!("Using default encryption key!"); + BACKUP_ENV_KEY.to_owned() + }) +} diff --git a/ush-obfuscate/src/format_helper.rs b/ush-obfuscate/src/format_helper.rs index 54279ad..a9e00fc 100644 --- a/ush-obfuscate/src/format_helper.rs +++ b/ush-obfuscate/src/format_helper.rs @@ -1,9 +1,72 @@ +use proc_macro::TokenStream; +use quote::quote; use syn::parse::{Parse, ParseStream}; -use syn::{Expr, Lit, Token}; +use syn::{Expr, Lit, Token, parse_macro_input}; -pub struct PrintlnArgs { - pub format_str: String, - pub args: Vec, +pub fn format_obs(input: TokenStream) -> TokenStream { + let PrintlnArgs { format_str, args } = parse_macro_input!(input as PrintlnArgs); + + let segments = parse_format_string(&format_str); + + if segments.is_empty() { + return quote! { + print!("\n") + } + .into(); + } + + let mut parts = Vec::new(); + + for segment in segments { + match segment { + FormatSegment::Static(text) => { + parts.push(quote! { + obfuscate::symbol!(#text).to_string() + }); + } + FormatSegment::Dynamic(spec, idx) => { + if idx >= args.len() { + return syn::Error::new( + proc_macro2::Span::call_site(), + format!("argument {} is missing", idx), + ) + .to_compile_error() + .into(); + } + + let arg = &args[idx]; + let fmt_spec = if spec.is_empty() { + quote! { "{}" } + } else { + let full_spec = format!("{{{}}}", spec); + quote! { #full_spec } + }; + + // quote! { + // println!(#fmt_spec, #arg); + // } + parts.push(quote! { + format!(#fmt_spec, #arg) + }); + } + } + } + + (quote! { + { + let mut string = String::new(); + #( + string.push_str(&#parts); + )* + string + } + }) + .into() +} + +struct PrintlnArgs { + format_str: String, + args: Vec, } impl Parse for PrintlnArgs { @@ -40,12 +103,12 @@ impl Parse for PrintlnArgs { } #[derive(Debug)] -pub enum FormatSegment { +enum FormatSegment { Static(String), Dynamic(String, usize), // format spec, arg index } -pub fn parse_format_string(fmt: &str) -> Vec { +fn parse_format_string(fmt: &str) -> Vec { let mut segments = Vec::new(); let mut current_static = String::new(); let mut chars = fmt.chars().peekable(); diff --git a/ush-obfuscate/src/lib.rs b/ush-obfuscate/src/lib.rs index 0ae4e48..fd24e9a 100644 --- a/ush-obfuscate/src/lib.rs +++ b/ush-obfuscate/src/lib.rs @@ -3,12 +3,9 @@ use proc_macro::TokenStream; use quote::quote; -use syn::parse_macro_input; +mod env; mod format_helper; -use format_helper::*; - -mod crypt; #[allow(dead_code, unused_imports)] mod no_obfuscate; @@ -43,8 +40,6 @@ pub fn junk_asm(input: TokenStream) -> TokenStream { obs::junk_asm(input) } -// - #[proc_macro] pub fn file_symbol(_input: TokenStream) -> TokenStream { // Get the call site span to extract file information @@ -58,70 +53,10 @@ pub fn file_symbol(_input: TokenStream) -> TokenStream { let output = quote! { obfuscate::symbol!(#concatted) }; - // let output = quote! { - // #concatted - // }; output.into() } #[proc_macro] pub fn format_obs(input: TokenStream) -> TokenStream { - let PrintlnArgs { format_str, args } = parse_macro_input!(input as PrintlnArgs); - - let segments = parse_format_string(&format_str); - - if segments.is_empty() { - return quote! { - print!("\n") - } - .into(); - } - - let mut parts = Vec::new(); - - for segment in segments { - match segment { - FormatSegment::Static(text) => { - parts.push(quote! { - obfuscate::symbol!(#text).to_string() - }); - } - FormatSegment::Dynamic(spec, idx) => { - if idx >= args.len() { - return syn::Error::new( - proc_macro2::Span::call_site(), - format!("argument {} is missing", idx), - ) - .to_compile_error() - .into(); - } - - let arg = &args[idx]; - let fmt_spec = if spec.is_empty() { - quote! { "{}" } - } else { - let full_spec = format!("{{{}}}", spec); - quote! { #full_spec } - }; - - // quote! { - // println!(#fmt_spec, #arg); - // } - parts.push(quote! { - format!(#fmt_spec, #arg) - }); - } - } - } - - (quote! { - { - let mut string = String::new(); - #( - string.push_str(&#parts); - )* - string - } - }) - .into() + format_helper::format_obs(input) } diff --git a/ush-obfuscate/src/obfuscate/mod.rs b/ush-obfuscate/src/obfuscate/mod.rs index 6d70b03..ba30f46 100644 --- a/ush-obfuscate/src/obfuscate/mod.rs +++ b/ush-obfuscate/src/obfuscate/mod.rs @@ -5,14 +5,3 @@ mod sym_aes_strings; pub use obs_junk_asm::junk_asm; pub use obs_xor::xor; pub use sym_aes_strings::*; - -use crate::crypt::{BACKUP_ENV_KEY, ENV_KEY_NAME}; - -fn get_encryption_key() -> String { - std::env::var(ENV_KEY_NAME).unwrap_or({ - println!("Using default encryption key!"); - BACKUP_ENV_KEY.to_owned() - }) -} - -// pub fn diff --git a/ush-obfuscate/src/obfuscate/sym_aes_strings.rs b/ush-obfuscate/src/obfuscate/sym_aes_strings.rs index 4d6437c..4ed6253 100644 --- a/ush-obfuscate/src/obfuscate/sym_aes_strings.rs +++ b/ush-obfuscate/src/obfuscate/sym_aes_strings.rs @@ -1,9 +1,9 @@ -use crate::crypt::{BACKUP_ENV_KEY, ENV_KEY_NAME, STATIC_IV, aes_encrypt::encrypt_aes_lines}; +use base62::{STATIC_IV, encrypt_aes_lines}; use proc_macro::TokenStream; use quote::quote; use syn::{ItemFn, LitStr, parse_macro_input}; -use crate::obfuscate::get_encryption_key; +use crate::env::get_encryption_key; /// Obfuscate function names by encrypting in AES pub fn aes_fn_name(_attr: TokenStream, item: TokenStream) -> TokenStream {