myph-v2~ rust shellcode loader with evasive capabilities |
| git clone https://github.com/djnnvx/myph-v2.git |
| log | files | refs | archive | README |
code_validator.rs (7912B)
1 use std::collections::HashSet; 2 3 #[derive(Debug, Clone, PartialEq, Eq)] 4 pub enum ValidationError { 5 UnbalancedBraces { open: usize, close: usize }, 6 UnbalancedParentheses { open: usize, close: usize }, 7 MissingExternBlock, 8 MissingUnsafeBlock, 9 InvalidFunctionSignature(String), 10 MissingRequiredImport(String), 11 DuplicateExternDeclaration(String), 12 } 13 14 impl std::fmt::Display for ValidationError { 15 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 16 match self { 17 ValidationError::UnbalancedBraces { open, close } => { 18 write!(f, "Unbalanced braces: {} open, {} close", open, close) 19 } 20 ValidationError::UnbalancedParentheses { open, close } => { 21 write!(f, "Unbalanced parentheses: {} open, {} close", open, close) 22 } 23 ValidationError::MissingExternBlock => { 24 write!(f, "Missing extern block for Windows API functions") 25 } 26 ValidationError::MissingUnsafeBlock => { 27 write!(f, "Windows API calls must be in unsafe block") 28 } 29 ValidationError::InvalidFunctionSignature(sig) => { 30 write!(f, "Invalid function signature: {}", sig) 31 } 32 ValidationError::MissingRequiredImport(import) => { 33 write!(f, "Missing required import: {}", import) 34 } 35 ValidationError::DuplicateExternDeclaration(name) => { 36 write!(f, "Duplicate extern declaration: {}", name) 37 } 38 } 39 } 40 } 41 42 pub struct CodeValidator; 43 44 impl CodeValidator { 45 pub fn validate_technique_code(code: &str) -> Result<(), Vec<ValidationError>> { 46 let mut errors = Vec::new(); 47 48 if let Err(e) = Self::check_balanced_braces(code) { 49 errors.push(e); 50 } 51 52 if let Err(e) = Self::check_balanced_parentheses(code) { 53 errors.push(e); 54 } 55 56 if let Some(e) = Self::check_unsafe_usage(code) { 57 errors.push(e); 58 } 59 60 if let Some(e) = Self::check_duplicate_externs(code) { 61 errors.push(e); 62 } 63 64 if errors.is_empty() { 65 Ok(()) 66 } else { 67 Err(errors) 68 } 69 } 70 71 fn check_balanced_braces(code: &str) -> Result<(), ValidationError> { 72 let open = code.matches('{').count(); 73 let close = code.matches('}').count(); 74 if open != close { 75 Err(ValidationError::UnbalancedBraces { open, close }) 76 } else { 77 Ok(()) 78 } 79 } 80 81 fn check_balanced_parentheses(code: &str) -> Result<(), ValidationError> { 82 let open = code.matches('(').count(); 83 let close = code.matches(')').count(); 84 if open != close { 85 Err(ValidationError::UnbalancedParentheses { open, close }) 86 } else { 87 Ok(()) 88 } 89 } 90 91 fn check_unsafe_usage(code: &str) -> Option<ValidationError> { 92 let has_windows_api_calls = code.contains("VirtualAlloc") 93 || code.contains("VirtualProtect") 94 || code.contains("CreateProcess") 95 || code.contains("WriteProcessMemory") 96 || code.contains("QueueUserAPC"); 97 98 let has_unsafe_block = code.contains("unsafe"); 99 100 if has_windows_api_calls && !has_unsafe_block { 101 Some(ValidationError::MissingUnsafeBlock) 102 } else { 103 None 104 } 105 } 106 107 fn check_duplicate_externs(code: &str) -> Option<ValidationError> { 108 let mut extern_functions = HashSet::new(); 109 let lines: Vec<&str> = code.lines().collect(); 110 let mut in_extern_block = false; 111 112 for line in lines { 113 let trimmed = line.trim(); 114 115 if trimmed.starts_with("extern") && trimmed.contains('{') { 116 in_extern_block = true; 117 continue; 118 } 119 120 if in_extern_block && trimmed == "}" { 121 in_extern_block = false; 122 continue; 123 } 124 125 if in_extern_block && trimmed.starts_with("fn ") { 126 let fn_name = trimmed 127 .trim_start_matches("fn ") 128 .split('(') 129 .next() 130 .unwrap_or(""); 131 if !fn_name.is_empty() && !extern_functions.insert(fn_name.to_string()) { 132 return Some(ValidationError::DuplicateExternDeclaration( 133 fn_name.to_string(), 134 )); 135 } 136 } 137 } 138 None 139 } 140 141 pub fn validate_with_context( 142 code: &str, 143 context: &str, 144 ) -> Result<(), Vec<(String, ValidationError)>> { 145 Self::validate_technique_code(code).map_err(|errors| { 146 errors 147 .into_iter() 148 .map(|e| (context.to_string(), e)) 149 .collect() 150 }) 151 } 152 } 153 154 #[cfg(test)] 155 mod tests { 156 use super::*; 157 158 #[test] 159 fn test_valid_code_passes() { 160 let code = r#" 161 unsafe { 162 let ptr = VirtualAlloc(ptr::null_mut(), 1024, MEM_COMMIT, PAGE_READWRITE); 163 } 164 "#; 165 assert!(CodeValidator::validate_technique_code(code).is_ok()); 166 } 167 168 #[test] 169 fn test_unbalanced_braces_detected() { 170 let code = r#" 171 unsafe { 172 let ptr = VirtualAlloc(ptr::null_mut(), 1024, MEM_COMMIT, PAGE_READWRITE); 173 "#; 174 let result = CodeValidator::validate_technique_code(code); 175 assert!(result.is_err()); 176 let errors = result.unwrap_err(); 177 assert!(matches!( 178 errors[0], 179 ValidationError::UnbalancedBraces { .. } 180 )); 181 } 182 183 #[test] 184 fn test_unbalanced_parentheses_detected() { 185 let code = r#" 186 unsafe { 187 let ptr = VirtualAlloc(ptr::null_mut(), 1024, MEM_COMMIT, PAGE_READWRITE; 188 } 189 "#; 190 let result = CodeValidator::validate_technique_code(code); 191 assert!(result.is_err()); 192 let errors = result.unwrap_err(); 193 assert!(matches!( 194 errors[0], 195 ValidationError::UnbalancedParentheses { .. } 196 )); 197 } 198 199 #[test] 200 fn test_missing_unsafe_block_detected() { 201 let code = r#" 202 { 203 let ptr = VirtualAlloc(ptr::null_mut(), 1024, MEM_COMMIT, PAGE_READWRITE); 204 } 205 "#; 206 let result = CodeValidator::validate_technique_code(code); 207 assert!(result.is_err()); 208 let errors = result.unwrap_err(); 209 assert!(matches!(errors[0], ValidationError::MissingUnsafeBlock)); 210 } 211 212 #[test] 213 fn test_duplicate_extern_detected() { 214 let code = r#" 215 extern "system" { 216 fn VirtualAlloc(addr: *mut c_void) -> *mut c_void; 217 fn VirtualAlloc(addr: *mut c_void) -> *mut c_void; 218 } 219 "#; 220 let result = CodeValidator::validate_technique_code(code); 221 assert!(result.is_err()); 222 let errors = result.unwrap_err(); 223 eprintln!("Errors found: {:?}", errors); 224 assert!(errors 225 .iter() 226 .any(|e| matches!(e, ValidationError::DuplicateExternDeclaration(_)))); 227 } 228 229 #[test] 230 fn test_code_without_api_calls_doesnt_need_unsafe() { 231 let code = r#" 232 { 233 let x = 42; 234 let y = x + 1; 235 } 236 "#; 237 assert!(CodeValidator::validate_technique_code(code).is_ok()); 238 } 239 240 #[test] 241 fn test_validation_with_context() { 242 let code = r#" 243 { 244 let ptr = VirtualAlloc(ptr::null_mut(), 1024, MEM_COMMIT, PAGE_READWRITE); 245 } 246 "#; 247 let result = CodeValidator::validate_with_context(code, "CreateFiberGenerator"); 248 assert!(result.is_err()); 249 let errors = result.unwrap_err(); 250 assert_eq!(errors[0].0, "CreateFiberGenerator"); 251 } 252 }