Skip to main content

yara_x/
models.rs

1use std::ops::Range;
2use std::slice::Iter;
3
4use bstr::{BStr, ByteSlice};
5use serde::ser::SerializeStruct;
6use serde::{Deserialize, Serialize, Serializer};
7
8use crate::compiler::{IdentId, PatternId, PatternInfo, RuleInfo};
9use crate::scanner::{ScanContext, ScanState};
10use crate::{Rules, compiler, scanner};
11
12/// Kinds of patterns.
13#[derive(Serialize, Deserialize, Clone, Copy)]
14pub enum PatternKind {
15    /// The pattern is a plain text string.
16    Text,
17    /// The pattern is a hex pattern (e.g: { 01 02 03 })
18    Hex,
19    /// The pattern is a regular expression.
20    Regexp,
21}
22
23/// A structure that describes a rule.
24pub struct Rule<'a, 'r> {
25    pub(crate) ctx: Option<&'a ScanContext<'r, 'a>>,
26    pub(crate) rules: &'r Rules,
27    pub(crate) rule_info: &'r RuleInfo,
28}
29
30impl<'a, 'r> Rule<'a, 'r> {
31    /// Returns the rule's name.
32    pub fn identifier(&self) -> &'r str {
33        self.rules.ident_pool().get(self.rule_info.ident_id).unwrap()
34    }
35
36    /// Returns the rule's namespace.
37    pub fn namespace(&self) -> &'r str {
38        self.rules.ident_pool().get(self.rule_info.namespace_ident_id).unwrap()
39    }
40
41    /// Returns the metadata associated to this rule.
42    pub fn metadata(&self) -> Metadata<'a, 'r> {
43        Metadata {
44            rules: self.rules,
45            iterator: self.rule_info.metadata.iter(),
46            len: self.rule_info.metadata.len(),
47        }
48    }
49
50    /// Returns true if the rule is global.
51    pub fn is_global(&self) -> bool {
52        self.rule_info.is_global
53    }
54
55    /// Returns true if the rule is private.
56    pub fn is_private(&self) -> bool {
57        self.rule_info.is_private
58    }
59
60    /// Returns the tags associated to this rule.
61    pub fn tags(&self) -> Tags<'a, 'r> {
62        Tags {
63            rules: self.rules,
64            iterator: self.rule_info.tags.iter(),
65            len: self.rule_info.tags.len(),
66        }
67    }
68
69    /// Returns an iterator over the patterns defined for this rule.
70    ///
71    /// By default, the iterator yields only public patterns. Use
72    /// [`Patterns::include_private`] if you want to include private patterns
73    /// as well.
74    pub fn patterns(&self) -> Patterns<'a, 'r> {
75        Patterns {
76            ctx: self.ctx,
77            rules: self.rules,
78            include_private: false,
79            iterator: self.rule_info.patterns.iter(),
80            len_non_private: self.rule_info.patterns.len()
81                - self.rule_info.num_private_patterns,
82            len_private: self.rule_info.num_private_patterns,
83        }
84    }
85}
86
87impl Serialize for Rule<'_, '_> {
88    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
89    where
90        S: Serializer,
91    {
92        let mut s = serializer.serialize_struct("rule", 7)?;
93
94        s.serialize_field("identifier", &self.identifier())?;
95        s.serialize_field("namespace", &self.namespace())?;
96        s.serialize_field("is_global", &self.is_global())?;
97        s.serialize_field("is_private", &self.is_private())?;
98
99        let metadata: Vec<_> = self.metadata().collect();
100        s.serialize_field("metadata", &metadata)?;
101
102        let tags: Vec<_> = self.tags().collect();
103        s.serialize_field("tags", &tags)?;
104
105        let patterns: Vec<_> = self.patterns().include_private(true).collect();
106        s.serialize_field("patterns", &patterns)?;
107
108        s.end()
109    }
110}
111
112/// A metadata value.
113#[derive(Debug, PartialEq, Serialize)]
114#[serde(untagged)]
115pub enum MetaValue<'r> {
116    /// Integer value.
117    Integer(i64),
118    /// Float value.
119    Float(f64),
120    /// Bool value.
121    Bool(bool),
122    /// A valid UTF-8 string.
123    String(&'r str),
124    /// An arbitrary string. Used when the value contains invalid UTF-8
125    /// characters.
126    Bytes(&'r BStr),
127}
128
129/// Iterator that returns the metadata associated to a rule.
130///
131/// The iterator returns (`&str`, [`MetaValue`]) pairs, where the first item
132/// is the identifier, and the second one the metadata value.
133pub struct Metadata<'a, 'r> {
134    rules: &'r Rules,
135    iterator: Iter<'a, (IdentId, compiler::MetaValue)>,
136    len: usize,
137}
138
139impl<'r> Metadata<'_, 'r> {
140    /// Returns the metadata as a [`serde_json::Value`].
141    ///
142    /// The returned value is an array of tuples `(ident, value)` with all
143    /// the metadata associated to the rule.
144    ///
145    /// ```rust
146    /// # use yara_x;
147    /// let rules = yara_x::compile(r#"
148    /// rule test {
149    ///   meta:
150    ///     some_int = 1
151    ///     some_bool = true
152    ///     some_str = "foo"
153    ///     some_bytes = "\x01\x02\x03"
154    ///   condition:
155    ///     true
156    /// }
157    /// "#).unwrap();
158    ///
159    /// let mut scanner = yara_x::Scanner::new(&rules);
160    ///
161    /// let scan_results = scanner
162    ///     .scan(&[])
163    ///     .unwrap();
164    ///
165    /// let matching_rule = scan_results
166    ///     .matching_rules()
167    ///     .next()
168    ///     .unwrap();
169    ///
170    /// assert_eq!(
171    ///     matching_rule.metadata().into_json(),
172    ///     serde_json::json!([
173    ///         ("some_int", 1),
174    ///         ("some_bool", true),
175    ///         ("some_str", "foo"),
176    ///         ("some_bytes", [0x01, 0x02, 0x03]),
177    ///     ])
178    /// );
179    /// ```
180    pub fn into_json(self) -> serde_json::Value {
181        let v: Vec<(&'r str, MetaValue<'r>)> = self.collect();
182        serde_json::value::to_value(v).unwrap()
183    }
184
185    /// Returns `true` if the rule doesn't have any metadata.
186    #[inline]
187    pub fn is_empty(&self) -> bool {
188        self.iterator.len() == 0
189    }
190}
191
192impl<'r> Iterator for Metadata<'_, 'r> {
193    type Item = (&'r str, MetaValue<'r>);
194
195    fn next(&mut self) -> Option<Self::Item> {
196        let (ident_id, value) = self.iterator.next()?;
197
198        let ident = self.rules.ident_pool().get(*ident_id).unwrap();
199
200        let value = match value {
201            compiler::MetaValue::Bool(b) => MetaValue::Bool(*b),
202            compiler::MetaValue::Integer(i) => MetaValue::Integer(*i),
203            compiler::MetaValue::Float(f) => MetaValue::Float(*f),
204            compiler::MetaValue::String(id) => {
205                let s = self.rules.lit_pool().get(*id).unwrap();
206                let s = s.to_str().unwrap();
207                MetaValue::String(s)
208            }
209            compiler::MetaValue::Bytes(id) => {
210                MetaValue::Bytes(self.rules.lit_pool().get(*id).unwrap())
211            }
212        };
213
214        Some((ident, value))
215    }
216}
217
218impl ExactSizeIterator for Metadata<'_, '_> {
219    #[inline]
220    fn len(&self) -> usize {
221        self.len
222    }
223}
224
225/// An iterator that returns the tags defined by a rule.
226pub struct Tags<'a, 'r> {
227    rules: &'r Rules,
228    iterator: Iter<'a, IdentId>,
229    len: usize,
230}
231
232impl Tags<'_, '_> {
233    /// Returns `true` if the rule doesn't have any tags.
234    #[inline]
235    pub fn is_empty(&self) -> bool {
236        self.iterator.len() == 0
237    }
238}
239
240impl<'r> Iterator for Tags<'_, 'r> {
241    type Item = Tag<'r>;
242
243    fn next(&mut self) -> Option<Self::Item> {
244        let ident_id = self.iterator.next()?;
245        Some(Tag { rules: self.rules, ident_id: *ident_id })
246    }
247}
248
249impl ExactSizeIterator for Tags<'_, '_> {
250    #[inline]
251    fn len(&self) -> usize {
252        self.len
253    }
254}
255
256/// Represents a tag defined by a rule.
257pub struct Tag<'r> {
258    rules: &'r Rules,
259    ident_id: IdentId,
260}
261
262impl<'r> Tag<'r> {
263    /// Returns the tag's identifier.
264    pub fn identifier(&self) -> &'r str {
265        self.rules.ident_pool().get(self.ident_id).unwrap()
266    }
267}
268
269impl<'r> Serialize for Tag<'r> {
270    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
271    where
272        S: Serializer,
273    {
274        serializer.serialize_str(self.identifier())
275    }
276}
277
278/// An iterator that returns the patterns defined by a rule.
279///
280/// By default, the iterator yields only public patterns. Use
281/// [`Patterns::include_private`] if you want to include private patterns
282/// as well.
283pub struct Patterns<'a, 'r> {
284    ctx: Option<&'a ScanContext<'r, 'a>>,
285    rules: &'r Rules,
286    iterator: Iter<'a, PatternInfo>,
287    /// True if the iterator should yield all patterns, including the
288    /// private ones. If false, only the non-private patterns are
289    /// yielded.
290    include_private: bool,
291    /// Number of private patterns that remain to be yielded.
292    len_private: usize,
293    /// Number of non-private patterns that remain to be yielded.
294    len_non_private: usize,
295}
296
297impl Patterns<'_, '_> {
298    /// Specifies whether the iterator should yield private patterns.
299    ///
300    /// This does not reset the iterator to its initial state, the iterator will
301    /// continue from its current position.
302    pub fn include_private(mut self, yes: bool) -> Self {
303        self.include_private = yes;
304        self
305    }
306}
307
308impl ExactSizeIterator for Patterns<'_, '_> {
309    #[inline]
310    fn len(&self) -> usize {
311        if self.include_private {
312            self.len_non_private + self.len_private
313        } else {
314            self.len_non_private
315        }
316    }
317}
318
319impl<'a, 'r> Iterator for Patterns<'a, 'r> {
320    type Item = Pattern<'a, 'r>;
321
322    fn next(&mut self) -> Option<Self::Item> {
323        loop {
324            let pattern = self.iterator.next()?;
325
326            if pattern.is_private {
327                self.len_private -= 1;
328            } else {
329                self.len_non_private -= 1;
330            }
331
332            if self.include_private || !pattern.is_private {
333                return Some(Pattern {
334                    ctx: self.ctx,
335                    rules: self.rules,
336                    ident_id: pattern.ident_id,
337                    pattern_id: pattern.pattern_id,
338                    kind: pattern.kind,
339                    is_private: pattern.is_private,
340                });
341            }
342        }
343    }
344}
345
346/// Represents a pattern defined by a rule.
347pub struct Pattern<'a, 'r> {
348    ctx: Option<&'a ScanContext<'r, 'a>>,
349    rules: &'r Rules,
350    ident_id: IdentId,
351    pattern_id: PatternId,
352    kind: PatternKind,
353    is_private: bool,
354}
355
356impl<'a, 'r> Pattern<'a, 'r> {
357    /// Returns the pattern's identifier (e.g: $a, $b).
358    pub fn identifier(&self) -> &'r str {
359        self.rules.ident_pool().get(self.ident_id).unwrap()
360    }
361
362    /// Returns the kind of this pattern.
363    #[inline]
364    pub fn kind(&self) -> PatternKind {
365        self.kind
366    }
367
368    /// Returns true if the pattern is private.
369    #[inline]
370    pub fn is_private(&self) -> bool {
371        self.is_private
372    }
373
374    /// Returns the matches found for this pattern.
375    ///
376    /// The returned matches are affected by [`crate::Scanner::fast_scan`].
377    /// If fast scan mode is enabled, not all matches are guaranteed to be
378    /// returned.
379    pub fn matches(&self) -> Matches<'a, 'r> {
380        Matches {
381            ctx: self.ctx,
382            iterator: self.ctx.and_then(|ctx| {
383                ctx.tracker
384                    .pattern_matches
385                    .get(self.pattern_id)
386                    .map(|matches| matches.iter())
387            }),
388        }
389    }
390}
391
392impl<'a, 'r> Serialize for Pattern<'a, 'r> {
393    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
394    where
395        S: Serializer,
396    {
397        let mut s = serializer.serialize_struct("pattern", 4)?;
398        s.serialize_field("identifier", &self.identifier())?;
399        s.serialize_field("kind", &self.kind())?;
400        s.serialize_field("is_private", &self.is_private())?;
401        let matches: Vec<_> = self.matches().collect();
402        s.serialize_field("matches", &matches)?;
403        s.end()
404    }
405}
406
407/// Iterator that returns the matches for a pattern.
408pub struct Matches<'a, 'r> {
409    ctx: Option<&'a ScanContext<'r, 'a>>,
410    iterator: Option<Iter<'a, scanner::Match>>,
411}
412
413impl<'a, 'r> Iterator for Matches<'a, 'r> {
414    type Item = Match<'a, 'r>;
415
416    fn next(&mut self) -> Option<Self::Item> {
417        let iter = self.iterator.as_mut()?;
418        Some(Match { ctx: self.ctx?, inner: iter.next()? })
419    }
420}
421
422impl ExactSizeIterator for Matches<'_, '_> {
423    fn len(&self) -> usize {
424        self.iterator.as_ref().map_or(0, |it| it.len())
425    }
426}
427
428/// Represents a match.
429pub struct Match<'a, 'r> {
430    ctx: &'a ScanContext<'r, 'a>,
431    inner: &'a scanner::Match,
432}
433
434impl<'a> Match<'a, '_> {
435    /// Range within the original data where the match occurred.
436    #[inline]
437    pub fn range(&self) -> Range<usize> {
438        self.inner.range.clone()
439    }
440
441    /// Slice containing the data that matched.
442    #[inline]
443    pub fn data(&self) -> &'a [u8] {
444        match &self.ctx.scan_state {
445            ScanState::Finished(snippets) => {
446                snippets.get(self.range()).unwrap()
447            }
448            _ => panic!("invalid scan state"),
449        }
450    }
451
452    /// Similar to [`Match::data`] but returns a slice that covers the match
453    /// and some extra bytes at its left and right. The returned range indicates
454    /// the portion of the slice that corresponds to the match itself.
455    ///
456    /// Calling this function only makes sense if [`crate::Scanner::match_context_size`]
457    /// is used for indicating how many bytes at the left and right of each
458    /// match are desired. Otherwise, this function will return the same result
459    /// as [`Match::data`].
460    pub fn data_with_context(&self) -> (&'a [u8], Range<usize>) {
461        match &self.ctx.scan_state {
462            ScanState::Finished(snippets) => snippets
463                .get_with_context(self.range(), self.ctx.match_context_size)
464                .unwrap(),
465            _ => panic!("invalid scan state"),
466        }
467    }
468
469    /// XOR key used for decrypting the data if the pattern had the `xor`
470    /// modifier, or `None` if otherwise.
471    #[inline]
472    pub fn xor_key(&self) -> Option<u8> {
473        self.inner.xor_key
474    }
475}
476
477impl<'a, 'r> Serialize for Match<'a, 'r> {
478    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
479    where
480        S: Serializer,
481    {
482        let mut s = serializer.serialize_struct("match", 2)?;
483        s.serialize_field("range", &self.range())?;
484        s.serialize_field("xor_key", &self.xor_key())?;
485        s.end()
486    }
487}