diff --git a/Cargo.lock b/Cargo.lock index f5b0353..5b97e71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,6 +64,22 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "cryptify" +version = "3.0.8" +dependencies = [ + "labyrinth_macros 2.0.0", +] + +[[package]] +name = "cryptify" +version = "3.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d7875a5ccecb7451ad5542c0394e5fd7507c2be0ed2b88cbe96a35809f6f26b" +dependencies = [ + "labyrinth_macros 2.0.0", +] + [[package]] name = "getrandom" version = "0.2.11" @@ -101,15 +117,20 @@ dependencies = [ ] [[package]] -name = "labyrinth" -version = "0.1.0" +name = "labyrinth_macros" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a49a429784bf214985bd5e5c058a89889a2e5b9fc60ebd60ced2bf0429791fa4" dependencies = [ - "labyrinth_macros", + "proc-macro2", + "quote", + "rand", + "syn", ] [[package]] name = "labyrinth_macros" -version = "0.1.0" +version = "3.0.0" dependencies = [ "proc-macro2", "quote", @@ -220,10 +241,10 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rust-obfuscator" -version = "0.1.0" +version = "1.0.0" dependencies = [ "clap", - "labyrinth", + "cryptify 3.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2", "quote", "rand", diff --git a/Cargo.toml b/Cargo.toml index 713a81f..0faa24f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,8 @@ [workspace] members = [ "auto_obfuscate", - "labyrinth", + "cryptify", "labyrinth_macros", ] +default-members = ["auto_obfuscate"] resolver = "2" \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..11b85ad --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Pranav Dronavalli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 83618f1..4f5c98a 100644 --- a/README.md +++ b/README.md @@ -1 +1,236 @@ -# rust-obfuscator \ No newline at end of file +# Rust-Obfuscator + +`rust-obfuscator` is a set of tools designed to automatically obfuscate Rust source code by inserting procedural macros or by (optionally) providing the obfuscation in the source code directly. For more fine-grained obfuscation a procedural macro library [cryptify](https://crates.io/crates/cryptify) is also provided. + +## Currently Supported +1. string literal encryption +2. control-flow obfuscation +3. control-flow obfuscation (source code) +4. variable renaming (source code) + +## Features + +- **String Encryption**: Automatically encrypts string literals assigned to local variables at compile time. + - Can also be used for formatted strings, but currently requires manual placement + ```rs + println!("{}", cryptify::encrypt_string!("hello!")); + ``` +- **Control Flow Obfuscation**: Introduces compile-dummy dummy loops and random variables. +- **Customizable Obfuscation**: Offers flexibility to enable or disable specific obfuscation features based on your requirements. +- **Variable Renaming**: Obfuscation of the source code directly, if you'd like to ship the code or just want to make your code look worse. + +## Installation + +Add `cryptify` to your `Cargo.toml` as a dependency: + +```toml +[dependencies] +cryptify = "3.1.0" +``` + +To install `rust-obfuscator`, clone the repository and build the tool using Cargo from the root: +``` +cargo build --release --bin rust-obfuscator +``` +The binary can then be found under /target/release, you can copy it to the root of the project like such +``` +cp ./target/release/rust-obfuscator . +``` + +# Usage +Set the **CRYPTIFY_KEY** environment variable for custom encryption otherwise it defaults to defined fixed key +- Add to source code you'd like to modify +```rs +use cryptify; +``` +The binary can be used on either a file or a directory. If provided with a directory it will only modify rust source files within that directory not any subdirectories +```sh +./rust-obfuscator path/to/your_project +``` +- All Obfuscated code will be under the **obfuscated_code** directory that is created from the directory the tool was run. +- **Recommended to use a Rust Formatter with the obfuscated code as syn naturally modifies the structure and it will be written to the file as one line** + +## Option Flags +- --no_string: Disables string obfuscation. +- --no_flow: Disables control flow obfuscation. +- --disable_macro: Uses direct source manipulation for flow obfuscation instead of procedural macros. +- --var: Enables variable renaming source code obfuscation. + +### Example usage with flag +```sh +rust-obfuscator path/to/your_project --no_flow +``` +(disables flow obfuscation) + +# Input +-running the tool with no config +```rs +use cryptify; +mod word_counter; +use std::env; +use std::fs; +use word_counter::count_words; +fn main() { + let b = "Hello World"; + println!("{}", b); + let args: Vec = env::args().collect(); + if args.len() < 2 { + eprintln!("Usage: {} ", args[0]); + return; + } + let filename = &args[1]; + let content = fs::read_to_string(filename).expect("Could not read file"); + let word_counts = count_words(&content); + for (word, count) in word_counts.iter() { + println!("{}: {}", word, count); + } +} + +fn dummy() { + let a = 1; + let b = 2; + let c = a + b; + println!("{}", c); +} + +fn calc_sum(a: i32, b: i32) -> i32 { + cryptify::flow_stmt!(); + let c = a + b; + c +} + +fn helloooo(){ + println!("hi"); +} + +``` +# Output +```rs +fn main() { + cryptify::flow_stmt!(); + let b = cryptify::encrypt_string!("Hello World"); + println!("{}", b); + let args: Vec = env::args().collect(); + if args.len() < 2 { + eprintln!("Usage: {} ", args[0]); + return; + } + let filename = &args[1]; + let content = fs::read_to_string(filename).expect("Could not read file"); + let word_counts = count_words(&content); + for (word, count) in word_counts.iter() { + println!("{}: {}", word, count); + } +} +fn dummy() { + cryptify::flow_stmt!(); + let a = 1; + let b = 2; + let c = a + b; + println!("{}", c); +} +fn calc_sum(a: i32, b: i32) -> i32 { + cryptify::flow_stmt!(); + let c = a + b; + c +} +fn helloooo() { + println!("hi"); +} +``` +## Expanded Output +```rs +fn main() { + { + let _is_dummy_145 = true; + let _dummy_upper_bound = 100; + let _random_dummy_var = 1; + let mut _dummy_counter = 6i32; + let _dummy_increment = 2i32; + loop { + if _dummy_counter > _dummy_upper_bound { + break; + } + unsafe { + std::ptr::write_volatile( + &mut _dummy_counter, + _dummy_counter + _dummy_increment, + ); + } + } + }; + let b = cryptify::decrypt_string("0\u{b}\r\u{1f}\tFd\u{18}\u{11}\t\0"); + { + ::std::io::_print(format_args!("{0}\n", b)); + }; + let args: Vec = env::args().collect(); + if args.len() < 2 { + { + ::std::io::_eprint(format_args!("Usage: {0} \n", args[0])); + }; + return; + } + let filename = &args[1]; + let content = fs::read_to_string(filename).expect("Could not read file"); + let word_counts = count_words(&content); + for (word, count) in word_counts.iter() { + { + ::std::io::_print(format_args!("{0}: {1}\n", word, count)); + }; + } +} +fn dummy() { + { + let _is_dummy_145 = true; + let mut _dummy_counter = 4i32; + let _dummy_upper_bound = 100; + let _dummy_increment = 3i32; + loop { + if _dummy_counter > _dummy_upper_bound { + break; + } + unsafe { + std::ptr::write_volatile( + &mut _dummy_counter, + _dummy_counter + _dummy_increment, + ); + } + } + }; + let a = 1; + let b = 2; + let c = a + b; + { + ::std::io::_print(format_args!("{0}\n", c)); + }; +} +fn calc_sum(a: i32, b: i32) -> i32 { + { + let _is_dummy_145 = true; + let mut _dummy_counter = 8i32; + let _dummy_increment = 3i32; + let _extra_dummy_var = 4i32; + let _dummy_upper_bound = 100; + loop { + if _dummy_counter > _dummy_upper_bound { + break; + } + unsafe { + std::ptr::write_volatile( + &mut _dummy_counter, + _dummy_counter + _dummy_increment, + ); + } + } + }; + let c = a + b; + c +} +fn helloooo() { + { + ::std::io::_print(format_args!("hi\n")); + }; +} +``` +# License +rust-obfuscator is licensed under the MIT License - see the [LICENSE](https://github.com/dronavallipranav/rust-obfuscator/blob/main/LICENSE) file for details. diff --git a/auto_obfuscate/Cargo.toml b/auto_obfuscate/Cargo.toml index 1a9ced3..d4d16f4 100644 --- a/auto_obfuscate/Cargo.toml +++ b/auto_obfuscate/Cargo.toml @@ -1,9 +1,11 @@ [package] name = "rust-obfuscator" -version = "0.1.0" +version = "1.0.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[[bin]] +name = "rust-obfuscator" +path = "src/main.rs" [dependencies] syn = { version = "2.0", features = ["full", "visit-mut", "visit"] } @@ -12,4 +14,4 @@ proc-macro2 = "1.0" rand = "0.8.0" regex = "1.5.4" clap = "3.0" -labyrinth = { path = "../labyrinth" } \ No newline at end of file +cryptify = "3.1.0" \ No newline at end of file diff --git a/auto_obfuscate/README.md b/auto_obfuscate/README.md deleted file mode 100644 index 83618f1..0000000 --- a/auto_obfuscate/README.md +++ /dev/null @@ -1 +0,0 @@ -# rust-obfuscator \ No newline at end of file diff --git a/auto_obfuscate/src/flow.rs b/auto_obfuscate/src/flow.rs index 766996d..60fe3ed 100644 --- a/auto_obfuscate/src/flow.rs +++ b/auto_obfuscate/src/flow.rs @@ -113,7 +113,7 @@ impl VisitMut for FlowObfuscator { //if use macro enabled, use macro to expand to dummy loop if self.use_macro { let macro_call = syn::parse_quote! { - labyrinth::flow_stmt!(); + cryptify::flow_stmt!(); }; block.stmts.insert(0, macro_call); } else { diff --git a/auto_obfuscate/src/main.rs b/auto_obfuscate/src/main.rs index 0a634e4..8e3caef 100644 --- a/auto_obfuscate/src/main.rs +++ b/auto_obfuscate/src/main.rs @@ -10,9 +10,9 @@ use std::fs; fn main() { //default config let mut config = Config::default(); - let matches = App::new("Rust Obfuscator") + let matches = App::new("Rust Automatic Obfuscator") .version("1.0") - .author("Your Name") + .author("Pranav Dronavalli") .about("Obfuscates Rust source code") .arg( Arg::with_name("path") diff --git a/auto_obfuscate/src/string.rs b/auto_obfuscate/src/string.rs index 593ac42..7850a50 100644 --- a/auto_obfuscate/src/string.rs +++ b/auto_obfuscate/src/string.rs @@ -2,13 +2,14 @@ use syn::{ visit_mut::VisitMut, visit::Visit, parse_file, - parse2, parse_str, Expr, + ExprLit, LitStr, Lit, - Macro, File, + Local, + parse_quote, }; use quote::quote; use proc_macro2::{ TokenStream, TokenTree }; @@ -36,6 +37,7 @@ pub struct StringObfuscator { percentage: u8, encrypted_count: usize, strings_to_encrypt: usize, + num_strings_encrypted: usize, } impl StringObfuscator { @@ -45,8 +47,10 @@ impl StringObfuscator { percentage: config.percentage, encrypted_count: 0, strings_to_encrypt: 0, + num_strings_encrypted: 0, } } + #[allow(dead_code)] fn process_macro_tokens(&self, tokens: TokenStream) -> TokenStream { tokens .into_iter() @@ -61,7 +65,7 @@ impl StringObfuscator { if let Ok(lit_str) = parse_str::(&lit_str) { let macro_call: TokenStream = quote! { - labyrinth::encrypt_string!(#lit_str) + cryptify::encrypt_string!(#lit_str) }; return macro_call; } @@ -84,13 +88,10 @@ impl StringObfuscator { let ast = parse_file(code).expect("Failed to parse code"); let total_strings = count_string_literals(&ast); - println!("total strings: {}", total_strings); let strings_to_encrypt = ( ((self.percentage as f32) / 100.0) * (total_strings as f32) ).ceil() as usize; - println!("percentage: {}", self.percentage); - println!("Encrypting {} strings", strings_to_encrypt); self.encrypted_count = 0; self.strings_to_encrypt = strings_to_encrypt; @@ -103,43 +104,23 @@ impl StringObfuscator { impl VisitMut for StringObfuscator { //replace all string literals with call to obfuscation macro - fn visit_expr_mut(&mut self, expr: &mut Expr) { - if - !self.enabled || - (self.encrypted_count >= self.strings_to_encrypt && self.percentage != 100) - { - return; - } - if let Expr::Lit(expr_lit) = expr { - if let Lit::Str(_) = &expr_lit.lit { - //replace string literal with macro call - let macro_call = - quote! { - labyrinth::encrypt_string!(#expr_lit) - }; - self.encrypted_count += 1; - //replace expression to use macro call - *expr = parse2(macro_call).expect("Failed to parse macro call"); + fn visit_local_mut(&mut self, local: &mut Local) { + if let Some(local_init) = &mut local.init { + if self.num_strings_encrypted >= self.strings_to_encrypt { + return; } - } + self.num_strings_encrypted += 1; - syn::visit_mut::visit_expr_mut(self, expr); - } - fn visit_macro_mut(&mut self, mac: &mut Macro) { - if self.enabled == false { - return; - } - //check to see if macro is not obfuscation macro - if - mac.path.segments.len() == 2 && - mac.path.segments[0].ident == "labyrinth" && - mac.path.segments[1].ident == "encrypt_string" - { - return; + + //match on local variables that contain string literal assignments + if let Expr::Lit(ExprLit { lit: Lit::Str(lit_str), .. }) = &*local_init.expr { + let encrypted = quote! { cryptify::encrypt_string!(#lit_str) }; + let new_expr: Expr = parse_quote!(#encrypted); + *local_init.expr = *Box::new(new_expr); + } } - //encrypt string literal within macro - let new_tokens = self.process_macro_tokens(mac.tokens.clone()); - mac.tokens = new_tokens; + + syn::visit_mut::visit_local_mut(self, local); } } diff --git a/auto_obfuscate/src/string/string_tests.rs b/auto_obfuscate/src/string/string_tests.rs index 495a10c..d6cf9cb 100644 --- a/auto_obfuscate/src/string/string_tests.rs +++ b/auto_obfuscate/src/string/string_tests.rs @@ -1,23 +1,6 @@ #[cfg(test)] use super::*; -#[test] -fn test_replacement_in_macro() { - let code = r#" - fn main() { - println!("Hello, world!"); - } - "#; - let string_config = StringConfig::default(); - let mut string_obfuscator = StringObfuscator::new(string_config); - let obfuscated_code = string_obfuscator.obfuscate_strings(code); - assert_ne!(code, obfuscated_code); - assert!(obfuscated_code.contains("encrypt_string")); - - let parse_result = syn::parse_file(&obfuscated_code); - assert!(parse_result.is_ok(), "Modified code is not valid Rust code"); -} - #[test] fn test_replacement_in_expr() { let code = r#" @@ -36,22 +19,18 @@ fn test_replacement_in_expr() { } #[test] -fn test_replacement_in_nested_macro() { +fn test_no_macro() { let code = r#" - fn main() { - let num1 = 10; - let num2 = 20; - println!("Formatted: {}", format!("Num1: {}, Num2: {}", num1, num2)); - } -"#; - + fn main() { + println!("Hello, world!"); + let word_re = Regex::new(r"\b\w+\b").unwrap(); + } + "#; let string_config = StringConfig::default(); let mut string_obfuscator = StringObfuscator::new(string_config); let obfuscated_code = string_obfuscator.obfuscate_strings(code); - assert_ne!(code, obfuscated_code); - assert!(obfuscated_code.contains("encrypt_string")); - + assert!(!obfuscated_code.contains("encrypt_string")); let parse_result = syn::parse_file(&obfuscated_code); assert!(parse_result.is_ok(), "Modified code is not valid Rust code"); } @@ -61,7 +40,16 @@ fn test_percentage() { let code = r#" fn main() { - let a = "d"; + let a = "a"; + let b = "b"; + let c = "c"; + let d = "d"; + let e = "e"; + let f = "f"; + let g = "g"; + let h = "h"; + let i = "i"; + let j = "j"; println!("Hello"); println!("Hello"); println!("Hello"); @@ -76,7 +64,8 @@ fn test_percentage() { let mut string_obfuscator = StringObfuscator::new(string_config); let obfuscated_code = string_obfuscator.obfuscate_strings(code); assert_ne!(code, obfuscated_code); - assert!(obfuscated_code.contains("encrypt_string")); + assert!(obfuscated_code.contains("encrypt_string ! (\"h\")")); + assert!(obfuscated_code.contains("let i = \"i\"")); println!("{}", obfuscated_code); let parse_result = syn::parse_file(&obfuscated_code); diff --git a/cryptify/Cargo.toml b/cryptify/Cargo.toml new file mode 100644 index 0000000..faf116e --- /dev/null +++ b/cryptify/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "cryptify" +version = "3.1.0" +edition = "2021" +authors = ["Pranav Dronavalli "] +description = "A procedural macro library to obfuscate Rust code. Provides compile-time string encryption and random flow obfuscation." +license = "MIT" +repository = "https://github.com/dronavallipranav/rust-obfuscator/tree/main/labyrinth_macros" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +labyrinth_macros = "2.0.0" diff --git a/cryptify/README.md b/cryptify/README.md new file mode 100644 index 0000000..8cca009 --- /dev/null +++ b/cryptify/README.md @@ -0,0 +1,70 @@ +# cryptify + +`cryptify` is a procedural macro crate for compile-time rust obfuscation. It provides the user with string encryption and compile-time determined flow obfuscation and random variables which survive compile-time optimization. + + +[rust-obfuscator](https://github.com/dronavallipranav/rust-obfuscator) - Check out this auto obfuscator tool for easier usage and integration +## Features + +- **String Obfuscation**: Automatically encrypts string literals in your code at compile time, making them harder to read and understand. +- **Flow Obfuscation**: Introduces dummy loops and random variables into control flows, enhancing the overall obfuscation of the logic. + +# Usage + +## Bring macro into scope +```rs +use cryptify; + +fn main(){ + let decrypted = cryptify::encrypt_string("Hello, World!"); + println!(decrypted); + println!("{}", cryptify::encrypt_string!("formatted!")); +} +``` + +Set the **CRYPTIFY_KEY** environment variable for custom encryption otherwise it defaults to defined fixed key + +## Output +``` +Hello World! +formatted! +``` +## Example of expanded Flow_Stmt! + +```rs + { + let _is_dummy_145 = true; + let _dummy_upper_bound = 100; + let _dummy_increment = 1i32; + let mut _dummy_counter = 10i32; + let _extra_dummy_var = 2i32; + loop { + if _dummy_counter > _dummy_upper_bound { + break; + } + unsafe { + std::ptr::write_volatile( + &mut _dummy_counter, + _dummy_counter + _dummy_increment, + ); + } + } + }; + match (&1, &1) { + (left_val, right_val) => { + if !(*left_val == *right_val) { + let kind = ::core::panicking::AssertKind::Eq; + ::core::panicking::assert_failed( + kind, + &*left_val, + &*right_val, + ::core::option::Option::None, + ); + } + } + }; + +``` + +# License +cryptify is licensed under the MIT License - see the [LICENSE](https://github.com/dronavallipranav/rust-obfuscator/blob/main/LICENSE) file for details. diff --git a/cryptify/src/lib.rs b/cryptify/src/lib.rs new file mode 100644 index 0000000..517343a --- /dev/null +++ b/cryptify/src/lib.rs @@ -0,0 +1,16 @@ +//re-export proc macro crate +pub use labyrinth_macros::*; + +/// A helper decryption function meant to decrypt encrypted strings at runtime +/// +/// # Parameters +/// - `input`: The encrypted string literal +/// +pub fn decrypt_string(encrypted: &str) -> String { + let key = std::env::var("CRYPTIFY_KEY").unwrap_or_else(|_| "xnasff3wcedj".to_string()); + encrypted + .chars() + .zip(key.chars().cycle()) + .map(|(encrypted_char, key_char)| ((encrypted_char as u8) ^ (key_char as u8)) as char) + .collect() +} diff --git a/labyrinth/tests/macro_tests.rs b/cryptify/tests/macro_tests.rs similarity index 58% rename from labyrinth/tests/macro_tests.rs rename to cryptify/tests/macro_tests.rs index d14d6d1..cf31103 100644 --- a/labyrinth/tests/macro_tests.rs +++ b/cryptify/tests/macro_tests.rs @@ -1,12 +1,13 @@ +//integration tests testing whole crate #[test] fn test_encrypt_macro() { - let decrypted = labyrinth::encrypt_string!("Hello World"); + let decrypted = cryptify::encrypt_string!("Hello World"); assert_eq!("Hello World", decrypted); } #[test] fn test_flow_macro() { //manually test for now with cargo expand - labyrinth::flow_stmt!(); + cryptify::flow_stmt!(); assert_eq!(1, 1); } diff --git a/labyrinth/Cargo.toml b/labyrinth/Cargo.toml deleted file mode 100644 index d5c3300..0000000 --- a/labyrinth/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "labyrinth" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -labyrinth_macros = { path = "../labyrinth_macros" } \ No newline at end of file diff --git a/labyrinth/src/lib.rs b/labyrinth/src/lib.rs deleted file mode 100644 index 687ca6e..0000000 --- a/labyrinth/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub use labyrinth_macros::*; -//helper function to decrypt string at runtime -pub fn decrypt_string(encrypted: &str) -> String { - let key = std::env::var("LABYRINTH_KEY").unwrap_or_else(|_| "xnasff3wcedj".to_string()); - encrypted - .chars() - .zip(key.chars().cycle()) - .map(|(encrypted_char, key_char)| ((encrypted_char as u8) ^ (key_char as u8)) as char) - .collect() -} diff --git a/labyrinth_macros/Cargo.toml b/labyrinth_macros/Cargo.toml index 038908e..1804eb2 100644 --- a/labyrinth_macros/Cargo.toml +++ b/labyrinth_macros/Cargo.toml @@ -1,7 +1,11 @@ [package] name = "labyrinth_macros" -version = "0.1.0" +version = "3.0.0" edition = "2021" +authors = ["Pranav Dronavalli "] +description = "A procedural macro crate for the cryptify crate meant to provide obfuscation through compile time string encryption. not meant to be used standalone" +license = "MIT" +repository = "https://github.com/dronavallipranav/rust-obfuscator/tree/main/labyrinth_macros" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] diff --git a/labyrinth_macros/README.md b/labyrinth_macros/README.md new file mode 100644 index 0000000..a441f5e --- /dev/null +++ b/labyrinth_macros/README.md @@ -0,0 +1,11 @@ +# labyrinth_macros + +`labyrinth_macros` is a procedural macro crate designed to complement the `cryptify` super crate. It provides compile-time string and control flow obfuscation capabilities, aimed at enhancing the security and complexity of Rust code. Not meant to be used standalone, necessary obfuscation features are in the super crate `cryptify` + +## Features + +- **String Obfuscation**: Automatically encrypts string literals in your code at compile time, making them harder to read and understand. +- **Flow Obfuscation**: Introduces dummy loops and random variables into control flows, enhancing the overall obfuscation of the logic. + +# License +labyrinth_macros is licensed under the MIT License - see the [LICENSE](https://github.com/dronavallipranav/rust-obfuscator/blob/main/LICENSE) file for details. \ No newline at end of file diff --git a/labyrinth_macros/src/lib.rs b/labyrinth_macros/src/lib.rs index 619dafb..1c9efd5 100644 --- a/labyrinth_macros/src/lib.rs +++ b/labyrinth_macros/src/lib.rs @@ -1,3 +1,7 @@ +//! `labyrinth_macros` crate provides procedural macros for compile-time obfuscation. NOT MEANT TO BE USED STANDALONE. +//! +//! This crate includes macros like `encrypt_string` and `flow_stmt` which are used +//! to enhance the security of Rust code by obfuscating strings and control flows. use proc_macro::TokenStream; use quote::quote; use syn::*; @@ -5,6 +9,11 @@ use std::env; use rand::Rng; use rand::seq::SliceRandom; +/// A procedural macro that adds a compile-time randomly generated loop and variables. +/// +/// # Note +/// The unsafe operation is meant to help the dummy loop survive compiler optimizations. only writes to dummy variable +/// #[proc_macro] pub fn flow_stmt(_: TokenStream) -> TokenStream { let mut rng = rand::thread_rng(); @@ -52,19 +61,23 @@ pub fn flow_stmt(_: TokenStream) -> TokenStream { TokenStream::from(generated_loop) } - +/// A procedural macro that encrypts a string literal at compile time. +/// +/// # Parameters +/// - `input`: The string literal to be encrypted. +/// #[proc_macro] pub fn encrypt_string(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as LitStr); let string = input.value(); //set key to seeded env key or default - let key = env::var("LABYRINTH_KEY").unwrap_or_else(|_| "xnasff3wcedj".to_string()); + let key = env::var("CRYPTIFY_KEY").unwrap_or_else(|_| "xnasff3wcedj".to_string()); let encrypted_string = xor_cipher(&string, &key); let output = quote! { - labyrinth::decrypt_string(#encrypted_string) + cryptify::decrypt_string(#encrypted_string).as_ref() }; TokenStream::from(output) @@ -81,7 +94,7 @@ fn xor_cipher(input: &str, key: &str) -> String { //for self-contained tests #[allow(dead_code)] fn decrypt_string(encrypted: &str) -> String { - let key = std::env::var("LABYRINTH_KEY").unwrap_or_else(|_| "xnasff3wcedj".to_string()); + let key = std::env::var("CRYPTIFY_KEY").unwrap_or_else(|_| "xnasff3wcedj".to_string()); encrypted .chars() .zip(key.chars().cycle()) @@ -89,6 +102,7 @@ fn decrypt_string(encrypted: &str) -> String { .collect() } +//unit tests testing decryption logic #[cfg(test)] mod tests { use super::*; @@ -107,9 +121,9 @@ mod tests { #[test] fn test_xor_cipher_and_decrypt_customkey() { //set key - std::env::set_var("LABYRINTH_KEY", "testkey"); + std::env::set_var("CRYPTIFY_KEY", "testkey"); //test loc from encrypt_string meant to extract key - let key = env::var("LABYRINTH_KEY").unwrap_or_else(|_| "xnasff3wcedj".to_string()); + let key = env::var("CRYPTIFY_KEY").unwrap_or_else(|_| "xnasff3wcedj".to_string()); assert_eq!(key, "testkey"); let test_strings = ["Hello", "World", "1234", "!@#$%^&*()"];