use anyhow::{Context, Result};
use std::fs;
use sha2::{Sha256, Digest};
use crate::log::Log;
fn create_self_protected_binary(
input_path: &str,
output_path: &str,
key: &str,
) -> Result<()> {
let binary_data = fs::read(input_path)
.with_context(|| format!("Failed to read binary: {}", input_path))?;
let mut hasher = Sha256::new();
hasher.update(key.as_bytes());
let key_hash = hasher.finalize();
let encrypted_data: Vec<u8> = binary_data
.iter()
.enumerate()
.map(|(i, &byte)| byte ^ key_hash[i % key_hash.len()])
.collect();
let loader_code = format!(
r#"
// Self-Protected Binary - Auto-generated by cargo-mate
// This binary decrypts itself and runs without external dependencies
use std::{{env, fs, process}};
use std::os::unix::fs::PermissionsExt;
use sha2::{{Sha256, Digest}};
fn main() -> Result<(), Box<dyn std::error::Error>> {{
// Get current executable path
let current_exe = env::current_exe()?;
// Read the entire executable
let exe_data = fs::read(¤t_exe)?;
// Find the encrypted payload marker
let marker = b"ENCRYPTED_PAYLOAD_STARTS_HERE";
let marker_pos = exe_data.windows(marker.len())
.position(|window| window == marker)
.ok_or("Encrypted payload not found")?;
// Extract encrypted data (everything after marker)
let encrypted_data = &exe_data[marker_pos + marker.len()..];
// Recreate the same key hash
let mut hasher = Sha256::new();
hasher.update(b"{key}");
let key_hash = hasher.finalize();
// XOR decrypt
let decrypted_data: Vec<u8> = encrypted_data
.iter()
.enumerate()
.map(|(i, &byte)| byte ^ key_hash[i % key_hash.len()])
.collect();
// Create temporary file for decrypted binary
let temp_dir = env::temp_dir();
let temp_path = temp_dir.join("cargo_mate_protected_bin");
// Write decrypted binary
fs::write(&temp_path, decrypted_data)?;
// Make executable on Unix systems
#[cfg(unix)]
{{
let mut perms = fs::metadata(&temp_path)?.permissions();
perms.set_mode(0o755);
fs::set_permissions(&temp_path, perms)?;
}}
// Get command line arguments (skip program name)
let args: Vec<String> = env::args().skip(1).collect();
// Execute decrypted binary with arguments
let status = process::Command::new(&temp_path)
.args(&args)
.status()?;
// Clean up temporary file
let _ = fs::remove_file(&temp_path);
// Exit with the same status as the executed program
if status.success() {{
Ok(())
}} else {{
std::process::exit(status.code().unwrap_or(1));
}}
}}
"#,
key = key
);
let temp_dir = std::env::temp_dir();
let temp_source = temp_dir.join("protected_loader.rs");
fs::write(&temp_source, &loader_code)?;
let temp_binary = temp_dir.join("protected_loader");
let compile_result = std::process::Command::new("rustc")
.args(
&[
"--extern",
"sha2",
"-L",
"dependency=target/release/deps",
&temp_source.to_string_lossy(),
"-o",
&temp_binary.to_string_lossy(),
],
)
.status();
if compile_result.is_err() || !compile_result.unwrap().success() {
let log = Log::new();
log.log(
"Failed to compile with rustc, trying cargo...",
vec!["create_self_protected_binary".to_string(), "error".to_string()],
)?;
let cargo_toml_content = format!(
r#"
[package]
name = "protected-loader"
version = "0.1.0"
edition = "2021"
[dependencies]
sha2 = "0.10"
[[bin]]
name = "loader"
path = "src/main.rs"
"#
);
let cargo_dir = temp_dir.join("protected_loader_cargo");
fs::create_dir_all(&cargo_dir)?;
fs::write(cargo_dir.join("Cargo.toml"), cargo_toml_content)?;
fs::create_dir_all(cargo_dir.join("src"))?;
fs::write(cargo_dir.join("src/main.rs"), loader_code.clone())?;
let build_result = std::process::Command::new("cargo")
.args(&["build", "--release", "--bin", "loader"])
.current_dir(&cargo_dir)
.status();
if build_result.is_err() || !build_result.unwrap().success() {
let log = Log::new();
log.log(
"Failed to compile loader",
vec!["create_self_protected_binary".to_string(), "error".to_string()],
)?;
return Err(anyhow::anyhow!("Compilation failed"));
}
let cargo_binary = cargo_dir.join("target/release/loader");
fs::copy(&cargo_binary, &temp_binary)?;
}
let _ = fs::remove_file(&temp_source);
let mut final_binary = fs::read(&temp_binary)?;
final_binary.extend_from_slice(b"ENCRYPTED_PAYLOAD_STARTS_HERE");
final_binary.extend_from_slice(&encrypted_data);
fs::write(output_path, final_binary)?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut perms = fs::metadata(output_path)?.permissions();
perms.set_mode(0o755);
fs::set_permissions(output_path, perms)?;
}
let _ = fs::remove_file(&temp_binary);
Ok(())
}