Hugal31 / yara-rust

Rust bindings for VirusTotal/Yara
Apache License 2.0
73 stars 29 forks source link

Error on scanning #74

Closed ikrivosheev closed 2 years ago

ikrivosheev commented 2 years ago

Hello! I found a very strange error. My use-case: I need unpack file and then scan it with yara.

Simple code for reproduce:

Cargo.toml

[package]
name = "gz"
version = "0.1.0"
edition = "2021"

[dependencies]
libflate = "1.2"
yara = { version = "0.13", features = ["vendored", "bundled-4_1_3"] }

main.rs

use libflate::gzip::Decoder;
use std::fs::File;
use std::io::{Read, Result};
use yara::{Compiler, MemoryBlock, MemoryBlockIterator, Rules};

const RULES: &str = r#"
import "pe"
rule is_awesome {
  strings:
    $rust = /[Rr]ust/
  condition:
    $rust
}
rule is_ok {
  strings:
    $go = "go"
  condition:
    $go
}
rule re_is_ok {
  strings:
    $go = /[Oo]k/
  condition:
    $go
}
"#;

fn compile(rule: &str) -> Rules {
    Compiler::new()
        .expect("Should create compiler")
        .add_rules_str(rule)
        .expect("Should parse rule")
        .compile_rules()
        .expect("Should compile rules")
}

pub struct GZipMemoryBlockIterator<R> {
    buffer: Vec<u8>,
    decoder: Decoder<R>,
}

impl<R: Read> GZipMemoryBlockIterator<R> {
    pub fn new(reader: R) -> Result<Self> {
        Ok(GZipMemoryBlockIterator {
            buffer: vec![0; 1024],
            decoder: Decoder::new(reader)?,
        })
    }
}

impl<R: Read> MemoryBlockIterator for GZipMemoryBlockIterator<R> {
    fn first(&mut self) -> Option<MemoryBlock> {
        self.next()
    }

    fn next(&mut self) -> Option<MemoryBlock> {
        let size = self.decoder.read(&mut self.buffer).unwrap();
        if size == 0 {
            return None;
        }
        Some(MemoryBlock::new(0, size as u64, &self.buffer))
    }
}

fn main() {
    let file = File::open("memdump.bin.gz").unwrap();
    let iterator = GZipMemoryBlockIterator::new(file).unwrap();
    let rules = compile(RULES);
    let scanner = rules.scanner().unwrap();
    scanner.scan_mem_blocks(iterator).unwrap();
}

And I got error:

cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/gz`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 9, kind: Uncategorized, message: "Bad file descriptor" }', src/main.rs:57:56
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Then I run code with strace: strace -e trace=close,read --output /tmp/logs -k target/debug/gz and output:

...
close(3)                                = 0
 > /usr/lib/libc.so.6(close+0x17) [0x102667]
 > /tmp/gz/target/debug/gz(<std::os::fd::owned::OwnedFd as core::ops::drop::Drop>::drop+0xd) [0x131bd]
 > /tmp/gz/target/debug/gz(core::ptr::drop_in_place<std::os::fd::owned::OwnedFd>+0xa) [0x12eda]
 > /tmp/gz/target/debug/gz(core::ptr::drop_in_place<std::sys::unix::fd::FileDesc>+0xa) [0x12eea]
 > /tmp/gz/target/debug/gz(core::ptr::drop_in_place<std::sys::unix::fs::File>+0xa) [0x12eaa]
 > /tmp/gz/target/debug/gz(core::ptr::drop_in_place<std::fs::File>+0xa) [0x12dba]
 > /tmp/gz/target/debug/gz(core::ptr::drop_in_place<libflate::bit::BitReader<std::fs::File>>+0x17) [0x13007]
 > /tmp/gz/target/debug/gz(core::ptr::drop_in_place<libflate::deflate::decode::Decoder<std::fs::File>>+0x13) [0x13113]
 > /tmp/gz/target/debug/gz(core::ptr::drop_in_place<libflate::gzip::Decoder<std::fs::File>>+0x47) [0x12fc7]
 > /tmp/gz/target/debug/gz(core::ptr::drop_in_place<gz::GZipMemoryBlockIterator<std::fs::File>>+0x47) [0x13097]
 > /tmp/gz/target/debug/gz(core::ptr::drop_in_place<yara::internals::iterator::WrapperMemoryBlockIterator<gz::GZipMemoryBlockIterator<std::fs::File>>>+0xa) [0x12d5a]
 > /tmp/gz/target/debug/gz(yara::internals::scan::scanner_scan_mem_blocks+0xc3) [0x22533]
 > /tmp/gz/target/debug/gz(yara::scanner::Scanner::scan_mem_blocks_callback+0x5c) [0x129fc]
 > /tmp/gz/target/debug/gz(yara::scanner::Scanner::scan_mem_blocks+0xc2) [0x12802]
 > /tmp/gz/target/debug/gz(gz::main+0x178) [0x22ba8]
 > /tmp/gz/target/debug/gz(core::ops::function::FnOnce::call_once+0xb) [0x12c6b]
 > /tmp/gz/target/debug/gz(std::sys_common::backtrace::__rust_begin_short_backtrace+0xe) [0x1206e]
 > /tmp/gz/target/debug/gz(std::rt::lang_start::{{closure}}+0x11) [0x22d41]
 > /tmp/gz/target/debug/gz(std::rt::lang_start_internal+0x3fe) [0xcd39e]
 > /tmp/gz/target/debug/gz(std::rt::lang_start+0x30) [0x22d10]
 > /tmp/gz/target/debug/gz(main+0x1c) [0x22c7c]
 > /usr/lib/libc.so.6(__libc_init_first+0x90) [0x29290]
 > /usr/lib/libc.so.6(__libc_start_main+0x8a) [0x2934a]
 > /tmp/gz/target/debug/gz(_start+0x25) [0x11f85]
read(3, 0x7ffc552e6377, 1)              = -1 EBADF (Bad file descriptor)
...

Can someone help me to understand what's going on here??

Hugal31 commented 2 years ago

@ikrivosheev Hi, I noticed one of your change in string.rs in #75 caused a bug when retrieving the YR_STRINGs. I reverted it, and cannot reproduce the SEGFAULT you mentioned in your PR. Can you test with v0.13.2 and tell me if you can reproduce the segfault?

ikrivosheev commented 2 years ago

@Hugal31 yes! It is work, thank you!