boreal 0.1.0

A library to evaluate YARA rules, used to scan bytes for textual and binary pattern
Documentation
use object::{
    coff::SectionTable, pe, read::pe::DataDirectories, Bytes, LittleEndian as LE, ReadRef,
};

use super::Value;

pub fn pdb_path(data_dirs: &DataDirectories, mem: &[u8], sections: &SectionTable) -> Option<Value> {
    let dir = data_dirs.get(pe::IMAGE_DIRECTORY_ENTRY_DEBUG)?;
    let mut debug_data = Bytes(dir.data(mem, sections).ok()?);

    let nb_directories = debug_data.len() / std::mem::size_of::<pe::ImageDebugDirectory>();
    for debug_dir in debug_data
        .read_slice::<pe::ImageDebugDirectory>(nb_directories)
        .ok()?
    {
        if debug_dir.typ.get(LE) != pe::IMAGE_DEBUG_TYPE_CODEVIEW {
            return None;
        }

        let mut offset = 0;

        // try first as an RVA, then as a raw offset. See logic from libyara for explanations.
        let raw_data_addr = debug_dir.address_of_raw_data.get(LE);
        let raw_data_ptr = debug_dir.pointer_to_raw_data.get(LE);
        if raw_data_addr != 0 {
            if let Some(v) = super::va_to_file_offset(sections, raw_data_addr) {
                offset = v;
            }
        }
        if offset == 0 && raw_data_ptr != 0 {
            offset = raw_data_ptr;
        }
        if offset == 0 {
            continue;
        }

        let info = mem
            .read_slice_at::<u8>(offset.into(), debug_dir.size_of_data.get(LE) as usize)
            .ok()?;

        let mut info = Bytes(info);
        let sig = match info.read_bytes(4) {
            Ok(v) => v.0,
            Err(_) => continue,
        };

        let pdb_path_offset = match sig {
            // PDB20
            b"NB10" => 12,
            // PDB70
            b"RSDS" => 20,
            // MTOC
            b"MTOC" => 16,
            _ => continue,
        };

        let path = info.read_string_at(pdb_path_offset).ok()?;

        return Some(path.to_vec().into());
    }

    None
}