Skip to content

Commit

Permalink
Merge pull request #136 from jpohls1/master
Browse files Browse the repository at this point in the history
Allow iterating over compiled ruleset before scanning
  • Loading branch information
Hugal31 authored Nov 28, 2023
2 parents c752dd3 + d3f7e9a commit e62b7c6
Show file tree
Hide file tree
Showing 10 changed files with 6,542 additions and 5,923 deletions.
26 changes: 24 additions & 2 deletions examples/tutorial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,39 @@ const RULES: &str = r#"
$rust
}
"#;
const RULES2: &str = r#"
rule contains_rust_too {
strings:
$more_rust = "rust" nocase
condition:
$more_rust
}
"#;

fn main() {
let compiler = Compiler::new().unwrap();
let compiler = compiler
.add_rules_str(RULES)
.expect("Should have parsed rule");
let rules = compiler
let compiler = compiler
.add_rules_str(RULES2)
.expect("Should have parsed rule");
let ruleset = compiler
.compile_rules()
.expect("Should have compiled rules");
let results = rules

let mut rules = ruleset.get_rules();
for (i, rule) in rules.iter_mut().enumerate() {
println!("{}: {}", i, rule.identifier);
if i % 2 == 1 {
rule.disable()
}
}

let results = ruleset
.scan_mem("I love Rust!".as_bytes(), 5)
.expect("Should have scanned");

assert_eq!(results.len(), 1);
assert!(results.iter().any(|r| r.identifier == "contains_rust"));
}
77 changes: 72 additions & 5 deletions src/internals/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::ptr;
use crate::errors::*;
use crate::internals::meta::MetadataIterator;
use crate::internals::string::YrStringIterator;
use crate::rules::RulesetRule;
use crate::{Metadata, Rule, YrString};

pub fn rules_destroy(rules: *mut yara_sys::YR_RULES) {
Expand All @@ -33,6 +34,17 @@ pub fn scanner_destroy(scanner: *mut yara_sys::YR_SCANNER) {
}
}

pub fn get_rules<'a>(ruleset: *mut yara_sys::YR_RULES) -> Vec<RulesetRule<'a>> {
let num_rules = unsafe { (*ruleset).num_rules } as usize;
let mut result: Vec<RulesetRule> = Vec::with_capacity(num_rules);

for rule in RuleIterator::from(unsafe { &*ruleset }) {
result.push(rule);
}

result
}

// TODO Check if non mut
pub fn rules_save(rules: *mut yara_sys::YR_RULES, filename: &str) -> Result<(), YaraError> {
let filename = CString::new(filename).unwrap();
Expand Down Expand Up @@ -88,8 +100,8 @@ where
})
}

impl<'a> From<(&'a yara_sys::YR_SCAN_CONTEXT, &'a yara_sys::YR_RULE)> for Rule<'a> {
fn from((context, rule): (&'a yara_sys::YR_SCAN_CONTEXT, &'a yara_sys::YR_RULE)) -> Self {
impl<'a> From<&'a yara_sys::YR_RULE> for Rule<'a> {
fn from(rule: &'a yara_sys::YR_RULE) -> Self {
let identifier = unsafe { CStr::from_ptr(rule.get_identifier()) }
.to_str()
.unwrap();
Expand All @@ -100,9 +112,7 @@ impl<'a> From<(&'a yara_sys::YR_SCAN_CONTEXT, &'a yara_sys::YR_RULE)> for Rule<'
let tags = TagIterator::from(rule)
.map(|c| c.to_str().unwrap())
.collect();
let strings = YrStringIterator::from(rule)
.map(|s| YrString::from((context, s)))
.collect();
let strings: Vec<YrString> = Vec::new();

Rule {
identifier,
Expand All @@ -114,6 +124,63 @@ impl<'a> From<(&'a yara_sys::YR_SCAN_CONTEXT, &'a yara_sys::YR_RULE)> for Rule<'
}
}

impl<'a> From<(&'a yara_sys::YR_SCAN_CONTEXT, &'a yara_sys::YR_RULE)> for Rule<'a> {
fn from((context, rule): (&'a yara_sys::YR_SCAN_CONTEXT, &'a yara_sys::YR_RULE)) -> Self {
let mut result = Rule::from(rule);
result.strings = YrStringIterator::from(rule)
.map(|s| YrString::from((context, s)))
.collect();
result
}
}

/// Iterate over YR_RULE in a YR_RULES.
///
/// # Implementation notes
///
/// See `yr_rules_foreach` in Yara.
pub struct RuleIterator<'a> {
head: *const yara_sys::YR_RULE,
_marker: marker::PhantomData<&'a yara_sys::YR_RULE>,
}

impl<'a> From<&'a yara_sys::YR_RULES> for RuleIterator<'a> {
fn from(rules: &'a yara_sys::YR_RULES) -> RuleIterator<'a> {
RuleIterator {
head: rules.get_rules_table(),
_marker: marker::PhantomData,
}
}
}

impl<'a> Iterator for RuleIterator<'a> {
type Item = RulesetRule<'a>;

fn next(&mut self) -> Option<Self::Item> {
if self.head.is_null() {
return None;
}

let rule = unsafe { *self.head };
let mut result: Option<Self::Item> = None;

if ((rule.flags as u32) & yara_sys::RULE_FLAGS_NULL) != 0 {
self.head = std::ptr::null();
} else {
let rule_data = Rule::from(unsafe { &*self.head });
result = Some(RulesetRule {
inner: self.head as *mut yara_sys::YR_RULE,
identifier: rule_data.identifier,
namespace: rule_data.namespace,
tags: rule_data.tags,
metadatas: rule_data.metadatas,
});
self.head = unsafe { self.head.offset(1) };
}
result
}
}

struct TagIterator<'a> {
head: *const c_char,
_marker: marker::PhantomData<&'a c_char>,
Expand Down
31 changes: 31 additions & 0 deletions src/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ impl Rules {
}

impl Rules {
pub fn get_rules(&self) -> Vec<RulesetRule> {
internals::get_rules(self.inner)
}

/// Create a [`Scanner`](crate::scanner::Scanner) from this set of rules.
///
/// You can create as many scanners as you want, and they each can have
Expand Down Expand Up @@ -316,6 +320,33 @@ impl Drop for Rules {
}
}

/// A rule contained in a ruleset.

pub struct RulesetRule<'r> {
pub(crate) inner: *mut yara_sys::YR_RULE,
/// Name of the rule.
pub identifier: &'r str,
/// Namespace of the rule.
pub namespace: &'r str,
/// Metadatas of the rule.
pub metadatas: Vec<Metadata<'r>>,
/// Tags of the rule.
pub tags: Vec<&'r str>,
}

impl<'r> RulesetRule<'r> {
pub fn enable(&mut self) {
unsafe {
(*self.inner).enable();
}
}
pub fn disable(&mut self) {
unsafe {
(*self.inner).disable();
}
}
}

/// A rule that matched during a scan.

#[derive(Debug)]
Expand Down
Loading

0 comments on commit e62b7c6

Please sign in to comment.