diff --git a/Cargo.lock b/Cargo.lock index cb982884..cab6a4bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -773,7 +773,6 @@ dependencies = [ "hashbrown", "hhmmss", "lazy_static", - "linecount", "linked-hash-map", "mopa", "num_cpus", @@ -1016,12 +1015,6 @@ version = "0.2.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" -[[package]] -name = "linecount" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d5a4a243b9cf052d37af99679cc93b08a791f444a4a1b21bb4efcaf01847d8" - [[package]] name = "linked-hash-map" version = "0.5.3" diff --git a/Cargo.toml b/Cargo.toml index 7d74f4f5..af29763b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,6 @@ dotenv = "0.15.0" hhmmss = "*" pbr = "*" hashbrown = "0.11.2" -linecount = "*" [target.x86_64-pc-windows-gnu] linker = "x86_64-w64-mingw32-gcc" diff --git a/src/afterfact.rs b/src/afterfact.rs index 4275cf7e..8cbe21a5 100644 --- a/src/afterfact.rs +++ b/src/afterfact.rs @@ -189,8 +189,6 @@ where mod tests { use crate::afterfact::emit_csv; use crate::detections::print; - use crate::detections::print::AlertMessage; - use crate::detections::print::ERROR_LOG_PATH; use chrono::{Local, TimeZone, Utc}; use serde_json::Value; use std::fs::File; @@ -205,7 +203,6 @@ mod tests { } fn test_emit_csv_output() { - AlertMessage::create_error_log(ERROR_LOG_PATH.to_string()); let testfilepath: &str = "test.evtx"; let testrulepath: &str = "test-rule.yml"; let test_title = "test_title"; diff --git a/src/detections/configs.rs b/src/detections/configs.rs index 492f209e..06f60e3d 100644 --- a/src/detections/configs.rs +++ b/src/detections/configs.rs @@ -68,7 +68,6 @@ fn build_app<'a>() -> ArgMatches<'a> { -t --thread-number=[NUMBER] 'Thread number (default: optimal number for performance)' -s --statistics 'Prints statistics of event IDs' -q --quiet 'Quiet mode. Do not display the launch banner' - -Q --quiet-errors 'Quiet errors mode. Do not display errors or save error logs' --contributors 'Prints the list of contributors'"; App::new(&program) .about("Hayabusa: Aiming to be the world's greatest Windows event log analysis tool!") @@ -141,7 +140,7 @@ impl TargetEventTime { Err(err) => { AlertMessage::alert( &mut std::io::stderr().lock(), - format!("start-timeline field: {}", err), + format!("starttimeline field: {}", err), ) .ok(); None @@ -158,7 +157,7 @@ impl TargetEventTime { Err(err) => { AlertMessage::alert( &mut std::io::stderr().lock(), - format!("end-timeline field: {}", err), + format!("endtimeline field: {}", err), ) .ok(); None diff --git a/src/detections/detection.rs b/src/detections/detection.rs index 30a90572..d63a73e8 100644 --- a/src/detections/detection.rs +++ b/src/detections/detection.rs @@ -1,7 +1,6 @@ extern crate csv; use crate::detections::print::AlertMessage; -use crate::detections::print::ERROR_LOG_PATH; use crate::detections::print::MESSAGES; use crate::detections::rule; use crate::detections::rule::AggResult; @@ -12,8 +11,6 @@ use crate::yaml::ParseYaml; use hashbrown; use serde_json::Value; use std::collections::HashMap; -use std::fs::OpenOptions; -use std::io::BufWriter; use tokio::{runtime::Runtime, spawn, task::JoinHandle}; use std::sync::Arc; @@ -61,12 +58,7 @@ impl Detection { rulefile_loader.read_dir(rulespath.unwrap_or(DIRPATH_RULES), &level, exclude_ids); if result_readdir.is_err() { AlertMessage::alert( - &mut BufWriter::new( - OpenOptions::new() - .append(true) - .open(ERROR_LOG_PATH.to_string()) - .unwrap(), - ), + &mut std::io::stderr().lock(), format!("{}", result_readdir.unwrap_err()), ) .ok(); diff --git a/src/detections/print.rs b/src/detections/print.rs index 810f61ba..594aa504 100644 --- a/src/detections/print.rs +++ b/src/detections/print.rs @@ -2,20 +2,13 @@ extern crate lazy_static; use crate::detections::configs; use crate::detections::utils; use crate::detections::utils::get_serde_number_to_string; -use chrono::{DateTime, Local, TimeZone, Utc}; +use chrono::{DateTime, TimeZone, Utc}; use lazy_static::lazy_static; -use linecount::count_lines; use regex::Regex; use serde_json::Value; use std::collections::BTreeMap; use std::collections::HashMap; -use std::env; -use std::fs::create_dir; -use std::fs::remove_file; -use std::fs::File; -use std::io::BufWriter; use std::io::{self, Write}; -use std::path::Path; use std::sync::Mutex; #[derive(Debug)] @@ -39,15 +32,6 @@ pub struct AlertMessage {} lazy_static! { pub static ref MESSAGES: Mutex = Mutex::new(Message::new()); pub static ref ALIASREGEX: Regex = Regex::new(r"%[a-zA-Z0-9-_]+%").unwrap(); - pub static ref ERROR_LOG_PATH: String = format!( - "./logs/errorlog-{}.log", - Local::now().format("%Y%m%d_%H%M%S") - ); - pub static ref QUIET_ERRORS_FLAG: bool = configs::CONFIG - .read() - .unwrap() - .args - .is_present("quiet-errors"); } impl Message { @@ -196,68 +180,11 @@ impl Message { } impl AlertMessage { - //対象のディレクトリが存在することを確認後、最初の定型文を追加して、ファイルのbufwriterを返す関数 - pub fn create_error_log(path_str: String) { - let path = Path::new(&path_str); - if !path.parent().unwrap().exists() { - create_dir(path.parent().unwrap()).ok(); - } - // 1行目は必ず実行したコマンド情報を入れておく。 - let mut ret = BufWriter::new(File::create(path).unwrap()); - - ret.write( - format!( - "user input: {:?}\n", - format_args!( - "{}", - env::args() - .map(|arg| arg) - .collect::>() - .join(" ") - ) - ) - .as_bytes(), - ) - .unwrap(); - ret.flush().ok(); - } - - /// ERRORメッセージを表示する関数。error_log_flagでfalseの場合は外部へのエラーログの書き込みは行わずに指定されたwを用いた出力のみ行う。trueの場合はwを用いた出力を行わずにエラーログへの出力を行う pub fn alert(w: &mut W, contents: String) -> io::Result<()> { - if *QUIET_ERRORS_FLAG { - writeln!(w, "[ERROR] {}", contents) - } else { - Ok(()) - } + writeln!(w, "[ERROR] {}", contents) } - - // WARNメッセージを表示する関数 pub fn warn(w: &mut W, contents: String) -> io::Result<()> { - if *QUIET_ERRORS_FLAG { - writeln!(w, "[WARN] {}", contents) - } else { - Ok(()) - } - } - - /// エラーログへのERRORメッセージの出力数を確認して、0であったらファイルを削除する。1以上あればエラーを書き出した旨を標準出力に表示する - pub fn output_error_log_exist() { - let error_log_path_str = ERROR_LOG_PATH.to_string(); - // 1行しかなかった場合は最初に書いたコマンド情報のみと判断して削除する - if count_lines(File::open(&error_log_path_str).unwrap()).unwrap() == 1 { - if remove_file(&error_log_path_str).is_err() { - AlertMessage::alert( - &mut std::io::stderr().lock(), - format!("failed to remove file. filepath:{}", &error_log_path_str), - ) - .ok(); - } - return; - } - println!( - "Generated error was output to {}. Please see the file for details.", - &error_log_path_str - ); + writeln!(w, "[WARN] {}", contents) } } diff --git a/src/detections/rule/count.rs b/src/detections/rule/count.rs index 6b161296..c675589a 100644 --- a/src/detections/rule/count.rs +++ b/src/detections/rule/count.rs @@ -1,5 +1,4 @@ use crate::detections::print::AlertMessage; -use crate::detections::print::ERROR_LOG_PATH; use crate::detections::rule::AggResult; use crate::detections::rule::AggregationParseInfo; use crate::detections::rule::Message; @@ -7,8 +6,6 @@ use crate::detections::rule::RuleNode; use chrono::{DateTime, TimeZone, Utc}; use hashbrown::HashMap; use serde_json::Value; -use std::fs::OpenOptions; -use std::io::BufWriter; use std::num::ParseIntError; use std::path::Path; @@ -186,12 +183,7 @@ impl TimeFrameInfo { tnum.retain(|c| c != 'd'); } else { AlertMessage::alert( - &mut BufWriter::new( - OpenOptions::new() - .append(true) - .open(ERROR_LOG_PATH.to_string()) - .unwrap(), - ), + &mut std::io::stderr().lock(), format!("Timeframe is invalid. Input value:{}", value), ) .ok(); @@ -223,13 +215,8 @@ pub fn get_sec_timeframe(timeframe: &Option) -> Option { } Err(err) => { AlertMessage::alert( - &mut BufWriter::new( - OpenOptions::new() - .append(true) - .open(ERROR_LOG_PATH.to_string()) - .unwrap(), - ), - format!("Timeframe number is invalid. timeframe: {}", err), + &mut std::io::stderr().lock(), + format!("Timeframe number is invalid. timeframe.{}", err), ) .ok(); return Option::None; diff --git a/src/main.rs b/src/main.rs index 087ba29c..50abee7d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,6 @@ use chrono::{DateTime, Local}; use evtx::{EvtxParser, ParserSettings}; use hayabusa::detections::detection::{self, EvtxRecordInfo}; use hayabusa::detections::print::AlertMessage; -use hayabusa::detections::print::ERROR_LOG_PATH; use hayabusa::detections::rule::{get_detection_keys, RuleNode}; use hayabusa::filter; use hayabusa::omikuji::Omikuji; @@ -17,9 +16,6 @@ use pbr::ProgressBar; use serde_json::Value; use std::collections::{HashMap, HashSet}; use std::fmt::Display; -use std::fs::OpenOptions; -use std::io::BufWriter; -use std::path::Path; use std::sync::Arc; use std::{ fs::{self, File}, @@ -70,17 +66,6 @@ impl App { ); return; } - if let Some(csv_path) = configs::CONFIG.read().unwrap().args.value_of("output") { - if Path::new(csv_path).exists() { - AlertMessage::alert( - &mut std::io::stderr().lock(), - " file name in --output already exist other file. Please input unique file path.".to_owned(), - ) - .ok(); - return; - } - } - AlertMessage::create_error_log(ERROR_LOG_PATH.to_string()); if let Some(filepath) = configs::CONFIG.read().unwrap().args.value_of("filepath") { if !filepath.ends_with(".evtx") { AlertMessage::alert( @@ -115,22 +100,14 @@ impl App { let analysis_duration = analysis_end_time.signed_duration_since(analysis_start_time); println!("Elapsed Time: {}", &analysis_duration.hhmmssxxx()); println!(""); - AlertMessage::output_error_log_exist(); } fn collect_evtxfiles(&self, dirpath: &str) -> Vec { let entries = fs::read_dir(dirpath); if entries.is_err() { - AlertMessage::alert( - &mut BufWriter::new( - OpenOptions::new() - .append(true) - .open(ERROR_LOG_PATH.to_string()) - .unwrap(), - ), - format!("{}", entries.unwrap_err()), - ) - .ok(); + let stderr = std::io::stderr(); + let mut stderr = stderr.lock(); + AlertMessage::alert(&mut stderr, format!("{}", entries.unwrap_err())).ok(); return vec![]; } @@ -194,8 +171,6 @@ impl App { pb.inc(); } after_fact(); - println!(""); - AlertMessage::output_error_log_exist(); } // Windowsイベントログファイルを1ファイル分解析する。 @@ -231,16 +206,7 @@ impl App { evtx_filepath, record_result.unwrap_err() ); - AlertMessage::alert( - &mut BufWriter::new( - OpenOptions::new() - .append(true) - .open(ERROR_LOG_PATH.to_string()) - .unwrap(), - ), - errmsg, - ) - .ok(); + AlertMessage::alert(&mut std::io::stderr().lock(), errmsg).ok(); continue; } diff --git a/src/yaml.rs b/src/yaml.rs index 9c389714..4411afb2 100644 --- a/src/yaml.rs +++ b/src/yaml.rs @@ -3,14 +3,11 @@ extern crate yaml_rust; use crate::detections::configs; use crate::detections::print::AlertMessage; -use crate::detections::print::ERROR_LOG_PATH; use crate::filter::RuleExclude; use std::collections::HashMap; use std::ffi::OsStr; use std::fs; -use std::fs::OpenOptions; use std::io; -use std::io::BufWriter; use std::io::{BufReader, Read}; use std::path::{Path, PathBuf}; use yaml_rust::Yaml; @@ -75,12 +72,7 @@ impl ParseYaml { let read_content = self.read_file(path); if read_content.is_err() { AlertMessage::warn( - &mut BufWriter::new( - OpenOptions::new() - .append(true) - .open(ERROR_LOG_PATH.to_string()) - .unwrap(), - ), + &mut std::io::stdout().lock(), format!( "fail to read file: {}\n{} ", entry.path().display(), @@ -95,12 +87,7 @@ impl ParseYaml { let yaml_contents = YamlLoader::load_from_str(&read_content.unwrap()); if yaml_contents.is_err() { AlertMessage::warn( - &mut BufWriter::new( - OpenOptions::new() - .append(true) - .open(ERROR_LOG_PATH.to_string()) - .unwrap(), - ), + &mut std::io::stdout().lock(), format!( "Failed to parse yml: {}\n{} ", entry.path().display(),