Hugal31 / yara-rust

Rust bindings for VirusTotal/Yara

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add support for setting YR_MODULE_IMPORT::module_data

wbenny opened this issue · comments

CallbackMsg::ImportModule should be extended to access YR_MODULE_IMPORT data, namely module_name and module_data(_size).

Some modules accept additional module data, e.g. cuckoo module accepts json, which enables extended yara scanning.

This functionality is already exposed in python bindings (https://github.com/VirusTotal/yara-python/blob/master/yara-python.c#L618) and it would be lovely to have this functionality in this awesome rust crate :)

I managed to make it sort of work with these changes:

//
// add to the top of internals/scan.rs
//

#[derive(Debug)]
pub struct Module<'r> {
    inner: *mut yara_sys::YR_MODULE_IMPORT,
    _marker: std::marker::PhantomData<&'r ()>,
}

impl<'r> Module<'r> {
    pub fn get_name(&self) -> &'r str {
        let inner = unsafe { &mut *self.inner };
        unsafe { CStr::from_ptr(inner.module_name) }
            .to_str()
            .unwrap()
    }

    pub fn set_data(&mut self, data: &'r [u8]) {
        let inner = unsafe { &mut *self.inner };
        inner.module_data = data.as_ptr() as *mut c_void;
        inner.module_data_size = data.len() as u64;
    }
}

//
// update in CallbackMsg::from_yara
//
...
            yara_sys::CALLBACK_MSG_IMPORT_MODULE => {
                let _module = unsafe { &mut *(message_data as *mut yara_sys::YR_MODULE_IMPORT) };

                ImportModule(Module {
                    inner: _module,
                    _marker: std::marker::PhantomData
                })
            }
...

//
// ... and then, in main():
//
...
    let data = std::fs::read("data/yara/cuckoo.json").unwrap();

    let callback = |message: CallbackMsg| {
        match message {
            CallbackMsg::ImportModule(mut module) => {
                println!("module: '{}'", module.get_name());
                module.set_data(&data);
            }
            CallbackMsg::RuleMatching(rule) => {
                println!("match: '{}'", rule.identifier);
            },
            _ => (),
        }
        CallbackReturn::Continue
    };

    rules
        .scan_file_callback("data/yara/binary", 5, callback)
        .expect("Should have scanned");
...

The code above works.
However, I must have messed up lifetimes somewhere, because the following also compiles:

    let callback = |message: CallbackMsg| {
        match message {
            CallbackMsg::ImportModule(mut module) => {
                println!("module: '{}'", module.get_name());

                // !!!!!!!! this compiles fine, but of course crashes in runtime
                let data = std::fs::read("data/yara/cuckoo.json").unwrap();
                module.set_data(&data);
            }
            CallbackMsg::RuleMatching(rule) => {
                println!("match: '{}'", rule.identifier);
            },
            _ => (),
        }
        CallbackReturn::Continue
    };

Unfortunatelly, my rust-fu isn't yet advanced enough to comprehend what exactly is wrong with the lifetimes and how to fix them.

@wbenny hello! I thought about this, but bytes convert to struct in Rust is unsafe. And this was the problem why I didn't implement this...
Maybe we can create a lazy transmute API...

And the second problem is to send a type to which transmute bytes...