From 8fd48039c9dd23895aacfa49af81b522efd58f1a Mon Sep 17 00:00:00 2001 From: marirs <251870+marirs@users.noreply.github.com> Date: Sun, 11 Feb 2024 11:46:04 +0530 Subject: [PATCH] refactors --- Cargo.toml | 9 +-- examples/capa_cli.rs | 12 ++-- src/extractor/dnfile.rs | 90 +++++++++++++----------- src/extractor/smda.rs | 56 +++++++++------ src/lib.rs | 148 +++++++++++++++++++++++----------------- src/rules/features.rs | 46 ++++++------- src/rules/mod.rs | 6 +- 7 files changed, 211 insertions(+), 156 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b91be9b..9a54ea2 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "capa" -version = "0.3.8" +version = "0.3.9" description = "File capability extractor." authors = ["Marirs ", "Andrey Mnatsakanov "] keywords = ["capa", "fce", "capability", "file"] @@ -19,14 +19,15 @@ petgraph = "0.6.2" regex = "1.5" fancy-regex = { git = "https://github.com/mnaza/fancy-regex.git" } serde = { version = "1", features = ["derive"] } -smda = {git = "https://github.com/jorgeaduran/smda-rs.git", branch = "fixes"} +#smda = {git = "https://github.com/jorgeaduran/smda-rs.git", branch = "fixes"} +smda = "0.2.6" thiserror = "1" walkdir = "2.3.2" yaml-rust = "0.4.5" goblin = { version = "0.8.0", features = ["alloc"] } maplit = "1" -#dnfile = { git = "https://github.com/marirs/dnfile-rs.git", branch = "master" } -dnfile = { git = "https://github.com/jorgeaduran/dnfile-rs.git", branch = "features/optimize_decoding" } +dnfile = { git = "https://github.com/marirs/dnfile-rs.git", branch = "master" } +#dnfile = { git = "https://github.com/jorgeaduran/dnfile-rs.git", branch = "features/optimize_decoding" } lazy_static = "1.4.0" parking_lot = "0.12.1" serde_json = "1.0.113" diff --git a/examples/capa_cli.rs b/examples/capa_cli.rs index 0820c97..aded1ec 100644 --- a/examples/capa_cli.rs +++ b/examples/capa_cli.rs @@ -33,7 +33,7 @@ fn main() { match FileCapabilities::from_file(&filename, &rules_path, true, true, &|_s| {}) { Err(e) => println!("{:?}", e), Ok(s) => { - match to_value(&s) { + match to_value(s) { Err(e) => println!("serde_json_error: {}", e), Ok(data) => { let data = data.as_object().unwrap(); @@ -120,7 +120,7 @@ fn get_properties(props: &Value, features: Option<&Value>) -> Table { Alignment::CENTER, ) .with_hspan(2)])); - for (k, v) in &*meta { + for (k, v) in meta { tbl.add_row(Row::new(vec![ Cell::new(k) .with_style(Attr::ForegroundColor(color::BRIGHT_BLUE)) @@ -153,7 +153,7 @@ fn get_mitre(attacks: &Map) -> Table { Cell::new_align("ATT&CK Technique", Alignment::LEFT), ])); - for (tatic, v) in &*attacks { + for (tatic, v) in attacks { let techniques = v.as_array().unwrap(); let techniques = techniques .iter() @@ -183,7 +183,7 @@ fn get_mbc(mbc: &Map) -> Table { Cell::new_align("MBC Objective", Alignment::LEFT), Cell::new_align("MBC Behavior", Alignment::LEFT), ])); - for (objective, v) in &*mbc { + for (objective, v) in mbc { let behaviors = v.as_array().unwrap(); let behaviours = behaviors .iter() @@ -213,7 +213,7 @@ fn get_namespace(namespace: &Map) -> Table { Cell::new_align("Capability", Alignment::LEFT), Cell::new_align("Namespace", Alignment::LEFT), ])); - for (capability, v) in &*namespace { + for (capability, v) in namespace { let ns = v.as_str().unwrap().to_string(); tbl.add_row(Row::new(vec![ @@ -236,7 +236,7 @@ fn get_verbose_info(extra: &Map) -> Table { Cell::new_align("Features", Alignment::LEFT), Cell::new_align("Capabilities", Alignment::LEFT), ])); - for (function, v) in &*extra { + for (function, v) in extra { let caps = v.as_object().unwrap(); let address = caps.get("address").unwrap().as_str().unwrap(); let features = caps.get("features").unwrap().as_u64().unwrap().to_string(); diff --git a/src/extractor/dnfile.rs b/src/extractor/dnfile.rs index 3522fea..04d2e88 100644 --- a/src/extractor/dnfile.rs +++ b/src/extractor/dnfile.rs @@ -9,7 +9,7 @@ use dnfile::{ }; use std::{ collections::{HashMap, HashSet}, - sync::{Arc}, + sync::Arc, }; use parking_lot::RwLock; @@ -175,7 +175,7 @@ impl super::Extractor for Extractor { OpCodeValue::Jmp, OpCodeValue::Newobj, ] - .contains(&insn.opcode.value) + .contains(&insn.opcode.value) { continue; } @@ -210,15 +210,15 @@ impl super::Extractor for Extractor { ) -> Result> { let f: &Function = f.as_any().downcast_ref::().unwrap(); Ok([ - self.extract_function_call_to_features(&f)?, - self.extract_function_call_from_features(&f)?, - self.extract_recurcive_call_features(&f)?, + self.extract_function_call_to_features(f)?, + self.extract_function_call_from_features(f)?, + self.extract_recurcive_call_features(f)?, ] - .into_iter() - .fold(Vec::new(), |mut acc, f| { - acc.extend(f); - acc - })) + .into_iter() + .fold(Vec::new(), |mut acc, f| { + acc.extend(f); + acc + })) } fn get_basic_blocks( @@ -260,7 +260,6 @@ impl super::Extractor for Extractor { ss.extend(self.extract_unmanaged_call_characteristic_features(&f.f, &insn.i)?); Ok(ss) } - } impl Extractor { @@ -676,14 +675,14 @@ impl Extractor { insn: &cil::instruction::Instruction, ) -> Result> { let mut res = vec![]; - if !vec![ + if ![ OpCodeValue::Call, OpCodeValue::Callvirt, OpCodeValue::Jmp, OpCodeValue::Calli, OpCodeValue::Newobj, ] - .contains(&insn.opcode.value) + .contains(&insn.opcode.value) { return Ok(vec![]); } @@ -760,13 +759,13 @@ impl Extractor { insn: &cil::instruction::Instruction, ) -> Result> { let mut res = Vec::new(); - if vec![ + if [ OpCodeValue::Call, OpCodeValue::Callvirt, OpCodeValue::Jmp, OpCodeValue::Calli, ] - .contains(&insn.opcode.value) + .contains(&insn.opcode.value) { let operand_result = resolve_dotnet_token( &self.pe, @@ -795,23 +794,32 @@ impl Extractor { // Verifica si el nombre del método indica un acceso a una propiedad (get o set). if operand.name.starts_with("get_") || operand.name.starts_with("set_") { // Obtiene el namespace y el nombre de la clase a la que pertenece el MemberRef. - let (operand_class_type_namespace, operand_class_type_name) = match operand.class.table() { - "TypeRef" => { - if let Ok(rr) = self.pe.net()?.resolve_coded_index::(&operand.class) { - (rr.type_namespace.clone(), rr.type_name.clone()) - } else { - return Ok(vec![]); + let (operand_class_type_namespace, operand_class_type_name) = + match operand.class.table() { + "TypeRef" => { + if let Ok(rr) = self + .pe + .net()? + .resolve_coded_index::(&operand.class) + { + (rr.type_namespace.clone(), rr.type_name.clone()) + } else { + return Ok(vec![]); + } } - }, - "TypeDef" => { - if let Ok(rr) = self.pe.net()?.resolve_coded_index::(&operand.class) { - (rr.type_namespace.clone(), rr.type_name.clone()) - } else { - return Ok(vec![]); + "TypeDef" => { + if let Ok(rr) = self + .pe + .net()? + .resolve_coded_index::(&operand.class) + { + (rr.type_namespace.clone(), rr.type_name.clone()) + } else { + return Ok(vec![]); + } } - }, - _ => return Ok(vec![]), - }; + _ => return Ok(vec![]), + }; // Construye el nombre completo de la propiedad accedida. let property_name = format!( @@ -842,7 +850,7 @@ impl Extractor { } } } - } else if vec![ + } else if [ OpCodeValue::Ldfld, OpCodeValue::Ldflda, OpCodeValue::Ldsfld, @@ -850,12 +858,14 @@ impl Extractor { OpCodeValue::Stfld, OpCodeValue::Stsfld, ] - .contains(&insn.opcode.value) + .contains(&insn.opcode.value) { if let Ok(fields_lock) = self.get_fields() { if let Some(fields) = fields_lock.read().as_ref() { if let Some(field) = fields.get(&(insn.operand.value()? as u64)) { - let access = if vec![OpCodeValue::Stfld, OpCodeValue::Stsfld].contains(&insn.opcode.value) { + let access = if [OpCodeValue::Stfld, OpCodeValue::Stsfld] + .contains(&insn.opcode.value) + { Some(crate::rules::features::FeatureAccess::Write) } else { Some(crate::rules::features::FeatureAccess::Read) @@ -932,7 +942,7 @@ impl Extractor { _f: &cil::function::Function, insn: &cil::instruction::Instruction, ) -> Result> { - if !vec![ + if ![ OpCodeValue::Call, OpCodeValue::Callvirt, OpCodeValue::Jmp, @@ -945,7 +955,7 @@ impl Extractor { OpCodeValue::Stsfld, OpCodeValue::Newobj, ] - .contains(&insn.opcode.value) + .contains(&insn.opcode.value) { return Ok(vec![]); } @@ -983,7 +993,7 @@ impl Extractor { let fields_lock = self.get_fields()?.read(); if let Some(fields) = &*fields_lock { - if let Some(field) = fields.clone().get(&(insn.operand.value()? as u64)){ + if let Some(field) = fields.clone().get(&(insn.operand.value()? as u64)) { res.push(( crate::rules::features::Feature::Namespace( crate::rules::features::NamespaceFeature::new(&field.namespace, "")?, @@ -1002,7 +1012,7 @@ impl Extractor { _f: &cil::function::Function, insn: &cil::instruction::Instruction, ) -> Result> { - if !vec![ + if ![ OpCodeValue::Call, OpCodeValue::Callvirt, OpCodeValue::Jmp, @@ -1015,7 +1025,7 @@ impl Extractor { OpCodeValue::Stsfld, OpCodeValue::Newobj, ] - .contains(&insn.opcode.value) + .contains(&insn.opcode.value) { return Ok(vec![]); } @@ -1083,13 +1093,13 @@ impl Extractor { _f: &cil::function::Function, insn: &cil::instruction::Instruction, ) -> Result> { - if !vec![ + if ![ OpCodeValue::Call, OpCodeValue::Callvirt, OpCodeValue::Jmp, OpCodeValue::Calli, ] - .contains(&insn.opcode.value) + .contains(&insn.opcode.value) { return Ok(vec![]); } diff --git a/src/extractor/smda.rs b/src/extractor/smda.rs index 4f35d00..30f9b99 100644 --- a/src/extractor/smda.rs +++ b/src/extractor/smda.rs @@ -239,9 +239,19 @@ impl super::Extractor for Extractor { } impl Extractor { - pub fn new(path: &str, high_accuracy: bool, resolve_tailcalls: bool, data: &Vec) -> Result { + pub fn new( + path: &str, + high_accuracy: bool, + resolve_tailcalls: bool, + data: &Vec, + ) -> Result { Ok(Extractor { - report: Disassembler::disassemble_file(path, high_accuracy, resolve_tailcalls, Some(&data))?, + report: Disassembler::disassemble_file( + path, + high_accuracy, + resolve_tailcalls, + Some(data), + )?, buf: data.clone(), path: path.to_string(), }) @@ -327,7 +337,9 @@ impl Extractor { fn _extract_file_embedded_pe(&self) -> Result> { let mut res = vec![]; - for (mz_offset, _pe_offset, _key) in Extractor::find_embedded_pe_headers(&self.report.buffer) { + for (mz_offset, _pe_offset, _key) in + Extractor::find_embedded_pe_headers(&self.report.buffer) + { res.push(( crate::rules::features::Feature::Characteristic( crate::rules::features::CharacteristicFeature::new("embedded pe", "")?, @@ -347,7 +359,7 @@ impl Extractor { crate::rules::features::Feature::Section( crate::rules::features::SectionFeature::new(n.trim_matches(char::from(0)), "")?, ), - *b as u64, + *b, )); } Ok(res) @@ -879,7 +891,8 @@ impl Extractor { if pbytes[current_offset + 0x3E] == pbytes[current_offset + 0x3F] { let key = pbytes[current_offset + 0x3E]; - if pbytes[current_offset] ^ key == b'M' && pbytes[current_offset + 1] ^ key == b'Z' { + if pbytes[current_offset] ^ key == b'M' && pbytes[current_offset + 1] ^ key == b'Z' + { let e_lfanew = u32::from_le_bytes([ pbytes[current_offset + 0x3C] ^ key, pbytes[current_offset + 0x3D] ^ key, @@ -887,16 +900,19 @@ impl Extractor { 0, ]) as usize; - - if current_offset + e_lfanew + 0x18 <= end_safe_zone { - if pbytes[current_offset + e_lfanew] ^ key == b'P' && - pbytes[current_offset + e_lfanew + 1] ^ key == b'E' && - pbytes[current_offset + e_lfanew + 2] == key && - pbytes[current_offset + e_lfanew + 3] == key { - results.push((current_offset as u64, (current_offset + e_lfanew) as u64, key)); - current_offset = current_offset + e_lfanew + 4; - continue; - } + if current_offset + e_lfanew + 0x18 <= end_safe_zone + && pbytes[current_offset + e_lfanew] ^ key == b'P' + && pbytes[current_offset + e_lfanew + 1] ^ key == b'E' + && pbytes[current_offset + e_lfanew + 2] == key + && pbytes[current_offset + e_lfanew + 3] == key + { + results.push(( + current_offset as u64, + (current_offset + e_lfanew) as u64, + key, + )); + current_offset = current_offset + e_lfanew + 4; + continue; } } } @@ -910,7 +926,7 @@ impl Extractor { bytes.iter().map(|&b| b ^ key).collect() } - fn _carve_pe(pbytes: &[u8], offset: u64) -> Result>{ + fn _carve_pe(pbytes: &[u8], offset: u64) -> Result> { let mut mz_xor = vec![]; for key in 0..255 { mz_xor.push(( @@ -931,9 +947,9 @@ impl Extractor { } } let mut res = vec![]; - while !todo.is_empty() { + while let Some((off, mzx, pex, key)) = todo.pop() { // println!("{}", todo.len()); - let (off, mzx, pex, key) = todo.pop().unwrap(); + //The MZ header has one field we will check //e_lfanew is at 0x3c let e_lfanew = off + 0x3C; @@ -1176,7 +1192,9 @@ lazy_static::lazy_static! { } pub fn extract_ascii_strings(data: &[u8], min_length: usize) -> Result> { - if data.get(0).map_or(false, |&b| REPEATS.contains(&b) && buf_filled_with(data, &b)) { + if data.first().map_or(false, |&b| { + REPEATS.contains(&b) && buf_filled_with(data, &b) + }) { return Ok(vec![]); } let re = regex::bytes::Regex::new(&format!(r##"([{}]{{{},}})"##, ASCII_BYTE, min_length))?; diff --git a/src/lib.rs b/src/lib.rs index 3fbc544..03a2c96 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -94,7 +94,7 @@ impl FileCapabilities { #[cfg(feature = "verbose")] counts: &HashMap, ) -> Result<()> { for rule in capabilities.keys() { - let mut attacks_set: BTreeSet= BTreeSet::new(); + let mut attacks_set: BTreeSet = BTreeSet::new(); let mut mbc_set: BTreeSet = BTreeSet::new(); if rule .meta @@ -105,9 +105,9 @@ impl FileCapabilities { { for p in s { match Attacks::from_str(p.as_str().unwrap()) { - Ok(attack) =>{ + Ok(attack) => { attacks_set.insert(attack); - }, + } Err(e) => { println!("error = {:?}", e); } @@ -132,7 +132,7 @@ impl FileCapabilities { _ => { self.attacks.insert( parts[0].to_string(), - vec![ss.to_string()].iter().cloned().collect(), + [ss.to_string()].iter().cloned().collect(), ); } } @@ -151,10 +151,10 @@ impl FileCapabilities { match Mbc::from_str(p.as_str().unwrap()) { Ok(mbc) => { mbc_set.insert(mbc); - }, + } Err(e) => { println!("error = {:?}", e); - }, + } } let parts: Vec<&str> = p .as_str() @@ -176,7 +176,7 @@ impl FileCapabilities { _ => { self.mbc.insert( parts[0].to_string(), - vec![ss.to_string()].iter().cloned().collect(), + [ss.to_string()].iter().cloned().collect(), ); } } @@ -193,12 +193,15 @@ impl FileCapabilities { { self.capability_namespaces .insert(rule.name.clone(), s.clone()); - let _ = self.capabilities_associations.entry(rule.name.clone()).or_insert_with(|| CapabilityAssociation { - attack: attacks_set.clone(), - mbc: mbc_set.clone(), - namespace: s.clone(), - name: rule.name.clone(), - }); + let _ = self + .capabilities_associations + .entry(rule.name.clone()) + .or_insert_with(|| CapabilityAssociation { + attack: attacks_set.clone(), + mbc: mbc_set.clone(), + namespace: s.clone(), + name: rule.name.clone(), + }); } } } @@ -235,26 +238,38 @@ impl FileCapabilities { pub fn construct_json_for_capabilities_associations(self) -> Value { let mut rules = serde_json::Map::new(); for (name, association) in &self.capabilities_associations { - let attacks_json = association.attack.iter().map(|a| json!({ - "id": a.id, - "subtechnique": a.subtechnique, - "tactic": a.tactic, - "technique": a.technique, - })).collect::>(); - - let mbc_json = association.mbc.iter().map(|m| json!({ - "objective": m.objective, - "behavior": m.behavior, - "method": m.method, - "id": m.id, - })).collect::>(); + let attacks_json = association + .attack + .iter() + .map(|a| { + json!({ + "id": a.id, + "subtechnique": a.subtechnique, + "tactic": a.tactic, + "technique": a.technique, + }) + }) + .collect::>(); + + let mbc_json = association + .mbc + .iter() + .map(|m| { + json!({ + "objective": m.objective, + "behavior": m.behavior, + "method": m.method, + "id": m.id, + }) + }) + .collect::>(); let association_json = json!({ - "attacks": attacks_json, - "mbc": mbc_json, - "namespace": association.namespace, - "name": association.name, - }); + "attacks": attacks_json, + "mbc": mbc_json, + "namespace": association.namespace, + "name": association.name, + }); rules.insert(name.clone(), association_json); } @@ -263,11 +278,13 @@ impl FileCapabilities { pub fn serialize_file_capabilities(self) -> serde_json::Result { let mut fc_json = serde_json::to_value(self.clone())?; let associations_json = self.construct_json_for_capabilities_associations(); - fc_json.as_object_mut().unwrap().insert("rules".to_string(), associations_json); + fc_json + .as_object_mut() + .unwrap() + .insert("rules".to_string(), associations_json); serde_json::to_string(&fc_json) } - fn get_format(extractor: &Box) -> Result { Ok(extractor.format()) } @@ -526,9 +543,7 @@ fn find_file_capabilities<'a>( } } } else { - file_features - .entry(feature) - .or_insert_with(std::vec::Vec::new); + file_features.entry(feature).or_default(); } } @@ -538,14 +553,8 @@ fn find_file_capabilities<'a>( let mut matches: HashMap<&crate::rules::Rule, Vec<(u64, (bool, Vec))>> = HashMap::new(); - matches.extend( - match_fn(&ruleset.file_rules, &file_features, &0x0, logger)?.1 - .into_iter(), - ); - matches.extend( - match_fn(&ruleset.function_rules, &file_features, &0x0, logger)?.1 - .into_iter(), - ); + matches.extend(match_fn(&ruleset.file_rules, &file_features, &0x0, logger)?.1); + matches.extend(match_fn(&ruleset.function_rules, &file_features, &0x0, logger)?.1); Ok((matches, file_features.len())) } @@ -561,7 +570,11 @@ fn parse_parts_id(s: &str) -> Result<(Vec, String)> { let re = regex::Regex::new(r"^(.*?)(?:\s*\[(.*?)])?$").unwrap(); if let Some(caps) = re.captures(s) { let parts_str = caps.get(1).map_or("", |m| m.as_str()); - let parts: Vec = parts_str.split("::").filter(|s| !s.is_empty()).map(|s| s.to_string()).collect(); + let parts: Vec = parts_str + .split("::") + .filter(|s| !s.is_empty()) + .map(|s| s.to_string()) + .collect(); let id = caps.get(2).map_or("", |m| m.as_str()).to_string(); Ok((parts, id)) } else { @@ -577,7 +590,7 @@ pub struct Properties { #[serde(serialize_with = "to_hex", deserialize_with = "from_hex")] pub base_address: usize, } -#[derive(Debug, Serialize,Deserialize, Clone, Ord, PartialOrd, Eq, PartialEq)] +#[derive(Debug, Serialize, Deserialize, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct Attacks { pub id: String, pub subtechnique: String, @@ -587,7 +600,7 @@ pub struct Attacks { impl Attacks { fn from_str(s: &str) -> Result { let (parts, id) = parse_parts_id(s)?; - let tactic = parts.get(0).cloned().unwrap_or_default(); + let tactic = parts.first().cloned().unwrap_or_default(); let technique = parts.get(1).cloned().unwrap_or_default(); let subtechnique = parts.get(2).cloned().unwrap_or_default(); @@ -631,7 +644,7 @@ impl Default for Mbc { impl Mbc { fn from_str(s: &str) -> Result { let (parts, id) = parse_parts_id(s)?; - let objective = parts.get(0).cloned().unwrap_or_default(); + let objective = parts.first().cloned().unwrap_or_default(); let behavior = parts.get(1).cloned().unwrap_or_default(); let method = parts.get(2).cloned().unwrap_or_default(); @@ -779,24 +792,37 @@ fn get_format(f: &str) -> Result<(FileFormat, Vec)> { } } -fn get_file_extractors(f: &str, - format: FileFormat, - data: &Vec, - high_accuracy: bool, - resolve_tailcalls: bool,) -> Result> { +fn get_file_extractors( + f: &str, + format: FileFormat, + data: &Vec, + high_accuracy: bool, + resolve_tailcalls: bool, +) -> Result> { match format { FileFormat::PE => { if let Ok(e) = extractor::dnfile::Extractor::new(f) { Ok(Box::new(e)) - } - else{ - Ok(Box::new(extractor::smda::Extractor::new(f, high_accuracy, resolve_tailcalls, data)?)) + } else { + Ok(Box::new(extractor::smda::Extractor::new( + f, + high_accuracy, + resolve_tailcalls, + data, + )?)) } } - FileFormat::ELF => { - Ok(Box::new(extractor::smda::Extractor::new(f, high_accuracy, resolve_tailcalls, data)?)) - } - _ => Ok(Box::new(extractor::smda::Extractor::new(f, high_accuracy, resolve_tailcalls, data)?)), + FileFormat::ELF => Ok(Box::new(extractor::smda::Extractor::new( + f, + high_accuracy, + resolve_tailcalls, + data, + )?)), + _ => Ok(Box::new(extractor::smda::Extractor::new( + f, + high_accuracy, + resolve_tailcalls, + data, + )?)), } } - diff --git a/src/rules/features.rs b/src/rules/features.rs index 8639217..4fd355f 100755 --- a/src/rules/features.rs +++ b/src/rules/features.rs @@ -226,29 +226,29 @@ impl Feature { pub fn is_supported_in_scope(&self, scopes: &crate::rules::Scopes) -> Result { match self { - Feature::Property(a) => a.is_supported_in_scope(&scopes), - Feature::Api(a) => a.is_supported_in_scope(&scopes), - Feature::Regex(a) => a.is_supported_in_scope(&scopes), - Feature::String(a) => a.is_supported_in_scope(&scopes), - Feature::Substring(a) => a.is_supported_in_scope(&scopes), - Feature::Bytes(a) => a.is_supported_in_scope(&scopes), - Feature::Number(a) => a.is_supported_in_scope(&scopes), - Feature::Offset(a) => a.is_supported_in_scope(&scopes), - Feature::Mnemonic(a) => a.is_supported_in_scope(&scopes), - Feature::BasicBlock(a) => a.is_supported_in_scope(&scopes), - Feature::Characteristic(a) => a.is_supported_in_scope(&scopes), - Feature::Export(a) => a.is_supported_in_scope(&scopes), - Feature::Import(a) => a.is_supported_in_scope(&scopes), - Feature::Section(a) => a.is_supported_in_scope(&scopes), - Feature::MatchedRule(a) => a.is_supported_in_scope(&scopes), - Feature::FunctionName(a) => a.is_supported_in_scope(&scopes), - Feature::Os(a) => a.is_supported_in_scope(&scopes), - Feature::Format(a) => a.is_supported_in_scope(&scopes), - Feature::Arch(a) => a.is_supported_in_scope(&scopes), - Feature::Namespace(a) => a.is_supported_in_scope(&scopes), - Feature::Class(a) => a.is_supported_in_scope(&scopes), - Feature::OperandNumber(a) => a.is_supported_in_scope(&scopes), - Feature::OperandOffset(a) => a.is_supported_in_scope(&scopes), + Feature::Property(a) => a.is_supported_in_scope(scopes), + Feature::Api(a) => a.is_supported_in_scope(scopes), + Feature::Regex(a) => a.is_supported_in_scope(scopes), + Feature::String(a) => a.is_supported_in_scope(scopes), + Feature::Substring(a) => a.is_supported_in_scope(scopes), + Feature::Bytes(a) => a.is_supported_in_scope(scopes), + Feature::Number(a) => a.is_supported_in_scope(scopes), + Feature::Offset(a) => a.is_supported_in_scope(scopes), + Feature::Mnemonic(a) => a.is_supported_in_scope(scopes), + Feature::BasicBlock(a) => a.is_supported_in_scope(scopes), + Feature::Characteristic(a) => a.is_supported_in_scope(scopes), + Feature::Export(a) => a.is_supported_in_scope(scopes), + Feature::Import(a) => a.is_supported_in_scope(scopes), + Feature::Section(a) => a.is_supported_in_scope(scopes), + Feature::MatchedRule(a) => a.is_supported_in_scope(scopes), + Feature::FunctionName(a) => a.is_supported_in_scope(scopes), + Feature::Os(a) => a.is_supported_in_scope(scopes), + Feature::Format(a) => a.is_supported_in_scope(scopes), + Feature::Arch(a) => a.is_supported_in_scope(scopes), + Feature::Namespace(a) => a.is_supported_in_scope(scopes), + Feature::Class(a) => a.is_supported_in_scope(scopes), + Feature::OperandNumber(a) => a.is_supported_in_scope(scopes), + Feature::OperandOffset(a) => a.is_supported_in_scope(scopes), } } diff --git a/src/rules/mod.rs b/src/rules/mod.rs index 1f74115..5146261 100644 --- a/src/rules/mod.rs +++ b/src/rules/mod.rs @@ -846,7 +846,7 @@ impl Rule { return Ok(StatementElement::Statement(Box::new( Statement::Range(RangeStatement::new( StatementElement::Feature(Box::new(feature)), - min as u32, + min, max as u32, "", )?), @@ -1044,9 +1044,9 @@ pub fn get_rules_and_dependencies<'a>(rules: &'a [Rule], rule_name: &str) -> Res } let mut wanted = vec![rule_name.to_string()]; - fn rec<'a>( + fn rec( want: &mut Vec, - rule: &'a Rule, + rule: &Rule, rules_by_name: &HashMap, namespaces: &HashMap>, ) -> Result<()> {