Skip to content

Commit

Permalink
feat: add ability to set module data in scan callback
Browse files Browse the repository at this point in the history
Some modules in YARA need to be fed data to be usable, notably the
cuckoo module. This works by setting the module data in the "import
module" callback, as can be seen here:

<https://github.com/VirusTotal/yara/blob/923368eab/cli/yara.c#L1200>

This MR adds bindings to be able to do exactly this: the object related
to this callback msg is wrapped in a YrModuleImport object, which
exposes two functions:

- one to retrieve the module name
- one to set the module data

This makes the code looks like this:

```rust
let res = yara_scanner.scan_mem_callback(b"", |msg| {
    if let yara::CallbackMsg::ImportModule(mut module) = msg {
        if module.name() == Some(b"cuckoo") {
            // Safety: report is alive for longer than the scan.
            unsafe {
                module.set_module_data(
                    report.as_mut_ptr().cast(),
                    report.len() as u64,
                );
            }
        }
    }
    yara::CallbackReturn::Continue
});
```

I haven't added a test for it, because the only module that uses this is
the cuckoo module, and to use it, the module-cuckoo feature must be
enabled and the libjansson-dev needs to be installed. If you prefer to
have a test, I can try to update the CI to have a test like this
working.
  • Loading branch information
vthib committed May 1, 2024
1 parent ab7cd9c commit 93e802e
Show file tree
Hide file tree
Showing 9 changed files with 313 additions and 2 deletions.
2 changes: 2 additions & 0 deletions src/internals/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::errors::*;

pub use self::compiler::*;
pub use self::iterator::*;
pub use self::module_import::*;
pub use self::object::*;
pub use self::rules::*;
pub use self::scan::*;
Expand All @@ -17,6 +18,7 @@ pub mod string;
mod compiler;
pub mod configuration;
mod iterator;
mod module_import;
mod object;
mod rules;
mod scan;
Expand Down
45 changes: 45 additions & 0 deletions src/internals/module_import.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use std::ffi::{c_void, CStr};
use std::fmt::Debug;

/// Details about a module being imported.
pub struct YrModuleImport<'a>(&'a mut yara_sys::YR_MODULE_IMPORT);

impl Debug for YrModuleImport<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Debug::fmt("YrModuleImport", f)
}
}

impl<'a> From<&'a mut yara_sys::YR_MODULE_IMPORT> for YrModuleImport<'a> {
fn from(value: &'a mut yara_sys::YR_MODULE_IMPORT) -> Self {
Self(value)
}
}

impl YrModuleImport<'_> {
/// Get the name of the module.
pub fn name(&self) -> Option<&[u8]> {
let ptr = self.0.module_name;
if ptr.is_null() {
None
} else {
// Safety:
// - ptr is not null, and is guaranteed by libyara to be nul-terminated
// - returned slice is valid for as long as self, guaranteeing the ptr to stay valid.
let cstr = unsafe { CStr::from_ptr(ptr) };
Some(cstr.to_bytes())
}
}

/// Set the module data to be used by the module.
///
/// # Safety
///
/// The caller must guarantee that:
/// - `ptr` is valid for reads of `size` bytes.
/// - `ptr` stays valid for the full duration of the scan.
pub unsafe fn set_module_data(&mut self, ptr: *mut c_void, size: usize) {
self.0.module_data = ptr;
self.0.module_data_size = size as _;
}
}
7 changes: 5 additions & 2 deletions src/internals/scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{Rule, YrString};
pub enum CallbackMsg<'r> {
RuleMatching(Rule<'r>),
RuleNotMatching(Rule<'r>),
ImportModule,
ImportModule(YrModuleImport<'r>),
ModuleImported(YrObject<'r>),
TooManyMatches(YrString<'r>),
ScanFinished,
Expand All @@ -40,7 +40,10 @@ impl<'r> CallbackMsg<'r> {
let context = unsafe { &*context };
RuleNotMatching(Rule::from((context, rule)))
}
yara_sys::CALLBACK_MSG_IMPORT_MODULE => ImportModule,
yara_sys::CALLBACK_MSG_IMPORT_MODULE => {
let object = unsafe { &mut *(message_data as *mut yara_sys::YR_MODULE_IMPORT) };
ImportModule(YrModuleImport::from(object))
}
yara_sys::CALLBACK_MSG_MODULE_IMPORTED => {
let object = unsafe { &*(message_data as *mut yara_sys::YR_OBJECT) };
ModuleImported(YrObject::from(object))
Expand Down
52 changes: 52 additions & 0 deletions yara-sys/bindings/yara-4.5.0-x86_64-apple-darwin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5527,3 +5527,55 @@ extern "C" {
rules: *mut *mut YR_RULES,
) -> ::std::os::raw::c_int;
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct YR_MODULE_IMPORT {
pub module_name: *const ::std::os::raw::c_char,
pub module_data: *mut ::std::os::raw::c_void,
pub module_data_size: size_t,
}
#[test]
fn bindgen_test_layout_YR_MODULE_IMPORT() {
const UNINIT: ::std::mem::MaybeUninit<YR_MODULE_IMPORT> = ::std::mem::MaybeUninit::uninit();
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<YR_MODULE_IMPORT>(),
24usize,
concat!("Size of: ", stringify!(YR_MODULE_IMPORT))
);
assert_eq!(
::std::mem::align_of::<YR_MODULE_IMPORT>(),
8usize,
concat!("Alignment of ", stringify!(YR_MODULE_IMPORT))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).module_name) as usize - ptr as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(YR_MODULE_IMPORT),
"::",
stringify!(module_name)
)
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).module_data) as usize - ptr as usize },
8usize,
concat!(
"Offset of field: ",
stringify!(YR_MODULE_IMPORT),
"::",
stringify!(module_data)
)
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).module_data_size) as usize - ptr as usize },
16usize,
concat!(
"Offset of field: ",
stringify!(YR_MODULE_IMPORT),
"::",
stringify!(module_data_size)
)
);
}
52 changes: 52 additions & 0 deletions yara-sys/bindings/yara-4.5.0-x86_64-pc-windows-gnu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8134,3 +8134,55 @@ extern "C" {
rules: *mut *mut YR_RULES,
) -> ::std::os::raw::c_int;
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct YR_MODULE_IMPORT {
pub module_name: *const ::std::os::raw::c_char,
pub module_data: *mut ::std::os::raw::c_void,
pub module_data_size: size_t,
}
#[test]
fn bindgen_test_layout_YR_MODULE_IMPORT() {
const UNINIT: ::std::mem::MaybeUninit<YR_MODULE_IMPORT> = ::std::mem::MaybeUninit::uninit();
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<YR_MODULE_IMPORT>(),
24usize,
concat!("Size of: ", stringify!(YR_MODULE_IMPORT))
);
assert_eq!(
::std::mem::align_of::<YR_MODULE_IMPORT>(),
8usize,
concat!("Alignment of ", stringify!(YR_MODULE_IMPORT))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).module_name) as usize - ptr as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(YR_MODULE_IMPORT),
"::",
stringify!(module_name)
)
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).module_data) as usize - ptr as usize },
8usize,
concat!(
"Offset of field: ",
stringify!(YR_MODULE_IMPORT),
"::",
stringify!(module_data)
)
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).module_data_size) as usize - ptr as usize },
16usize,
concat!(
"Offset of field: ",
stringify!(YR_MODULE_IMPORT),
"::",
stringify!(module_data_size)
)
);
}
52 changes: 52 additions & 0 deletions yara-sys/bindings/yara-4.5.0-x86_64-pc-windows-msvc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8134,3 +8134,55 @@ extern "C" {
rules: *mut *mut YR_RULES,
) -> ::std::os::raw::c_int;
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct YR_MODULE_IMPORT {
pub module_name: *const ::std::os::raw::c_char,
pub module_data: *mut ::std::os::raw::c_void,
pub module_data_size: size_t,
}
#[test]
fn bindgen_test_layout_YR_MODULE_IMPORT() {
const UNINIT: ::std::mem::MaybeUninit<YR_MODULE_IMPORT> = ::std::mem::MaybeUninit::uninit();
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<YR_MODULE_IMPORT>(),
24usize,
concat!("Size of: ", stringify!(YR_MODULE_IMPORT))
);
assert_eq!(
::std::mem::align_of::<YR_MODULE_IMPORT>(),
8usize,
concat!("Alignment of ", stringify!(YR_MODULE_IMPORT))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).module_name) as usize - ptr as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(YR_MODULE_IMPORT),
"::",
stringify!(module_name)
)
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).module_data) as usize - ptr as usize },
8usize,
concat!(
"Offset of field: ",
stringify!(YR_MODULE_IMPORT),
"::",
stringify!(module_data)
)
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).module_data_size) as usize - ptr as usize },
16usize,
concat!(
"Offset of field: ",
stringify!(YR_MODULE_IMPORT),
"::",
stringify!(module_data_size)
)
);
}
52 changes: 52 additions & 0 deletions yara-sys/bindings/yara-4.5.0-x86_64-unknown-linux-gnu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5719,3 +5719,55 @@ extern "C" {
rules: *mut *mut YR_RULES,
) -> ::std::os::raw::c_int;
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct YR_MODULE_IMPORT {
pub module_name: *const ::std::os::raw::c_char,
pub module_data: *mut ::std::os::raw::c_void,
pub module_data_size: size_t,
}
#[test]
fn bindgen_test_layout_YR_MODULE_IMPORT() {
const UNINIT: ::std::mem::MaybeUninit<YR_MODULE_IMPORT> = ::std::mem::MaybeUninit::uninit();
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<YR_MODULE_IMPORT>(),
24usize,
concat!("Size of: ", stringify!(YR_MODULE_IMPORT))
);
assert_eq!(
::std::mem::align_of::<YR_MODULE_IMPORT>(),
8usize,
concat!("Alignment of ", stringify!(YR_MODULE_IMPORT))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).module_name) as usize - ptr as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(YR_MODULE_IMPORT),
"::",
stringify!(module_name)
)
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).module_data) as usize - ptr as usize },
8usize,
concat!(
"Offset of field: ",
stringify!(YR_MODULE_IMPORT),
"::",
stringify!(module_data)
)
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).module_data_size) as usize - ptr as usize },
16usize,
concat!(
"Offset of field: ",
stringify!(YR_MODULE_IMPORT),
"::",
stringify!(module_data_size)
)
);
}
52 changes: 52 additions & 0 deletions yara-sys/bindings/yara-4.5.0-x86_64-unknown-linux-musl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5719,3 +5719,55 @@ extern "C" {
rules: *mut *mut YR_RULES,
) -> ::std::os::raw::c_int;
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct YR_MODULE_IMPORT {
pub module_name: *const ::std::os::raw::c_char,
pub module_data: *mut ::std::os::raw::c_void,
pub module_data_size: size_t,
}
#[test]
fn bindgen_test_layout_YR_MODULE_IMPORT() {
const UNINIT: ::std::mem::MaybeUninit<YR_MODULE_IMPORT> = ::std::mem::MaybeUninit::uninit();
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<YR_MODULE_IMPORT>(),
24usize,
concat!("Size of: ", stringify!(YR_MODULE_IMPORT))
);
assert_eq!(
::std::mem::align_of::<YR_MODULE_IMPORT>(),
8usize,
concat!("Alignment of ", stringify!(YR_MODULE_IMPORT))
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).module_name) as usize - ptr as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(YR_MODULE_IMPORT),
"::",
stringify!(module_name)
)
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).module_data) as usize - ptr as usize },
8usize,
concat!(
"Offset of field: ",
stringify!(YR_MODULE_IMPORT),
"::",
stringify!(module_data)
)
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).module_data_size) as usize - ptr as usize },
16usize,
concat!(
"Offset of field: ",
stringify!(YR_MODULE_IMPORT),
"::",
stringify!(module_data_size)
)
);
}
1 change: 1 addition & 0 deletions yara-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ mod bindings {
.allowlist_type("YR_AC_AUTOMATON")
.allowlist_type("YR_AC_MATCH")
.allowlist_type("YR_ATOMS_CONFIG")
.allowlist_type("YR_MODULE_IMPORT")
.opaque_type("YR_AC_.*")
.opaque_type("YR_ATOMS_CONFIG")
.opaque_type("YR_FIXUP")
Expand Down

0 comments on commit 93e802e

Please sign in to comment.