From cf07b1032dedd821be799014b88c7ad4e7172b26 Mon Sep 17 00:00:00 2001 From: lapla-cogito Date: Thu, 22 Aug 2024 22:43:09 +0900 Subject: [PATCH 1/2] add function name encrypt --- Cargo.lock | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 + src/main.rs | 19 ++++++++ src/obfus.rs | 46 ++++++++++++++++++ 4 files changed, 196 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index c5dabd2..ed07d6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,16 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aes-stream" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e2533cd0b6abfc7687517ba71d820f57945de2aeb7ca6cadfde8a53765328d" +dependencies = [ + "rand 0.3.23", + "rust-crypto", +] + [[package]] name = "anstream" version = "0.6.11" @@ -60,9 +70,11 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" name = "cattleya" version = "0.1.0" dependencies = [ + "aes-stream", "anyhow", "clap", "memmap2", + "rust-crypto", "thiserror", ] @@ -112,6 +124,18 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" + [[package]] name = "heck" version = "0.5.0" @@ -151,6 +175,72 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +dependencies = [ + "libc", + "rand 0.4.6", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rust-crypto" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" +dependencies = [ + "gcc", + "libc", + "rand 0.3.23", + "rustc-serialize", + "time", +] + +[[package]] +name = "rustc-serialize" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe834bc780604f4674073badbad26d7219cadfb4a2275802db12cbae17498401" + [[package]] name = "strsim" version = "0.11.0" @@ -188,6 +278,17 @@ dependencies = [ "syn", ] +[[package]] +name = "time" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi", + "winapi", +] + [[package]] name = "unicode-ident" version = "1.0.12" @@ -200,6 +301,34 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-sys" version = "0.52.0" diff --git a/Cargo.toml b/Cargo.toml index 398b547..64ae24d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +aes-stream = "0.2.1" anyhow = "1.0.86" clap = { version = "4.5.3", features = ["derive"] } memmap2 = "0.9.4" +rust-crypto = "0.2.36" thiserror = "1.0.63" diff --git a/src/main.rs b/src/main.rs index 5ac4e46..049d27b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,6 +56,16 @@ struct Args { got_l: String, #[arg(long, help = "GOT overwrite target function name", default_value = "")] got_f: String, + #[arg( + long, + help = "encrypt function name with the given key", + default_value = "false" + )] + encrypt: bool, + #[arg(long, help = "encryption target function name", default_value = "")] + encrypt_f: String, + #[arg(long, help = "encryption key", default_value = "")] + encrypt_key: String, } fn main() -> crate::error::Result<()> { @@ -140,6 +150,15 @@ fn exec_obfus(input_path: &str, output_path: &str, args: &Args) -> crate::error: obfuscator.got_overwrite(&args.got_l, &args.got_f)?; } + if args.encrypt { + if args.encrypt_f.is_empty() || args.encrypt_key.is_empty() { + return Err(crate::error::Error::InvalidOption( + "target function name and encryption key is required", + )); + } + + obfuscator.encrypt_function_name(&args.encrypt_f, &args.encrypt_key)?; + } println!("obfuscation done!"); Ok(()) diff --git a/src/obfus.rs b/src/obfus.rs index 8747e3c..35842bb 100644 --- a/src/obfus.rs +++ b/src/obfus.rs @@ -321,4 +321,50 @@ impl Obfuscator { Err(crate::error::Error::Obfuscation("failed to overwrite GOT")) } + + pub fn encrypt_function_name(&mut self, function: &str, key: &str) -> crate::error::Result<()> { + let mut key_bytes = [0; 32]; + if key.len() > 32 { + return Err(crate::error::Error::InvalidOption( + "key length must be less than 32", + )); + } + for (i, byte) in key.bytes().enumerate() { + key_bytes[i] = byte; + } + let encryptor = crypto::aessafe::AesSafe256Encryptor::new(&key_bytes); + + let tmp_file = std::fs::OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open("/tmp/cattleya_encrypted_function_name") + .map_err(crate::error::Error::CreateFile)?; + let mut writer = aesstream::AesWriter::new(tmp_file, encryptor).unwrap(); + writer + .write_all(function.as_bytes()) + .map_err(crate::error::Error::Io)?; + + let mut encrypted_function_name = Vec::new(); + let mut tmp_file = std::fs::File::open("/tmp/encrypted_function_name") + .map_err(crate::error::Error::OpenFile)?; + tmp_file + .read_to_end(&mut encrypted_function_name) + .map_err(crate::error::Error::Io)?; + + let idx = self.string_table.find(function).unwrap(); + let (section_addr, _, _, _) = self.get_section(".strtab").unwrap(); + if function.len() >= 16 { + self.output[section_addr + idx..section_addr + idx + function.len()] + .copy_from_slice(&encrypted_function_name); + } else { + let mut encrypted_function_name = encrypted_function_name; + encrypted_function_name.resize(function.len(), 0); + self.output[section_addr + idx..section_addr + idx + function.len()] + .copy_from_slice(&encrypted_function_name); + } + + Ok(()) + } } From f2255d264becdb9f6602ca34503c4794d0c6046e Mon Sep 17 00:00:00 2001 From: lapla-cogito Date: Thu, 22 Aug 2024 22:50:04 +0900 Subject: [PATCH 2/2] update README --- README.md | 77 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 34517e7..90705f2 100644 --- a/README.md +++ b/README.md @@ -9,20 +9,23 @@ A CLI application to obfuscate ELF file(s) Usage: cattleya [OPTIONS] Options: - -i, --input input file name [default: ] - -o, --output output file name [default: ] - -c, --class change architecture class in the ELF - -e, --endian change endian in the ELF - -s, --sechdr nullify section header in the ELF - --symbol nullify symbols in the ELF - --comment nullify comment section in the ELF - --section
nullify section in the ELF [default: ] - -r, --recursive recursive [default: ] - -g, --got perform GOT overwrite - --got-l GOT overwrite target library function name [default: ] - --got-f GOT overwrite target function name [default: ] - -h, --help Print help - -V, --version Print version + -i, --input input file name [default: ] + -o, --output output file name [default: ] + -c, --class change architecture class in the ELF + -e, --endian change endian in the ELF + -s, --sechdr nullify section header in the ELF + --symbol nullify symbols in the ELF + --comment nullify comment section in the ELF + --section
nullify section in the ELF [default: ] + -r, --recursive recursive [default: ] + -g, --got perform GOT overwrite + --got-l GOT overwrite target library function name [default: ] + --got-f GOT overwrite target function name [default: ] + --encrypt encrypt function name with the given key + --encrypt-f encryption target function name [default: ] + --encrypt-key encryption key [default: ] + -h, --help Print help + -V, --version Print version ``` Both input and recursive options cannot be empty. @@ -143,12 +146,58 @@ Hex dump of section '.comment': 0x00000020 00000000 00000000 000000 ........... ``` +## function name encryption + +Encrypts the name of a specific function with AES 256bit using the given key: + +``` +$ cargo run -- -i bin/test_64bit --encrypt --encrypt-f fac --encrypt-key foo -o bin/res_enc +start obfuscating bin/test_64bit... +obfuscation done! +$ ./bin/res_enc +fac(1)=1 +fib(1)=1 +fac(5)=120 +fib(5)=5 +fac(10)=3628800 +fib(10)=55 +$ objdump -d bin/res_enc +... +000000000000120c
: + 120c: f3 0f 1e fa endbr64 + 1210: 55 push %rbp + 1211: 48 89 e5 mov %rsp,%rbp + 1214: 48 83 ec 10 sub $0x10,%rsp + 1218: 89 7d fc mov %edi,-0x4(%rbp) + 121b: 48 89 75 f0 mov %rsi,-0x10(%rbp) + 121f: bf 01 00 00 00 mov $0x1,%edi + 1224: e8 20 ff ff ff call 1149 <�0,> + 1229: bf 01 00 00 00 mov $0x1,%edi + 122e: e8 6a ff ff ff call 119d + 1233: bf 05 00 00 00 mov $0x5,%edi + 1238: e8 0c ff ff ff call 1149 <�0,> + 123d: bf 05 00 00 00 mov $0x5,%edi + 1242: e8 56 ff ff ff call 119d + 1247: bf 0a 00 00 00 mov $0xa,%edi + 124c: e8 f8 fe ff ff call 1149 <�0,> + 1251: bf 0a 00 00 00 mov $0xa,%edi + 1256: e8 42 ff ff ff call 119d + 125b: b8 00 00 00 00 mov $0x0,%eax + 1260: c9 leave + 1261: c3 ret +... +``` + +Function name "fac" is encrypted. + ## GOT overwrite Overwrites the GOT section with a specified value ``` $ cattleya -i bin/got --got --got-l system --got-f secret -o bin/res_got +start obfuscating bin/got... +obfuscation done! $ ./bin/res_got secret function called ```