Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

function name encryption #16

Merged
merged 2 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
77 changes: 63 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,23 @@ A CLI application to obfuscate ELF file(s)
Usage: cattleya [OPTIONS]

Options:
-i, --input <INPUT> input file name [default: ]
-o, --output <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 <SECTION> nullify section in the ELF [default: ]
-r, --recursive <RECURSIVE> recursive [default: ]
-g, --got perform GOT overwrite
--got-l <GOT_L> GOT overwrite target library function name [default: ]
--got-f <GOT_F> GOT overwrite target function name [default: ]
-h, --help Print help
-V, --version Print version
-i, --input <INPUT> input file name [default: ]
-o, --output <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 <SECTION> nullify section in the ELF [default: ]
-r, --recursive <RECURSIVE> recursive [default: ]
-g, --got perform GOT overwrite
--got-l <GOT_L> GOT overwrite target library function name [default: ]
--got-f <GOT_F> GOT overwrite target function name [default: ]
--encrypt encrypt function name with the given key
--encrypt-f <ENCRYPT_F> encryption target function name [default: ]
--encrypt-key <ENCRYPT_KEY> encryption key [default: ]
-h, --help Print help
-V, --version Print version
```

Both input and recursive options cannot be empty.
Expand Down Expand Up @@ -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 <main>:
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 <fib>
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 <fib>
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 <fib>
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
```
Expand Down
19 changes: 19 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<()> {
Expand Down Expand Up @@ -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(())
Expand Down
46 changes: 46 additions & 0 deletions src/obfus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}
}
Loading