Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Hugal31 committed May 11, 2018
0 parents commit 306f966
Show file tree
Hide file tree
Showing 17 changed files with 565 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/target
**/*.rs.bk
Cargo.lock
9 changes: 9 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "yara"
version = "0.1.0"
authors = ["Hugo Laloge <[email protected]>"]
description = "Rust bindings for VirusTotal/yara"

[dependencies]
failure = "~0.1.0"
yara-sys = { path = "yara-sys" }
89 changes: 89 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use std::fmt;
use std::str::Utf8Error;

use failure::{Context, Backtrace, Fail};

use yara_sys::{ERROR_INSUFFICIENT_MEMORY, ERROR_SCAN_TIMEOUT, ERROR_SUCCESS};

#[derive(Debug)]
pub struct Error {
inner: Context<ErrorKind>,
}

impl Error {
pub fn kind(&self) -> ErrorKind {
*self.inner.get_context()
}
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.inner.fmt(f)
}
}

impl Fail for Error {
fn cause(&self) -> Option<&Fail> {
self.inner.cause()
}

fn backtrace(&self) -> Option<&Backtrace> {
self.inner.backtrace()
}
}

#[derive(Clone, Copy, Debug, Fail, Eq, PartialEq)]
pub enum ErrorKind {
#[fail(display = "Utf8 error: {:?}", _0)]
Utf8(#[cause] Utf8Error),
#[fail(display = "{}", _0)]
Yara(#[cause] YaraError),
}

impl From<Context<ErrorKind>> for Error {
fn from(ctx: Context<ErrorKind>) -> Error {
Error { inner: ctx }
}
}

impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Error {
Error { inner: Context::new(kind) }
}
}

pub type YaraError = YaraErrorKind;

impl From<YaraError> for Error {
fn from(error: YaraError) -> Error {
ErrorKind::Yara(error).into()
}
}

#[derive(Clone, Copy, Debug, Fail, Eq, PartialEq)]
#[fail(display = "Error(s) during rule compilation.")]
pub struct CompilationError();

#[derive(Clone, Copy, Debug, Fail, Eq, PartialEq)]
pub enum YaraErrorKind {
#[fail(display = "Insufficient memory to complete the operation.")]
InsufficientMemory,
#[fail(display = "Timeouted during scan.")]
ScanTimeout,
#[fail(display = "Unknown Yara error: {}", _0)]
Unknown(u32),
}

impl YaraErrorKind {
pub(crate) fn from_yara(code: i32) -> Result<(), YaraErrorKind> {
let code = code as u32;
use self::YaraErrorKind::*;

match code {
ERROR_SUCCESS => Ok(()),
ERROR_INSUFFICIENT_MEMORY => Err(InsufficientMemory),
ERROR_SCAN_TIMEOUT => Err(ScanTimeout),
_ => Err(Unknown(code)),
}
}
}
1 change: 1 addition & 0 deletions src/internals/bindings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub use yara_sys::*;
51 changes: 51 additions & 0 deletions src/internals/compiler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use std::ffi;
use std::ptr;

use yara_sys;

use errors::*;

use super::{Compiler, Rules};

pub fn compiler_create() -> Result<*mut Compiler, YaraError> {
let mut pointer: *mut Compiler = ptr::null_mut();
let result = unsafe { yara_sys::yr_compiler_create(&mut pointer) };

YaraErrorKind::from_yara(result).map(|()| pointer)
}

pub fn compiler_destroy(compiler_ptr: *mut Compiler) {
unsafe {
yara_sys::yr_compiler_destroy(compiler_ptr);
}
}

pub fn compiler_add_string(
compiler_ptr: *mut Compiler,
string: &str,
namespace: Option<&str>,
) -> Result<(), CompilationError> {
let string = ffi::CString::new(string).unwrap();
let namespace = namespace.map(|n| ffi::CString::new(n).unwrap());
let result = unsafe {
yara_sys::yr_compiler_add_string(
compiler_ptr,
string.as_ptr(),
namespace.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
)
};

// TODO Add callbacks to get better errors
if result == 0 {
Ok(())
} else {
Err(CompilationError())
}
}

pub fn compiler_get_rules(compiler_ptr: *mut Compiler) -> Result<*mut Rules, YaraError> {
let mut pointer = ptr::null_mut();
let result = unsafe { yara_sys::yr_compiler_get_rules(compiler_ptr, &mut pointer) };

YaraErrorKind::from_yara(result).map(|()| pointer)
}
33 changes: 33 additions & 0 deletions src/internals/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
mod compiler;
mod rules;
mod scan;

pub use self::compiler::*;
pub use self::rules::*;
pub use self::scan::*;

use yara_sys;

use errors::*;

pub type Compiler = yara_sys::YR_COMPILER;
pub type Rule = yara_sys::YR_RULE;
pub type Rules = yara_sys::YR_RULES;

/// Initialize the Yara library
///
/// Can be called multiple times without problems
pub fn initialize() -> Result<(), YaraError> {
let result = unsafe { yara_sys::yr_initialize() };

YaraErrorKind::from_yara(result)
}

/// De-initialize the Yara library
///
/// Must not be called more time than [`initialize`].
pub fn finalize() -> Result<(), YaraError> {
let result = unsafe { yara_sys::yr_finalize() };

YaraErrorKind::from_yara(result)
}
21 changes: 21 additions & 0 deletions src/internals/rules.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use std::ffi;

use yara_sys;

use errors::*;

use super::Rules;

pub fn rules_destroy(rules: *mut Rules) {
unsafe {
yara_sys::yr_rules_destroy(rules);
}
}

// TODO Check if non mut
pub fn rules_save(rules: *mut Rules, filename: &str) -> Result<(), YaraError> {
let filename = ffi::CString::new(filename).unwrap();
let result = unsafe { yara_sys::yr_rules_save(rules, filename.as_ptr()) };

YaraErrorKind::from_yara(result)
}
121 changes: 121 additions & 0 deletions src/internals/scan.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
use std::ffi::CStr;
use std::fs::File;
use std::mem;
use std::os::raw;

use yara_sys;

use super::{Rule, Rules};

use errors::*;

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum CallbackMsg {
RuleMatching,
RuleNotMatching,
ScanFinished,
ImportModule,
ModuleImported,
UnknownMsg,
}

impl CallbackMsg {
pub fn from_yara(code: i32) -> Self {
use self::CallbackMsg::*;
let code = code as u32;

match code {
yara_sys::CALLBACK_MSG_RULE_MATCHING => RuleMatching,
yara_sys::CALLBACK_MSG_RULE_NOT_MATCHING => RuleNotMatching,
yara_sys::CALLBACK_MSG_SCAN_FINISHED => ScanFinished,
yara_sys::CALLBACK_MSG_IMPORT_MODULE => ImportModule,
yara_sys::CALLBACK_MSG_MODULE_IMPORTED => ModuleImported,
_ => UnknownMsg,
}
}
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum CallbackReturn {
Continue,
Abort,
Error,
}

#[derive(Debug)]
pub struct Match {

}

impl CallbackReturn {
pub fn to_yara(&self) -> i32 {
use self::CallbackReturn::*;

let res = match self {
Continue => yara_sys::CALLBACK_CONTINUE,
Abort => yara_sys::CALLBACK_ABORT,
Error => yara_sys::CALLBACK_ERROR,
};
res as i32
}
}

#[derive(Default)]
struct ScanResults {
matches: Vec<()>,
}

pub fn rules_scan_mem(rules: *mut Rules, mem: &[u8], timeout: i32) -> Result<(), YaraError> {
let mut results = Ok(ScanResults::default());
let result = unsafe {
yara_sys::yr_rules_scan_mem(
rules,
mem.as_ptr(),
mem.len(),
0,
Some(scan_callback),
mem::transmute(&mut results),
timeout,
)
};
YaraErrorKind::from_yara(result).map_err(|e| e.into())
.and(results)
.map(|_| ()) // TODO Change
}

#[cfg(unix)]
pub fn rules_scan_fd(rules: *mut Rules, file: File, timeout: i32) -> Result<(), Error> {
use std::os::unix::io::AsRawFd;

let mut results = Ok(ScanResults::default());
let fd = file.as_raw_fd();
let result = unsafe {
yara_sys::yr_rules_scan_fd(
rules,
fd,
0,
Some(scan_callback),
mem::transmute(&mut results),
timeout,
)
};
YaraErrorKind::from_yara(result).map_err(|e| e.into())
.and(results)
.map(|_| ()) // TODO Change
}

extern "C" fn scan_callback(
message: raw::c_int,
message_data: *mut raw::c_void,
user_data: *mut raw::c_void,
) -> i32 {
let results: &mut Result<ScanResults, Error> = unsafe { mem::transmute(user_data) };
let message = CallbackMsg::from_yara(message);

if message == CallbackMsg::RuleMatching {
let rule: &Rule = unsafe { mem::transmute(message_data) };
let truc = unsafe { CStr::from_ptr(rule.__bindgen_anon_1.identifier) };
}

CallbackReturn::Continue.to_yara()
}
Loading

0 comments on commit 306f966

Please sign in to comment.