//! 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 = "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)); }