Skip to content

Commit

Permalink
feat: control the name of the feature associated to each YARA module …
Browse files Browse the repository at this point in the history
…from the protobuf defining the module

Now each YARA module can define the name of the cargo feature that enables/disables the module. This is done using the new `cargo_feature` option, like in:

```
option (yara.module_options) = {
  name : "text"
  root_message: "text.Text"
  rust_module: "text"
  cargo_feature: "text-module"
};
```

The `cargo_feature` option is not required. If missing the module will always be enabled.
  • Loading branch information
plusvic committed Feb 18, 2024
1 parent 1d75a56 commit a4b12d8
Show file tree
Hide file tree
Showing 18 changed files with 107 additions and 56 deletions.
31 changes: 20 additions & 11 deletions docs/Module Developer's Guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ For illustrative purposes we are going to create a `text` module that allows
creating YARA rules for plain-text files, based on the number of lines and
words

- [Module Developer's Guide](#module-developers-guide)
- [Defining the module's structure](#defining-the-modules-structure)
- [Proto2 vs Proto3](#proto2-vs-proto3)
- [Tweaking the module's YAML output](#tweaking-the-modules-yaml-output)
Expand Down Expand Up @@ -65,6 +64,7 @@ option (yara.module_options) = {
name : "text"
root_message: "text.Text"
rust_module: "text"
cargo_feature: "text-module"
};
message Text {
Expand Down Expand Up @@ -121,6 +121,7 @@ option (yara.module_options) = {
name : "text"
root_message: "text.Text"
rust_module: "text"
cargo_feature: "text-module"
};
```

Expand All @@ -131,16 +132,24 @@ file, but one describing a module. In fact, you can put any `.proto` file in the
files is describing a YARA module. Only files containing a `yara.module_options`
section will define a module.

Options `name` and `root_message` are required, while `rust_module` is optional.
The `name` option defines the module's name. This is the name that will be used
for importing the module in a YARA rule, in this case our module will be imported
with `import "text"`. The `root_message` option indicates which is the module's
root structure, it must contain the name of some structure (a.k.a message) defined
in the `.proto` file. In our case the value for `root_message` is `"text.Text"`
because we have defined our module's structure in a message named `Text`, which
is under package `text`. In general the value in this field will have the form
`package.Message`, except if the `package` statement is missing, in which case
it would be the name of the message alone (i.e: `Text`).
Options `name` and `root_message` are required, while `rust_module` and
`cargo_feature` are optional. The `name` option defines the module's name. This
is the name that will be used for importing the module in a YARA rule, in this
case our module will be imported with `import "text"`.

The `cargo_feature` option indicates the name of the feature that controls whether
the module is built or not. If this option is not specified the module is always
built, but if you specify a feature name, this feature name must also be included
in the `Cargo.toml` file, and the module will be built only when this `cargo`
feature is enabled.

The `root_message` option a very important option indicating which is the module's
root structure, it must contain the name of some structure (a.k.a. message)
defined in the `.proto` file. In our case the value for `root_message` is
`"text.Text"` because we have defined our module's structure in a message named
`Text`, which is under package `text`. In general the value in this field will
have the form `package.Message`, except if the `package` statement is missing,
in which case it would be the name of the message alone (i.e: `Text`).

The `root_message` field is required because your `.proto` file can define
multiple messages, and YARA needs to know which of them is considered the root
Expand Down
40 changes: 24 additions & 16 deletions lib/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,15 +121,16 @@ fn main() {
yara_module_options.get(&proto_file.options)
{
modules.push((
module_options.name,
module_options.name.unwrap(),
proto_file
.name
.unwrap()
.strip_suffix(".proto")
.unwrap()
.to_string(),
module_options.rust_module,
module_options.root_message,
module_options.cargo_feature,
module_options.root_message.unwrap(),
));
}
}
Expand Down Expand Up @@ -164,37 +165,44 @@ fn main() {
let name = m.0;
let proto_mod = m.1;
let rust_mod = m.2;
let root_message = m.3;

if !rust_mod.is_empty() {
write!(
modules_rs,
r#"
#[cfg(feature = "{name}-module")]
mod {rust_mod};"#,
)
.unwrap();
}
let cargo_feature = m.3;
let root_message = m.4;

// If the YARA module has an associated Rust module, this module must
// have a function named "main". If the YARA module doesn't have an
// associated YARA module, the main function is set to None.
let main_fn = if !rust_mod.is_empty() {
let main_fn = if let Some(rust_mod) = &rust_mod {
format!("Some({}::__main__ as MainFn)", rust_mod)
} else {
"None".to_string()
};

let rust_mod_name = if !rust_mod.is_empty() {
let rust_mod_name = if let Some(rust_mod) = &rust_mod {
format!(r#"Some("{}")"#, rust_mod)
} else {
"None".to_string()
};

let cfg_feature = if let Some(cargo_feature) = &cargo_feature {
format!(r#"#[cfg(feature = "{cargo_feature}")]"#)
} else {
"".to_string()
};

if let Some(rust_mod) = &rust_mod {
write!(
modules_rs,
r#"
{cfg_feature}
mod {rust_mod};"#,
)
.unwrap();
}

write!(
add_modules_rs,
r#"
#[cfg(feature = "{name}-module")]
{cfg_feature}
add_module!(modules, "{name}", {proto_mod}, "{root_message}", {rust_mod_name}, {main_fn});"#,
)
.unwrap();
Expand Down
1 change: 1 addition & 0 deletions lib/src/modules/protos/console.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ option (yara.module_options) = {
name : "console"
root_message: "console.Console"
rust_module: "console"
cargo_feature: "console-module"
};

message Console {
Expand Down
1 change: 1 addition & 0 deletions lib/src/modules/protos/dotnet.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ option (yara.module_options) = {
name : "dotnet"
root_message: "dotnet.Dotnet"
rust_module: "dotnet"
cargo_feature: "dotnet-module"
};

message Dotnet {
Expand Down
1 change: 1 addition & 0 deletions lib/src/modules/protos/elf.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ option (yara.module_options) = {
name : "elf"
root_message: "elf.ELF"
rust_module: "elf"
cargo_feature: "elf-module"
};

message ELF {
Expand Down
1 change: 1 addition & 0 deletions lib/src/modules/protos/hash.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ option (yara.module_options) = {
name : "hash"
root_message: "hash.Hash"
rust_module: "hash"
cargo_feature: "hash-module"
};

message Hash {
Expand Down
1 change: 1 addition & 0 deletions lib/src/modules/protos/lnk.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ option (yara.module_options) = {
name : "lnk"
root_message: "lnk.Lnk"
rust_module: "lnk"
cargo_feature: "lnk-module"
};

enum FileAttributes {
Expand Down
1 change: 1 addition & 0 deletions lib/src/modules/protos/macho.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ option (yara.module_options) = {
name : "macho"
root_message: "macho.Macho"
rust_module: "macho"
cargo_feature: "macho-module"
};

message Dylib {
Expand Down
1 change: 1 addition & 0 deletions lib/src/modules/protos/math.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ option (yara.module_options) = {
name : "math"
root_message: "math.Math"
rust_module: "math"
cargo_feature: "math-module"
};

message Math {
Expand Down
1 change: 1 addition & 0 deletions lib/src/modules/protos/pe.proto
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ option (yara.module_options) = {
name : "pe"
root_message: "pe.PE"
rust_module: "pe"
cargo_feature: "pe-module"
};

message PE {
Expand Down
1 change: 1 addition & 0 deletions lib/src/modules/protos/string.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ option (yara.module_options) = {
name : "string"
root_message: "string.String"
rust_module: "string"
cargo_feature: "string-module"
};

message String {
Expand Down
4 changes: 4 additions & 0 deletions lib/src/modules/protos/test_proto2.proto
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ option (yara.module_options) = {
// in the data structure defined by this proto file, and don't need to have
// any associated code.
rust_module: "test_proto2"

// The name of the feature that controls whether this module is compiled or
// not. A feature with this name must be added to the Cargo.toml file.
cargo_feature: "test_proto2-module"
};

/// Top-level structure for this module.
Expand Down
4 changes: 4 additions & 0 deletions lib/src/modules/protos/test_proto3.proto
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ option (yara.module_options) = {
// in the data structure defined by this proto file, and don't need to have
// any associated code.
rust_module: "test_proto3"

// The name of the feature that controls whether this module is compiled or
// not. A feature with this name must be added to the Cargo.toml file.
cargo_feature: "test_proto3-module"
};

/// Top-level structure for this module.
Expand Down
3 changes: 3 additions & 0 deletions lib/src/modules/protos/text.proto
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ option (yara.module_options) = {
// The Rust module implementing this YARA module is named `text`. It can
// be found in `src/modules/text.rs`.
rust_module: "text"
// The feature that controls whether this module is compiled or not is named
// `text-module`.
cargo_feature: "text-module"
};

// This is the module's root structure.
Expand Down
1 change: 1 addition & 0 deletions lib/src/modules/protos/time.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ option (yara.module_options) = {
name : "time"
root_message: "time.Time"
rust_module: "time"
cargo_feature: "time-module"
};

message Time {
Expand Down
20 changes: 6 additions & 14 deletions lib/src/types/structure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ impl Struct {
if let Some(options) =
module_options.get(&file_descriptor.proto().options)
{
options.root_message == msg_descriptor.full_name()
options.root_message.unwrap() == msg_descriptor.full_name()
} else {
false
}
Expand All @@ -438,11 +438,7 @@ impl Struct {
if let Some(options) =
enum_options.get(&enum_descriptor.proto().options)
{
if options.name.is_empty() {
enum_descriptor.name().to_owned()
} else {
options.name.clone()
}
options.name.unwrap_or_else(|| enum_descriptor.name().to_owned())
} else {
enum_descriptor.name().to_owned()
}
Expand Down Expand Up @@ -484,7 +480,7 @@ impl Struct {
if let Some(options) =
enum_options.get(&enum_descriptor.proto().options)
{
options.inline
options.inline.unwrap_or(false)
} else {
false
}
Expand Down Expand Up @@ -529,7 +525,7 @@ impl Struct {
if let Some(options) =
enum_value.get(&enum_value_descriptor.proto().options)
{
options.i64
options.i64.unwrap_or_else(|| enum_value_descriptor.value() as i64)
} else {
enum_value_descriptor.value() as i64
}
Expand All @@ -552,11 +548,7 @@ impl Struct {
if let Some(options) =
field_options.get(&field_descriptor.proto().options)
{
if options.name.is_empty() {
field_descriptor.name().to_owned()
} else {
options.name.clone()
}
options.name.unwrap_or_else(|| field_descriptor.name().to_owned())
} else {
field_descriptor.name().to_owned()
}
Expand All @@ -575,7 +567,7 @@ impl Struct {
if let Some(options) =
field_options.get(&field_descriptor.proto().options)
{
options.ignore
options.ignore.unwrap_or(false)
} else {
false
}
Expand Down
20 changes: 20 additions & 0 deletions mod.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"includes": [
"../../atlas/vt-protos/protos/tools",
"../../atlas/vt-protos/protos"
],
"inputs": [
"../../atlas/vt-protos/protos/titan.proto",
"../../atlas/vt-protos/protos/filetypes.proto",
"../../atlas/vt-protos/protos/sandbox.proto",
"../../atlas/vt-protos/protos/vtnet.proto",
"../../atlas/vt-protos/protos/submitter.proto",
"../../atlas/vt-protos/protos/analysis.proto",
"../../atlas/vt-protos/protos/tools/net_analysis.proto",
"../../atlas/vt-protos/protos/tools/snort.proto",
"../../atlas/vt-protos/protos/tools/suricata.proto",
"../../atlas/vt-protos/protos/tools/tshark.proto",
"../../atlas/vt-protos/protos/sigma.proto",
"../../atlas/vt-protos/protos/relationships.proto"
]
}
Loading

0 comments on commit a4b12d8

Please sign in to comment.