Files

76 lines
2.4 KiB
Rust

//! Core behavior tests for PE analysis helpers.
use petools::{
ApiCategory, CallsiteQuery, IoctlMethod, IoctlScanOptions, analyze_callsites,
categorize_import, decode_ioctl, scan_strings,
};
#[test]
fn categorizes_common_windows_imports() {
assert_eq!(
categorize_import("kernel32.dll", "CreateFileW"),
ApiCategory::Filesystem
);
assert_eq!(
categorize_import("advapi32.dll", "RegOpenKeyExW"),
ApiCategory::Registry
);
assert_eq!(
categorize_import("ntdll.dll", "NtDeviceIoControlFile"),
ApiCategory::DeviceIo
);
}
#[test]
fn resolves_iat_call_targets_from_objdump_comments() {
let query = CallsiteQuery::apis(["CreateFileW"]);
let imports = [("0x140072010", "kernel32.dll", "CreateFileW")];
let disassembly = "140001098:\tcallq\t*0x70f72(%rip) # 0x140072010\n";
let report = analyze_callsites(disassembly, &imports, &query);
assert_eq!(report.callsites.len(), 1);
assert_eq!(report.callsites[0].api, "CreateFileW");
assert_eq!(report.callsites[0].address, 0x1400_01098);
}
#[test]
fn decodes_ctl_code_fields() {
let decoded = decode_ioctl(0x0022_2003).expect("ioctl");
assert_eq!(decoded.device_type, 0x22);
assert_eq!(decoded.function, 0x800);
assert_eq!(decoded.method, IoctlMethod::Neither);
assert_eq!(decoded.access_name, "FILE_ANY_ACCESS");
}
#[test]
fn scans_ascii_and_utf16_strings() {
let mut bytes = b"\0DeviceIoControl\0\0".to_vec();
bytes.extend("IoctlName".encode_utf16().flat_map(u16::to_le_bytes));
let strings = scan_strings(&bytes, 5);
assert!(strings.iter().any(|item| item.value == "DeviceIoControl"));
assert!(strings.iter().any(|item| item.value == "IoctlName"));
}
#[test]
fn utf16le_scan_reports_only_maximal_non_overlapping_runs() {
let bytes: Vec<u8> = "LongDeviceName"
.encode_utf16()
.flat_map(u16::to_le_bytes)
.collect();
let strings = scan_strings(&bytes, 5);
let utf16_hits: Vec<_> = strings
.iter()
.filter(|item| item.encoding == "utf16le")
.collect();
assert_eq!(utf16_hits.len(), 1);
assert_eq!(utf16_hits[0].offset, 0);
assert_eq!(utf16_hits[0].value, "LongDeviceName");
}
#[test]
fn filters_probable_ioctl_candidates() {
let options = IoctlScanOptions::default();
assert!(options.is_probable_code(0x0022_2000));
assert!(!options.is_probable_code(0x0000_0001));
}