-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Jan Starke
committed
Sep 8, 2023
1 parent
2eb1b30
commit fb2055b
Showing
5 changed files
with
186 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
use clap::Parser; | ||
use dfir_toolkit::common::HasVerboseFlag; | ||
use log::LevelFilter; | ||
|
||
use crate::output_format::OutputFormat; | ||
|
||
/// Display one or more events from an evtx file | ||
#[derive(Parser)] | ||
#[clap(name=env!("CARGO_BIN_NAME"),author,version,about)] | ||
pub (crate) struct Cli { | ||
/// Name of the evtx file to read from | ||
pub (crate) evtx_file: String, | ||
|
||
/// filter: minimal event record identifier | ||
#[clap(long)] | ||
pub (crate) min: Option<u64>, | ||
|
||
/// filter: maximal event record identifier | ||
#[clap(long)] | ||
pub (crate) max: Option<u64>, | ||
|
||
/// show only the one event with this record identifier | ||
#[clap(short, long)] | ||
pub (crate) id: Option<u64>, | ||
|
||
/// don't display the records in a table format | ||
#[clap(short('T'), long("display-table"))] | ||
pub (crate) show_table: bool, | ||
|
||
/// output format | ||
#[clap(value_enum, short('F'), long("format"), default_value_t = OutputFormat::Xml)] | ||
pub (crate) format: OutputFormat, | ||
|
||
#[clap(flatten)] | ||
verbose: clap_verbosity_flag::Verbosity, | ||
} | ||
|
||
impl HasVerboseFlag for Cli { | ||
fn log_level_filter(&self)-> LevelFilter { | ||
self.verbose.log_level_filter() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
|
||
#[derive(clap::ValueEnum, Clone)] | ||
pub (crate) enum OutputFormat { | ||
Json, | ||
Xml, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
use std::{io::{Read, Seek}, collections::HashMap, fs::File}; | ||
|
||
use evtx::{EvtxParser, SerializedEvtxRecord}; | ||
|
||
use crate::unfiltered::Unfiltered; | ||
|
||
|
||
pub (crate) trait RecordFilter: Sized { | ||
type ReaderType: Read + Seek; | ||
|
||
fn unfiltered(parser: &mut EvtxParser<Self::ReaderType>) -> Unfiltered<Self>; | ||
|
||
fn filter_by_id( | ||
mut parser: EvtxParser<Self::ReaderType>, | ||
filter_id: u64, | ||
) -> (Vec<u64>, HashMap<u64, SerializedEvtxRecord<Self>>) { | ||
let mut record_ids: Vec<u64> = Vec::new(); | ||
let mut records: HashMap<u64, SerializedEvtxRecord<Self>> = HashMap::new(); | ||
if let Some(result) = Self::unfiltered(&mut parser).find(|record| match record { | ||
Ok(evt) => evt.event_record_id == filter_id, | ||
_ => false, | ||
}) { | ||
let evt = result.unwrap(); | ||
record_ids.push(evt.event_record_id); | ||
records.insert(evt.event_record_id, evt); | ||
} | ||
(record_ids, records) | ||
} | ||
|
||
fn filter_by_range( | ||
mut parser: EvtxParser<Self::ReaderType>, | ||
min: u64, | ||
max: u64, | ||
) -> (Vec<u64>, HashMap<u64, SerializedEvtxRecord<Self>>) { | ||
let mut record_ids: Vec<u64> = Vec::new(); | ||
let mut records: HashMap<u64, SerializedEvtxRecord<Self>> = HashMap::new(); | ||
|
||
for record in Self::unfiltered(&mut parser) { | ||
match record { | ||
Err(_) => (), | ||
Ok(evt) => { | ||
let id = evt.event_record_id; | ||
|
||
if id >= min && id <= max { | ||
record_ids.push(id); | ||
records.insert(id, evt); | ||
} | ||
} | ||
} | ||
} | ||
|
||
record_ids.sort_unstable(); | ||
(record_ids, records) | ||
} | ||
} | ||
|
||
impl RecordFilter for serde_json::Value { | ||
type ReaderType = File; | ||
|
||
fn unfiltered(parser: &mut EvtxParser<Self::ReaderType>) -> Unfiltered<Self> { | ||
Unfiltered { | ||
inner: Box::new(parser.records_json_value()), | ||
} | ||
} | ||
} | ||
|
||
impl RecordFilter for String { | ||
type ReaderType = File; | ||
|
||
fn unfiltered(parser: &mut EvtxParser<Self::ReaderType>) -> Unfiltered<Self> { | ||
Unfiltered { | ||
inner: Box::new(parser.records()), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
use std::collections::HashMap; | ||
|
||
use colored_json::to_colored_json_auto; | ||
use evtx::SerializedEvtxRecord; | ||
use term_table::{row::Row, table_cell::TableCell}; | ||
|
||
use crate::cli::Cli; | ||
|
||
pub (crate) trait RecordListFormatter: Sized { | ||
fn format(record: &SerializedEvtxRecord<Self>) -> String; | ||
|
||
fn display_results( | ||
record_ids: Vec<u64>, | ||
records: HashMap<u64, SerializedEvtxRecord<Self>>, | ||
cli: &Cli, | ||
) { | ||
if !cli.show_table { | ||
for id in record_ids.into_iter() { | ||
let record = &records[&id]; | ||
println!("{}", Self::format(record)); | ||
} | ||
} else { | ||
let mut table = term_table::Table::new(); | ||
if let Some(size) = termsize::get() { | ||
table.set_max_column_widths(vec![(0, 12), (1, (size.cols - 16).into())]) | ||
} | ||
|
||
for id in record_ids.into_iter() { | ||
let record = &records[&id]; | ||
table.add_row(Row::new(vec![ | ||
TableCell::new(id), | ||
TableCell::new(Self::format(record)), | ||
])); | ||
} | ||
println!("{}", table.render()); | ||
} | ||
} | ||
} | ||
|
||
impl RecordListFormatter for String { | ||
fn format(record: &SerializedEvtxRecord<Self>) -> String { | ||
record.data.clone() | ||
} | ||
} | ||
|
||
impl RecordListFormatter for serde_json::Value { | ||
fn format(record: &SerializedEvtxRecord<Self>) -> String { | ||
to_colored_json_auto(&record.data).unwrap() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
use evtx::SerializedEvtxRecord; | ||
|
||
pub (crate) struct Unfiltered<'a, V> { | ||
pub (crate) inner: Box<dyn Iterator<Item = evtx::err::Result<SerializedEvtxRecord<V>>> + 'a>, | ||
} | ||
|
||
impl<'a, V> Iterator for Unfiltered<'a, V> { | ||
type Item = evtx::err::Result<SerializedEvtxRecord<V>>; | ||
|
||
fn next(&mut self) -> Option<Self::Item> { | ||
self.inner.next() | ||
} | ||
} |