@@ -5,6 +5,37 @@ use std::{collections::HashMap, sync::Arc};
55use super :: { EvalContext , Module , ModuleData , ModuleDataMap , StaticValue , Type , Value } ;
66
77/// `console` module.
8+ ///
9+ /// To use the module, you must provide a callback which will be called when
10+ /// `console.log` is called.
11+ ///
12+ /// The callback can also be overridden on every scan by specifying a `ConsoleData`
13+ /// in the scanner.
14+ ///
15+ /// ```
16+ /// use boreal::module::{Console, ConsoleData};
17+ /// use boreal::compiler::CompilerBuilder;
18+ ///
19+ /// let mut compiler = CompilerBuilder::new()
20+ /// // Do not log anything by default
21+ /// .add_module(Console::with_callback(|_log| {}))
22+ /// .build();
23+ /// compiler.add_rules_str(r#"
24+ /// import "console"
25+ ///
26+ /// rule a {
27+ /// condition: console.log("one")
28+ /// }"#).unwrap();
29+ /// let mut scanner = compiler.into_scanner();
30+ ///
31+ /// scanner.scan_mem(b""); // Will not log anything
32+ ///
33+ /// let console_data = ConsoleData::new(|log| {
34+ /// println!("yara console log: {log}");
35+ /// });
36+ /// scanner.set_module_data::<Console>(console_data);
37+ /// scanner.scan_mem(b""); // Will log "yara console log: one"
38+ /// ```
839pub struct Console {
940 callback : Arc < LogCallback > ,
1041}
@@ -47,19 +78,40 @@ impl Module for Console {
4778 }
4879
4980 fn setup_new_scan ( & self , data_map : & mut ModuleDataMap ) {
50- data_map. insert :: < Self > ( Data {
81+ data_map. insert :: < Self > ( PrivateData {
5182 callback : Arc :: clone ( & self . callback ) ,
5283 } ) ;
5384 }
5485}
5586
56- pub struct Data {
87+ pub struct PrivateData {
5788 callback : Arc < LogCallback > ,
5889}
5990
6091impl ModuleData for Console {
61- type PrivateData = Data ;
62- type UserData = ( ) ;
92+ type PrivateData = PrivateData ;
93+ type UserData = ConsoleData ;
94+ }
95+
96+ /// Data used by the console module.
97+ ///
98+ /// This data can be provided by a call to
99+ /// [`Scanner::set_module_data`](crate::scanner::Scanner::set_module_data) to override
100+ /// the default callback that was specified when compiling rules.
101+ pub struct ConsoleData {
102+ callback : Box < LogCallback > ,
103+ }
104+
105+ impl ConsoleData {
106+ /// Provide a callback called when console.log is evaluted in rules.
107+ pub fn new < T > ( callback : T ) -> Self
108+ where
109+ T : Fn ( String ) + Send + Sync + UnwindSafe + RefUnwindSafe + ' static ,
110+ {
111+ Self {
112+ callback : Box :: new ( callback) ,
113+ }
114+ }
63115}
64116
65117impl Console {
@@ -85,8 +137,7 @@ impl Console {
85137 add_value ( arg, & mut res) ?;
86138 }
87139
88- let data = ctx. module_data . get :: < Console > ( ) ?;
89- ( data. callback ) ( res) ;
140+ call_callback ( ctx, res) ?;
90141
91142 Some ( Value :: Integer ( 1 ) )
92143 }
@@ -104,13 +155,24 @@ impl Console {
104155 }
105156 } ;
106157
107- let data = ctx. module_data . get :: < Console > ( ) ?;
108- ( data. callback ) ( res) ;
158+ call_callback ( ctx, res) ?;
109159
110160 Some ( Value :: Integer ( 1 ) )
111161 }
112162}
113163
164+ fn call_callback ( ctx : & EvalContext , log : String ) -> Option < ( ) > {
165+ // First, check if there is a callback specified for this scan.
166+ if let Some ( data) = ctx. module_data . get_user_data :: < Console > ( ) {
167+ ( data. callback ) ( log) ;
168+ } else {
169+ // Otherwise, use the callback specified when building the module.
170+ let data = ctx. module_data . get :: < Console > ( ) ?;
171+ ( data. callback ) ( log) ;
172+ }
173+ Some ( ( ) )
174+ }
175+
114176fn add_value ( value : Value , out : & mut String ) -> Option < ( ) > {
115177 match value {
116178 Value :: Integer ( v) => write ! ( out, "{v}" ) . ok ( ) ,
0 commit comments