Add refrerence symbolic strings

This commit is contained in:
Michael Mikovsky
2026-02-20 18:17:11 -07:00
parent 55d2deef1c
commit 689c4ac714
12 changed files with 153 additions and 96 deletions
@@ -1,7 +1,57 @@
use aes::cipher::{BlockDecryptMut, KeyIvInit, block_padding::Pkcs7}; use crate::{base62::Base62, hash};
use aes::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit};
use cbc::cipher::block_padding::Pkcs7;
use regex::Regex; use regex::Regex;
use crate::{Base62, hash}; fn pkcs7_padded_length(input_len: usize) -> usize {
let block_size = 16;
((input_len / block_size) + 1) * block_size
}
pub fn encrypt_aes(plaintext: &str, key_str: &str, iv: [u8; 16]) -> String {
let plaintext = plaintext.as_bytes();
// Hash the env key to get a 32-byte (256-bit) AES key
let key = hash(key_str.as_bytes());
// Generate a pseudo-random salt byte based on the plaintext
// I hope this does not break the encryption.
let mut salt = 0;
for byte in plaintext {
salt ^= byte;
}
let mut key_salted = key.clone();
// Salt the key by XORing the salt byte with all the key bytes.
// This ensures that the "hash" generated from the plaintext will
// make the encrypted result extremely different.
for i in 0..32 {
key_salted[i] ^= salt;
}
let buf_len = pkcs7_padded_length(plaintext.len());
let mut buf = vec![0u8; buf_len];
let pt_len = plaintext.len();
buf[..pt_len].copy_from_slice(&plaintext);
let mut ct = cbc::Encryptor::<aes::Aes256>::new(&key_salted.into(), &iv.into())
.encrypt_padded_mut::<Pkcs7>(&mut buf, pt_len)
.unwrap()
.to_vec();
// Add the salt byte to the key byte,
ct.insert(0, salt);
// Encode result in base62
Base62::encode_full(&ct, &key)
}
pub fn encrypt_aes_lines(plaintext: &str, key_str: &str, iv: [u8; 16]) -> String {
format!("_{}_", encrypt_aes(plaintext, key_str, iv))
}
pub fn decrypt_aes(input: &str, key_str: &str, iv: [u8; 16]) -> Result<String, String> { pub fn decrypt_aes(input: &str, key_str: &str, iv: [u8; 16]) -> Result<String, String> {
// Hash the env key to get a 32-byte (256-bit) AES key // Hash the env key to get a 32-byte (256-bit) AES key
-53
View File
@@ -1,53 +0,0 @@
use crate::{base62::Base62, hash};
use aes::cipher::{BlockEncryptMut, KeyIvInit};
use cbc::cipher::block_padding::Pkcs7;
fn pkcs7_padded_length(input_len: usize) -> usize {
let block_size = 16;
((input_len / block_size) + 1) * block_size
}
pub fn encrypt_aes(plaintext: &str, key_str: &str, iv: [u8; 16]) -> String {
let plaintext = plaintext.as_bytes();
// Hash the env key to get a 32-byte (256-bit) AES key
let key = hash(key_str.as_bytes());
// Generate a psudo-random salt byte based on the plaintext
// I hope this does not break the encryption.
let mut salt = 0;
for byte in plaintext {
salt ^= byte;
}
let mut key_salted = key.clone();
// Salt the key by XORing the salt byte with all the key bytes.
// This ensures that the "hash" generated from the plaintext will
// make the encrypted result extremely different.
for i in 0..32 {
key_salted[i] ^= salt;
}
let buf_len = pkcs7_padded_length(plaintext.len());
let mut buf = vec![0u8; buf_len];
let pt_len = plaintext.len();
buf[..pt_len].copy_from_slice(&plaintext);
let mut ct = cbc::Encryptor::<aes::Aes256>::new(&key_salted.into(), &iv.into())
.encrypt_padded_mut::<Pkcs7>(&mut buf, pt_len)
.unwrap()
.to_vec();
// Add the salt byte to the key byte,
ct.insert(0, salt);
// Encode result in base62
Base62::encode_full(&ct, &key)
}
pub fn encrypt_aes_lines(plaintext: &str, key_str: &str, iv: [u8; 16]) -> String {
format!("_{}_", encrypt_aes(plaintext, key_str, iv))
}
+4 -3
View File
@@ -18,19 +18,20 @@ const ENCODING_RATIO: f64 = 8.0 / 5.954196310386875; // 8.0 / log2(62.0)
impl Base62 { impl Base62 {
pub fn new(key: &[u8], nonce: usize) -> Self { pub fn new(key: &[u8], nonce: usize) -> Self {
// Hash key again, for the chance that this random function can be used to derive the key // Hash key again, for the chance that this random function can be used to derive the key
// My solution to not being good at cryptography lol
let key = hash(key); let key = hash(key);
let mut charset: [char; 62] = [0 as char; 62]; let mut charset: [char; 62] = [0 as char; 62];
// Create a vector of indices from 0 to 61 // Create a vector of indices from 0 to 61
let mut current_indicies = (0..62).map(|i| i as usize).collect::<Vec<usize>>(); let mut current_indices = (0..62).map(|i| i as usize).collect::<Vec<usize>>();
// Loop through each byte in the key until all chars are filled // Loop through each byte in the key until all chars are filled
for i in 0..62 as usize { for i in 0..62 as usize {
let rand = STATIC_BYTE_MAP[(key[i as usize % key.len()] as usize + nonce) % 255]; let rand = STATIC_BYTE_MAP[(key[i as usize % key.len()] as usize + nonce) % 255];
let index_index = rand as usize % current_indicies.len(); let index_index = rand as usize % current_indices.len();
let put_index = current_indicies.remove(index_index); let put_index = current_indices.remove(index_index);
charset[put_index] = BASE62_CHARS[i]; charset[put_index] = BASE62_CHARS[i];
} }
+18 -5
View File
@@ -1,11 +1,8 @@
mod aes_decrypt; mod aes;
mod aes_encrypt;
#[allow(dead_code)]
mod base62; mod base62;
// Exports // Exports
pub use aes_decrypt::{decrypt_aes, decrypt_aes_lines}; pub use aes::{decrypt_aes, decrypt_aes_lines, encrypt_aes, encrypt_aes_lines};
pub use aes_encrypt::{encrypt_aes, encrypt_aes_lines};
pub use base62::Base62; pub use base62::Base62;
pub const STATIC_IV: [u8; 16] = [ pub const STATIC_IV: [u8; 16] = [
@@ -35,3 +32,19 @@ pub fn hash(input: &[u8]) -> [u8; 32] {
hasher.update(input); hasher.update(input);
hasher.finalize().into() hasher.finalize().into()
} }
pub fn encode_usize(value: usize) -> Vec<u8> {
if value == 0 {
return vec![0];
}
let bytes = value.to_be_bytes();
let leading_zeros = bytes.iter().take_while(|&&b| b == 0).count();
bytes[leading_zeros..].to_vec()
}
pub fn decode_usize(bytes: &[u8]) -> usize {
let mut buf = [0u8; size_of::<usize>()];
let offset = buf.len() - bytes.len();
buf[offset..].copy_from_slice(bytes);
usize::from_be_bytes(buf)
}
+3
View File
@@ -5,6 +5,9 @@
# -Z build-std-features= \ # -Z build-std-features= \
# --profile minimize -p unshell-payload -- $@ # --profile minimize -p unshell-payload -- $@
set -e
OBFUSCATION_KEY=kjwerkwerkjbwejehrwhje \
cargo build --profile minimize -p ush-payload $@ cargo build --profile minimize -p ush-payload $@
export BINARY=./target/minimize/ush-payload export BINARY=./target/minimize/ush-payload
+1 -2
View File
@@ -6,8 +6,7 @@ authors.workspace = true
include.workspace = true include.workspace = true
[features] [features]
default = ["obfuscate_none"] default = []
obfuscate_none = []
obfuscate_aes = [] obfuscate_aes = []
obfuscate_ref = [] obfuscate_ref = []
+4 -2
View File
@@ -2,8 +2,10 @@ const ENV_KEY_NAME: &str = "OBFUSCATION_KEY";
const BACKUP_ENV_KEY: &str = "OBFUSCATION_KEY_DO_NOT_USE"; const BACKUP_ENV_KEY: &str = "OBFUSCATION_KEY_DO_NOT_USE";
pub fn get_encryption_key() -> String { pub fn get_encryption_key() -> String {
std::env::var(ENV_KEY_NAME).unwrap_or({ if let Ok(key) = std::env::var(ENV_KEY_NAME) {
key
} else {
println!("Using default encryption key!"); println!("Using default encryption key!");
BACKUP_ENV_KEY.to_owned() BACKUP_ENV_KEY.to_owned()
}) }
} }
-3
View File
@@ -14,9 +14,6 @@ pub fn xor(input: TokenStream) -> TokenStream {
return TokenStream::from(quote! { String::new() }); return TokenStream::from(quote! { String::new() });
} }
// --- Obfuscated Branch Logic ---
// This code runs at compile-time
let str_bytes = original_str.as_bytes(); let str_bytes = original_str.as_bytes();
let len = str_bytes.len(); let len = str_bytes.len();
+2 -2
View File
@@ -30,7 +30,7 @@ macro_rules! delete {
}; };
} }
#[cfg(feature = "obfuscate_none")] #[cfg(all(not(feature = "obfuscate_aes"), not(feature = "obfuscate_ref")))]
pub mod proc_impl { pub mod proc_impl {
use proc_macro::TokenStream; use proc_macro::TokenStream;
use syn::{LitStr, parse_macro_input}; use syn::{LitStr, parse_macro_input};
@@ -61,6 +61,6 @@ pub mod proc_impl {
unwrap_string!(xor); unwrap_string!(xor);
delete!(junk_asm); delete!(junk_asm);
unwrap_string!(sym); passtrough!(sym, crate::symbolic_ref::sym_ref);
unwrap_string!(sym_fn); unwrap_string!(sym_fn);
} }
+47
View File
@@ -1 +1,48 @@
use std::collections::HashMap;
use base62::{Base62, hash};
use proc_macro::TokenStream;
use quote::quote;
use syn::{LitStr, parse_macro_input};
use crate::env::get_encryption_key;
static mut SYM_COUNTER: Vec<String> = Vec::new();
#[allow(static_mut_refs)]
pub fn get_symbol_number() -> usize {
unsafe { SYM_COUNTER.len() }
}
#[allow(static_mut_refs)]
pub fn get_symbol(text: String) -> usize {
unsafe {
if let Some(n) = SYM_COUNTER.iter().position(|r| r == &text) {
n
} else {
SYM_COUNTER.push(text);
SYM_COUNTER.len() - 1
}
}
}
pub fn sym_ref(input: TokenStream) -> TokenStream {
// Parse the input as a string literal
let lit_str = parse_macro_input!(input as LitStr);
let original_name = lit_str.value();
let n = get_symbol(original_name);
let data = base62::encode_usize(n);
let key = hash(&get_encryption_key().as_bytes());
let encoded = format!("_{}_", Base62::encode_full(&data, &key));
println!("Aliased '{}' as '{encoded}'", lit_str.value());
// Expand to a static string literal
TokenStream::from(quote! {
#encoded
})
}
+1 -1
View File
@@ -8,7 +8,7 @@ edition = "2024"
default = ["log"] default = ["log"]
log = ["unshell/log"] log = ["unshell/log"]
log_debug = ["unshell/log_debug"] log_debug = ["unshell/log_debug"]
obfuscate = ["unshell/obfuscate_aes"] obfuscate = ["unshell/obfuscate_ref"]
[dependencies] [dependencies]
unshell.path = "../" unshell.path = "../"
+21 -23
View File
@@ -1,46 +1,44 @@
#![macro_use] #![macro_use]
extern crate unshell; extern crate unshell;
use unshell::{ use unshell::{info, obfuscate::sym, tree::Tree};
Value, info,
obfuscate::{junk_asm, sym},
tree::{Tree, TreeElement, symbols},
};
fn main() { fn main() {
let mut manager = Tree::new(); let mut manager = Tree::new();
manager.init_logger(); manager.init_logger();
println!("{}", sym!("TEST"));
info!("Test thing!"); info!("Test thing!");
info!("Test thing!"); info!("Test thing!");
loop { // loop {
if test123(&mut manager) { // if test123(&mut manager) {
break; // break;
} // }
} // }
// println!("Test"); // println!("Test");
} }
fn test123(manager: &mut Tree) -> bool { // fn test123(manager: &mut Tree) -> bool {
let result = manager.send_message( // let result = manager.send_message(
Value::String(sym!("Logger").to_string()), // Value::String(sym!("Logger").to_string()),
Value::String(symbols::CMD_GET.to_string()), // Value::String(symbols::CMD_GET.to_string()),
); // );
junk_asm!(20.); // junk_asm!(20.);
let is_null = result.is_null(); // let is_null = result.is_null();
// if let Ok(result) = serde_json::from_value::<Record>(result) { // // if let Ok(result) = serde_json::from_value::<Record>(result) {
// log(&result); // // log(&result);
// } // // }
is_null // is_null
// println!("Logger: {}", result); // // println!("Logger: {}", result);
} // }
// use std::{any::Any, collections::HashMap, fs::File, io::Read}; // use std::{any::Any, collections::HashMap, fs::File, io::Read};