myph-v2~ rust shellcode loader with evasive capabilities |
| git clone https://github.com/djnnvx/myph-v2.git |
| log | files | refs | archive | README |
validation.rs (6146B)
1 use super::capabilities::{get_technique_metadata, Capability}; 2 3 #[derive(Debug, Clone)] 4 pub struct ValidationError { 5 pub message: String, 6 pub suggestion: Option<String>, 7 } 8 9 impl ValidationError { 10 pub fn new(message: String, suggestion: Option<String>) -> Self { 11 Self { 12 message, 13 suggestion, 14 } 15 } 16 } 17 18 pub struct TechniqueValidator; 19 20 impl TechniqueValidator { 21 pub fn validate( 22 technique_name: &str, 23 with_dynamic_resolver: bool, 24 requires_process_param: bool, 25 ) -> Result<(), Vec<ValidationError>> { 26 let mut errors = Vec::new(); 27 28 let meta = match get_technique_metadata(technique_name) { 29 Some(m) => m, 30 None => { 31 errors.push(ValidationError::new( 32 format!("Unknown technique: '{}'", technique_name), 33 Some("Use --help to see available techniques".to_string()), 34 )); 35 return Err(errors); 36 } 37 }; 38 39 if with_dynamic_resolver && !meta.supports_dynamic_resolver() { 40 errors.push(ValidationError::new( 41 format!( 42 "Technique '{}' does not support dynamic function resolver", 43 technique_name 44 ), 45 Some( 46 "Remove --with-dynamic-function-resolver flag or choose a different technique" 47 .to_string(), 48 ), 49 )); 50 } 51 52 if requires_process_param && !meta.requires_process() { 53 errors.push(ValidationError::new( 54 format!( 55 "Technique '{}' is for local execution only and does not use the --process parameter", 56 technique_name 57 ), 58 Some("Remove --process flag or use a process injection technique (crt, crtx, process-hollowing, nt-create-thread-ex, thread-hijacking, early-bird)".to_string()), 59 )); 60 } 61 62 if errors.is_empty() { 63 Ok(()) 64 } else { 65 Err(errors) 66 } 67 } 68 69 pub fn display_technique_info(technique_name: &str) -> Option<String> { 70 let meta = get_technique_metadata(technique_name)?; 71 let mut output = String::new(); 72 73 output.push_str(&format!("Technique: {}\n", meta.name)); 74 output.push_str(&format!("Description: {}\n", meta.description)); 75 output.push_str(&format!( 76 "Detection Difficulty: {}\n", 77 meta.detection_difficulty.as_str() 78 )); 79 output.push_str("\nCapabilities:\n"); 80 81 for cap in &meta.capabilities { 82 output.push_str(&format!(" - {}\n", cap.description())); 83 } 84 85 if meta.has_capability(Capability::RequiresAdmin) { 86 output.push_str("\n[!] WARNING: This technique requires administrator privileges\n"); 87 } 88 89 Some(output) 90 } 91 92 pub fn suggest_compatible_techniques(with_dynamic_resolver: bool) -> Vec<String> { 93 let all_techniques = super::capabilities::list_all_techniques(); 94 all_techniques 95 .into_iter() 96 .filter(|meta| { 97 if with_dynamic_resolver { 98 meta.supports_dynamic_resolver() 99 } else { 100 true 101 } 102 }) 103 .map(|meta| meta.name.to_string()) 104 .collect() 105 } 106 } 107 108 #[cfg(test)] 109 mod tests { 110 use super::*; 111 112 #[test] 113 fn test_validate_crt_with_process() { 114 let result = TechniqueValidator::validate("crt", false, true); 115 assert!(result.is_ok()); 116 } 117 118 #[test] 119 fn test_validate_crt_without_process() { 120 // CRT without process parameter should now pass since process param is auto-generated 121 let result = TechniqueValidator::validate("crt", false, false); 122 assert!(result.is_ok()); 123 } 124 125 #[test] 126 fn test_validate_create_fiber_without_process() { 127 let result = TechniqueValidator::validate("create-fiber", false, false); 128 assert!(result.is_ok()); 129 } 130 131 #[test] 132 fn test_validate_create_fiber_with_process() { 133 let result = TechniqueValidator::validate("create-fiber", false, true); 134 assert!(result.is_err()); 135 let errors = result.unwrap_err(); 136 assert_eq!(errors.len(), 1); 137 assert!(errors[0].message.contains("local execution only")); 138 } 139 140 #[test] 141 fn test_validate_unknown_technique() { 142 let result = TechniqueValidator::validate("unknown-tech", false, false); 143 assert!(result.is_err()); 144 let errors = result.unwrap_err(); 145 assert_eq!(errors.len(), 1); 146 assert!(errors[0].message.contains("Unknown technique")); 147 } 148 149 #[test] 150 fn test_validate_with_dynamic_resolver() { 151 let result = TechniqueValidator::validate("crt", true, true); 152 assert!(result.is_ok()); 153 } 154 155 #[test] 156 fn test_display_technique_info() { 157 let info = TechniqueValidator::display_technique_info("crt"); 158 assert!(info.is_some()); 159 let info_str = info.unwrap(); 160 assert!(info_str.contains("crt")); 161 assert!(info_str.contains("CreateRemoteThread")); 162 } 163 164 #[test] 165 fn test_display_technique_info_fairy_law() { 166 let info = TechniqueValidator::display_technique_info("fairy-law"); 167 assert!(info.is_some()); 168 let info_str = info.unwrap(); 169 assert!(info_str.contains("fairy-law")); 170 assert!(info_str.contains("WARNING")); 171 assert!(info_str.contains("administrator")); 172 } 173 174 #[test] 175 fn test_display_technique_info_unknown() { 176 let info = TechniqueValidator::display_technique_info("unknown"); 177 assert!(info.is_none()); 178 } 179 180 #[test] 181 fn test_suggest_compatible_techniques_all() { 182 let techniques = TechniqueValidator::suggest_compatible_techniques(false); 183 assert_eq!(techniques.len(), 17); 184 } 185 186 #[test] 187 fn test_suggest_compatible_techniques_with_dynamic_resolver() { 188 let techniques = TechniqueValidator::suggest_compatible_techniques(true); 189 assert_eq!(techniques.len(), 17); 190 } 191 }