cargo-mate 1.8.0

Rust development companion that enhances cargo with intelligent workflows, state management, performance optimization, and comprehensive project monitoring.
Documentation
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(&current_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(())
}