diff --git a/Cargo.lock b/Cargo.lock index 8927443..2126cf6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "anstream" -version = "0.6.17" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -95,9 +95,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.1.34" +version = "1.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b9470d453346108f93a59222a9a1a5724db32d0a4727b7ab7ace4b4d822dc9" +checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf" dependencies = [ "shlex", ] @@ -203,9 +203,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" [[package]] name = "heck" @@ -231,9 +231,9 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "libc" -version = "0.2.161" +version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" [[package]] name = "malware-traces-generator" @@ -244,6 +244,8 @@ dependencies = [ "embed-resource", "rand", "regex_generate", + "serde", + "toml", "windows", ] diff --git a/Cargo.toml b/Cargo.toml index 9adc939..f12f113 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,8 @@ base64 = { version = "0.22.1" } clap = { version = "4.5.20", features = ["derive"] } rand = "0.8.5" regex_generate = "0.2.3" +toml = "0.8.19" +serde = { version = "1.0.214", features = ["derive"] } [build-dependencies] embed-resource = "2.5.0" diff --git a/src/cli.rs b/src/cli.rs deleted file mode 100644 index 809dd46..0000000 --- a/src/cli.rs +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-FileCopyrightText: 2023 The MalwareTracesGenerator development team -// -// SPDX-License-Identifier: GPL-3.0-or-later - -use crate::traces::Traces; -use clap::{Parser, Subcommand}; - -#[derive(Debug, Parser)] -#[clap(author, version)] -#[clap(arg_required_else_help = true)] -pub struct Arguments { - #[clap(subcommand)] - pub command: Commands, -} - -#[derive(Debug, Subcommand)] -pub enum Commands { - Traces(Traces), -} diff --git a/src/commands.rs b/src/commands.rs new file mode 100644 index 0000000..8835879 --- /dev/null +++ b/src/commands.rs @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: 2023 The MalwareTracesGenerator development team +// +// SPDX-License-Identifier: GPL-3.0-or-later + +pub mod generate; +pub mod traces; + +use crate::commands::{generate::Generate, traces::Traces}; +use clap::{Parser, Subcommand}; +use std::error::Error; + +#[derive(Parser)] +#[clap(author, version)] +#[clap(arg_required_else_help = true)] +pub struct Arguments { + #[clap(subcommand)] + pub command: Command, +} + +#[derive(Subcommand)] +pub enum Command { + Traces(Traces), + Generate(Generate), +} + +pub trait Runnable { + fn run(&self) -> Result<(), Box>; +} + +impl Runnable for Arguments { + fn run(&self) -> Result<(), Box> { + match &self.command { + Command::Traces(traces) => traces as &dyn Runnable, + Command::Generate(generate) => generate, + } + .run() + } +} diff --git a/src/commands/generate.rs b/src/commands/generate.rs new file mode 100644 index 0000000..d70130c --- /dev/null +++ b/src/commands/generate.rs @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2023 The MalwareTracesGenerator development team +// +// SPDX-License-Identifier: GPL-3.0-or-later + +use crate::commands::{traces::Traces, Runnable}; +use clap::Parser; +use serde::Deserialize; +use std::{error::Error, fs::read_to_string, path::PathBuf}; +use toml::from_str; + +#[derive(Deserialize)] +struct Configuration { + metadata: Metadata, + traces: Vec, +} + +#[derive(Deserialize)] +struct Metadata { + name: String, + version: String, + references: Vec, + authors: Option>, +} + +#[derive(Deserialize)] +struct Author { + name: String, + email: Option, +} + +#[derive(Parser)] +pub struct Generate { + #[clap(required = true, help = "Path to the configuration file")] + path: PathBuf, +} + +impl Runnable for Generate { + fn run(&self) -> Result<(), Box> { + if !self.path.try_exists()? || !self.path.is_file() { + return Ok(()); + } + + let configuration: Configuration = from_str(read_to_string(self.path.clone())?.as_str())?; + + for trace in configuration.traces { + trace.run()?; + } + + Ok(()) + } +} diff --git a/src/traces.rs b/src/commands/traces.rs similarity index 52% rename from src/traces.rs rename to src/commands/traces.rs index 348620b..00450e7 100644 --- a/src/traces.rs +++ b/src/commands/traces.rs @@ -2,34 +2,36 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -use crate::traces::{drivers::Drivers, processes::Processes}; +use crate::commands::{ + traces::{drivers::Drivers, processes::Processes}, + Runnable, +}; use clap::{Args, Subcommand}; +use serde::Deserialize; use std::error::Error; pub mod drivers; pub mod processes; -#[derive(Debug, Args)] +#[derive(Args, Deserialize)] pub struct Traces { #[clap(subcommand)] - pub command: Commands, + #[serde(flatten)] + pub command: Command, } -#[derive(Debug, Subcommand)] -pub enum Commands { +#[derive(Subcommand, Deserialize)] +#[serde(rename_all = "snake_case", untagged)] +pub enum Command { Drivers(Drivers), Processes(Processes), } -pub trait Runnable { - fn run(&self) -> Result<(), Box>; -} - impl Runnable for Traces { fn run(&self) -> Result<(), Box> { match &self.command { - Commands::Drivers(drivers) => drivers as &dyn Runnable, - Commands::Processes(processes) => processes, + Command::Drivers(drivers) => drivers as &dyn Runnable, + Command::Processes(processes) => processes, } .run() } diff --git a/src/traces/drivers.rs b/src/commands/traces/drivers.rs similarity index 56% rename from src/traces/drivers.rs rename to src/commands/traces/drivers.rs index 64f5827..b0b3582 100644 --- a/src/traces/drivers.rs +++ b/src/commands/traces/drivers.rs @@ -2,27 +2,30 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -use crate::traces::{drivers::byovd::Byovd, Runnable}; +use crate::commands::{traces::drivers::byovd::Byovd, Runnable}; use clap::{Args, Subcommand}; +use serde::Deserialize; use std::error::Error; pub mod byovd; -#[derive(Debug, Args)] +#[derive(Args, Deserialize)] pub struct Drivers { #[clap(subcommand)] - pub command: Commands, + #[serde(flatten)] + pub command: Command, } -#[derive(Debug, Subcommand)] -pub enum Commands { +#[derive(Subcommand, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum Command { Byovd(Byovd), } impl Runnable for Drivers { fn run(&self) -> Result<(), Box> { match &self.command { - Commands::Byovd(byovd) => byovd as &dyn Runnable, + Command::Byovd(byovd) => byovd as &dyn Runnable, } .run() } diff --git a/src/traces/drivers/byovd.rs b/src/commands/traces/drivers/byovd.rs similarity index 94% rename from src/traces/drivers/byovd.rs rename to src/commands/traces/drivers/byovd.rs index b3ca762..9c8552e 100644 --- a/src/traces/drivers/byovd.rs +++ b/src/commands/traces/drivers/byovd.rs @@ -2,8 +2,9 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -use crate::{traces::Runnable, windows::users::is_administrator}; +use crate::{commands::Runnable, windows::users::is_administrator}; use clap::Parser; +use serde::Deserialize; use std::{error::Error, path::PathBuf}; use windows::{ core::{Owned, HSTRING, PCWSTR}, @@ -17,7 +18,7 @@ use windows::{ }, }; -#[derive(Debug, Parser)] +#[derive(Parser, Deserialize)] pub struct Byovd { #[clap(required = true, help = "Name of the service")] service_name: String, diff --git a/src/traces/processes.rs b/src/commands/traces/processes.rs similarity index 55% rename from src/traces/processes.rs rename to src/commands/traces/processes.rs index 97e2f38..2238f5f 100644 --- a/src/traces/processes.rs +++ b/src/commands/traces/processes.rs @@ -2,27 +2,30 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -use crate::traces::{processes::spoofing::Spoofing, Runnable}; +use crate::commands::{traces::processes::spoofing::Spoofing, Runnable}; use clap::{Args, Subcommand}; +use serde::Deserialize; use std::error::Error; pub mod spoofing; -#[derive(Debug, Args)] +#[derive(Args, Deserialize)] pub struct Processes { #[clap(subcommand)] - pub command: Commands, + #[serde(flatten)] + pub command: Command, } -#[derive(Debug, Subcommand)] -pub enum Commands { +#[derive(Subcommand, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum Command { Spoofing(Spoofing), } impl Runnable for Processes { fn run(&self) -> Result<(), Box> { match &self.command { - Commands::Spoofing(spoofing) => spoofing as &dyn Runnable, + Command::Spoofing(spoofing) => spoofing as &dyn Runnable, } .run() } diff --git a/src/traces/processes/spoofing.rs b/src/commands/traces/processes/spoofing.rs similarity index 96% rename from src/traces/processes/spoofing.rs rename to src/commands/traces/processes/spoofing.rs index d0d622b..5ce0a1f 100644 --- a/src/traces/processes/spoofing.rs +++ b/src/commands/traces/processes/spoofing.rs @@ -2,8 +2,9 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -use crate::{traces::Runnable, windows::processes::get_pid}; +use crate::{commands::Runnable, windows::processes::get_pid}; use clap::Parser; +use serde::Deserialize; use std::{ error::Error, ffi::OsString, iter::once, mem::size_of, os::windows::ffi::OsStrExt, path::PathBuf, @@ -21,7 +22,7 @@ use windows::{ }, }; -#[derive(Debug, Parser)] +#[derive(Parser, Deserialize)] pub struct Spoofing { #[clap(required = true, help = "Path to the executable")] executable: PathBuf, diff --git a/src/main.rs b/src/main.rs index 17a0eae..8b41b3b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,19 +2,13 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -mod cli; -mod traces; +mod commands; mod windows; use clap::Parser; -use cli::{Arguments, Commands}; +use commands::{Arguments, Runnable}; use std::error::Error; -use traces::Runnable; fn main() -> Result<(), Box> { - match Arguments::parse().command { - Commands::Traces(action) => action.run()?, - }; - - Ok(()) + Arguments::parse().run() }