Skip to content

Commit

Permalink
Implement count for JSON output.
Browse files Browse the repository at this point in the history
This makes -c work with the ndjson output format. While I'm here, refactor the
walker function, which was getting a bit too large. Now it calls a separate
function for processing results which will call the appropriate output
functions.
  • Loading branch information
wxsBSD committed Aug 7, 2024
1 parent 77020a1 commit 37d9ad7
Showing 1 changed file with 61 additions and 45 deletions.
106 changes: 61 additions & 45 deletions cli/src/commands/scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use superconsole::style::Stylize;
use superconsole::{Component, Line, Lines, Span};
use yansi::Color::{Cyan, Red, Yellow};
use yansi::Paint;
use yara_x::{MetaValue, Rule, Rules, ScanError, Scanner};
use yara_x::{MetaValue, Rule, Rules, ScanError, ScanResults, Scanner};

use crate::commands::{
compile_rules, external_var_parser, truncate_with_ellipsis,
Expand Down Expand Up @@ -158,8 +158,6 @@ pub fn exec_scan(args: &ArgMatches) -> anyhow::Result<()> {
let num_threads = args.get_one::<u8>("threads");
let path_as_namespace = args.get_flag("path-as-namespace");
let skip_larger = args.get_one::<u64>("skip-larger");
let negate = args.get_flag("negate");
let count = args.get_flag("count");
let disable_console_logs = args.get_flag("disable-console-logs");
let scan_list = args.get_flag("scan-list");

Expand Down Expand Up @@ -302,50 +300,17 @@ pub fn exec_scan(args: &ArgMatches) -> anyhow::Result<()> {
.retain(|(p, _)| !file_path.eq(p));

let scan_results = scan_results?;

if count {
// The behavior of original YARA is to ignore things like -n and
// -t when using -c so we are doing it here also.
let match_count = scan_results.matching_rules().len();
let line = format!(
"{}: {}",
&file_path.display().to_string(),
match_count
);
output.send(Message::Info(line)).unwrap();

// Update the total number of matching, so the "summary" is
// correct at the end of the run.
if match_count > 0 {
state
.num_matching_files
.fetch_add(match_count, Ordering::Relaxed);
}
} else if negate {
let mut matching_rules = scan_results.non_matching_rules();
if matching_rules.len() > 0 {
state.num_matching_files.fetch_add(1, Ordering::Relaxed);
}
print_matching_rules(
args,
&file_path,
&mut matching_rules,
output,
);
} else {
let mut matching_rules = scan_results.matching_rules();
if matching_rules.len() > 0 {
state.num_matching_files.fetch_add(1, Ordering::Relaxed);
}
print_matching_rules(
args,
&file_path,
&mut matching_rules,
output,
);
};
let matched_count = process_scan_results(
&args,
&file_path,
&scan_results,
&output,
);

state.num_scanned_files.fetch_add(1, Ordering::Relaxed);
if matched_count > 0 {
state.num_matching_files.fetch_add(1, Ordering::Relaxed);
}

Ok(())
},
Expand Down Expand Up @@ -664,6 +629,57 @@ impl ScanState {
}
}

// Process scan results and output matches, non-matches, or count of matches
// based upon command line arguments. Return the number of "matched" files so
// the state can be updated.
fn process_scan_results(
args: &ArgMatches,
file_path: &Path,
scan_results: &ScanResults,
output: &Sender<Message>,
) -> usize {
let negate = args.get_flag("negate");
let count = args.get_flag("count");

if count {
// The behavior of original YARA is to ignore things like -n and
// -t when using -c so we are doing it here also.
let match_count = scan_results.matching_rules().len();
print_match_count(args, file_path, &match_count, output);
return match_count;
} else if negate {
let mut matching_rules = scan_results.non_matching_rules();
let match_count = matching_rules.len();
print_matching_rules(args, &file_path, &mut matching_rules, output);
return match_count;
} else {
let mut matching_rules = scan_results.matching_rules();
let match_count = matching_rules.len();
print_matching_rules(args, &file_path, &mut matching_rules, output);
return match_count;
};
}

fn print_match_count(
args: &ArgMatches,
file_path: &Path,
count: &usize,
output: &Sender<Message>,
) {
let line = match args.get_one::<OutputFormats>("output-format") {
Some(OutputFormats::Ndjson) => {
format!(
"{}",
serde_json::json!({"path": file_path.to_str().unwrap(), "count": count})
)
}
Some(OutputFormats::Text) | None => {
format!("{}: {}", &file_path.display().to_string(), count)
}
};
output.send(Message::Info(line)).unwrap();
}

// superconsole will not print any string that contains Unicode characters that
// are spaces but are not the ASCII space character, so we replace them all.
// See https://github.com/VirusTotal/yara-x/pull/163 for discussion.
Expand Down

0 comments on commit 37d9ad7

Please sign in to comment.