Skip to content

Commit

Permalink
Merge pull request #24 from dfir-dd/23-usage-of-pure-rust-scca-library
Browse files Browse the repository at this point in the history
23 usage of pure rust scca library
  • Loading branch information
Bitbee0 authored Feb 13, 2024
2 parents 798ca37 + 78d684c commit 5b5e483
Show file tree
Hide file tree
Showing 18 changed files with 125 additions and 624 deletions.
5 changes: 1 addition & 4 deletions .github/workflows/cargo_publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: Install required libscca-dev
run: sudo apt install -y libscca-dev


- uses: actions-rs/toolchain@v1
with:
toolchain: stable
Expand Down
3 changes: 0 additions & 3 deletions .github/workflows/cargo_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ jobs:
steps:
- uses: actions/checkout@v2

- name: Install required libscca-dev
run: sudo apt install -y libscca-dev

- uses: actions-rs/toolchain@v1
with:
toolchain: stable
Expand Down
3 changes: 0 additions & 3 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ jobs:
steps:

- uses: actions/checkout@v1

- name: Install required libscca-dev
run: sudo apt install -y libscca-dev

- uses: actions-rs/toolchain@v1
with:
Expand Down
3 changes: 0 additions & 3 deletions .github/workflows/rust-clippy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ jobs:
toolchain: stable
components: clippy
override: true

- name: Install required libscca-dev
run: sudo apt install -y libscca-dev

- name: Install required cargo
run: cargo install clippy-sarif sarif-fmt
Expand Down
24 changes: 23 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "dfir-toolkit"
version = "0.10.0"
version = "0.10.1"
edition = "2021"
authors = ["Jan Starke <jan.starke@posteo.de>", "Deborah Mahn <deborah.mahn@dfir-dd.de>"]
description = "CLI tools for digital forensics and incident response"
Expand Down Expand Up @@ -99,7 +99,7 @@ evtx2bodyfile = ["evtx", "getset", "ouroboros", "indicatif"]
ipgrep = []
ts2date = ["regex"]
lnk2bodyfile = ["lnk"]
pf2bodyfile = ["num", "libc"]
pf2bodyfile = ["num", "libc", "frnsc-prefetch", "forensic-rs"]

regdump = ["nt_hive2"]
hivescan = ["nt_hive2"]
Expand Down Expand Up @@ -176,6 +176,8 @@ lnk = {version="0.5.1", optional=true}
# pf2bodyfile
libc = {version="0.2", optional=true}
num = {version="0", optional=true}
frnsc-prefetch = {version="0.9", optional=true}
forensic-rs = {version="0.9.1", optional=true}

[dev-dependencies]

Expand Down
8 changes: 6 additions & 2 deletions src/bin/pf2bodyfile/cli.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use clap::Parser;
use clap::ValueHint;
use clio::Input;
use clio::ClioPath;
use dfir_toolkit::common::HasVerboseFlag;
use getset::Getters;
use log::LevelFilter;
Expand All @@ -12,7 +12,11 @@ use log::LevelFilter;
pub(crate) struct Cli {
/// names of the prefetch files (commonly files with 'pf' extension in 'C:\Windows\Prefetch')
#[clap(value_hint=ValueHint::FilePath)]
prefetch_files: Vec<Input>,
prefetch_files: Vec<ClioPath>,

/// show not only the executed files, but all references files -- such as libraries -- as well
#[clap(short='I')]
include_metrics: bool,

#[clap(flatten)]
verbose: clap_verbosity_flag::Verbosity,
Expand Down
99 changes: 77 additions & 22 deletions src/bin/pf2bodyfile/main.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,93 @@
mod cli;

use cli::Cli;
use dfir_toolkit::common::bodyfile::Bodyfile3Line;
use dfir_toolkit::common::FancyParser;
use dfir_toolkit::scca::File;
use forensic_rs::prelude::*;
use frnsc_prefetch::prelude::*;
use log::{error, warn};
use std::path::Path;

fn main() -> anyhow::Result<()> {
let cli = Cli::parse_cli();

if cli.prefetch_files().iter().any(|f| !f.can_seek()) {
anyhow::bail!(
"{} cannot read from a stream; you must specify a file",
env!("CARGO_BIN_NAME")
);
if cli.prefetch_files().iter().any(|f| !f.path().exists()) {
anyhow::bail!("some files you specified do not exist");
}

if cli.prefetch_files().iter().any(|f| ! f.path().is_file()) {
anyhow::bail!(
"{} you must specify a file",
env!("CARGO_BIN_NAME")
);
if cli.prefetch_files().iter().any(|f| !f.path().is_file()) {
anyhow::bail!("some paths you specified are no files");
}

let vfs = Box::new(StdVirtualFS::new());

for input in cli.prefetch_files().iter() {
let path = input.path().as_os_str().to_string_lossy();
let pf_file = input.path().file_name().unwrap().to_string_lossy();
let file = File::open(&path)?;
let executable = file.utf8_executable_filename()?;
let run_count = file.run_count()?;
for time in file.last_run_times()? {
match input.parent() {
Some(parent) => {
let mut fs = ChRootFileSystem::new(parent, vfs.clone());
if let Some(pf_os_filename) = input.path().file_name() {
if let Some(pf_filename) = pf_os_filename.to_str() {
let pf_file = read_prefetch_file(
pf_filename,
fs.open(Path::new(&pf_filename.to_string()))?,
)?;

pf_file.display_prefetch_file(pf_filename, *cli.include_metrics())?;
} else {
error!("invalid Unicode characters in filename: '{pf_os_filename:?}'")
}
} else {
warn!("unable to handle directories; you must specify concrete file names");
}
}
None => {
error!("specified path has no parent: {input}")
}
}
}
Ok(())
}

trait DisplayPrefetchFile {
fn display_prefetch_file(
&self,
pf_file_name: &str,
include_metrics: bool,
) -> anyhow::Result<()>;
}

impl DisplayPrefetchFile for PrefetchFile {
fn display_prefetch_file(
&self,
pf_file_name: &str,
include_metrics: bool,
) -> anyhow::Result<()> {
for time in &self.last_run_times {
let accessed =
winstructs::timestamp::WinTimestamp::new(&time.filetime().to_le_bytes())?
.to_datetime()
.into();

let bf_line = Bodyfile3Line::new()
.with_owned_name(format!("Prefetch: '{executable}' (run {run_count} times, read from '{pf_file}')"))
.with_atime(time.into());
.with_owned_name(format!(
"Prefetch: run '{}' (run {} times, read from '{pf_file_name}')",
self.name, self.run_count
))
.with_atime(accessed);
println!("{bf_line}");

if include_metrics {
for metric in &self.metrics {
let mf = &metric.file;
let bf_line = Bodyfile3Line::new()
.with_owned_name(format!(
"Prefetch: running '{} possibly loaded '{mf}', read from '{pf_file_name}')",
self.name
))
.with_atime(accessed);
println!("{bf_line}");
}
}
}
Ok(())
}
Ok(())
}
}
8 changes: 4 additions & 4 deletions src/common/bodyfile/times.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ use crate::common::bodyfile::Bodyfile3ParserError;
use std::fmt::Display;
use chrono::{DateTime, NaiveDateTime, Utc};

#[derive(Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd)]
pub struct Accessed(Option<i64>);
#[derive(Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd)]
pub struct Modified(Option<i64>);
#[derive(Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd)]
pub struct Changed(Option<i64>);
#[derive(Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd)]
pub struct Created(Option<i64>);

pub trait BehavesLikeI64: From<i64> + From<Option<i64>> {
Expand Down
16 changes: 10 additions & 6 deletions src/common/forensics_timestamp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ lazy_static! {
eprintln!();
eprintln!("Please take a look at");
eprintln!();
eprintln!(" <https://docs.rs/chrono/latest/chrono/format/strftime/index.html>");
eprintln!(
" <https://docs.rs/chrono/latest/chrono/format/strftime/index.html>"
);
eprintln!();
eprintln!("to see which format strings are accepted.");
eprintln!();
Expand All @@ -28,7 +30,8 @@ lazy_static! {
}
};
static ref ZERO: DateTime<FixedOffset> =
DateTime::<FixedOffset>::parse_from_rfc3339("0000-00-00T00:00:00+00:00").unwrap();
DateTime::<FixedOffset>::parse_from_rfc3339("0000-00-00T00:00:00+00:00")
.expect("unable to parse literal timestamp");
}

pub struct ForensicsTimestamp {
Expand Down Expand Up @@ -63,10 +66,11 @@ impl ForensicsTimestamp {
impl Display for ForensicsTimestamp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.unix_ts >= 0 {
let src_timestamp = match self
.src_zone
.from_local_datetime(&NaiveDateTime::from_timestamp_opt(self.unix_ts, 0).unwrap())
{
let src_timestamp = match self.src_zone.from_local_datetime(
&NaiveDateTime::from_timestamp_opt(self.unix_ts, 0).unwrap_or_else(|| {
panic!("unable to convert '{}' into unix timestamp", self.unix_ts)
}),
) {
LocalResult::None => {
panic!("INVALID DATETIME");
}
Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
pub mod registry;
pub mod common;
pub mod evtx;
pub mod scca;

#[cfg(feature="elastic")]
pub mod es4forensics;
5 changes: 0 additions & 5 deletions src/scca/access_flags.rs

This file was deleted.

Loading

0 comments on commit 5b5e483

Please sign in to comment.