1 个不稳定版本
使用旧的 Rust 2015
0.1.0 | 2016年4月7日 |
---|
#3 in #sig
28KB
558 行
二进制签名扫描器
二进制签名的扫描器。
预期用途是扫描可执行文件中的签名。
文档
目前文档可以在 crates.fyi 上找到。
使用方法
这个库可以在 crates.io 上找到。在您的 Cargo.toml 中添加
[dependencies]
scanner = "0.1"
示例
签名是一系列 pat::Unit
,它们可以静态创建或在运行时解析
extern create scanner;
use scanner::pat::{parse, Unit};
const MY_PATTERN: &'static [Unit] = &[Unit::Byte(0xE9), Unit::Store, Unit::Skip(4), Unit::Byte(0xC3)];
let pat = parse("E9*???? C3").unwrap();
assert_eq!(pat, MY_PATTERN);
签名扫描器支持两个主要用例
-
查找单个唯一的模式匹配。
extern crate scanner; use scanner::{Scanner, Match, pat}; const BYTES: &'static [u8] = b"\x22\x01\xD5\x44\x22\x01\x69\x55"; const PATTERN: &'static [pat::Unit] = &[pat::Unit::Byte(0x22), pat::Unit::RelByte, pat::Unit::Store, pat::Unit::Byte(0x55)]; let scan = Scanner::new(BYTES, 0..BYTES.len() as u32, 0); if let Some(mach) = scan.find(PATTERN) { // Found a unqiue match assert_eq!(mach, Match { haystack: BYTES, at: 5, store: [7, 0, 0, 0, 0] }); } else { // No unique match was found }
-
查找所有模式匹配。
extern crate scanner; use scanner::{Scanner, Match, pat}; const BYTES: &'static [u8] = b"\xDD\x7F\xDD\x15\xDD\xC1\xDD"; const PATTERN: &'static [pat::Unit] = &[pat::Unit::Byte(0xDD), pat::Unit::Skip(1), pat::Unit::Byte(0xDD)]; let scan = Scanner::new(BYTES, 0..BYTES.len() as u32, 0); let matches: Vec<Match> = scan.iter(PATTERN).collect(); assert_eq!(matches, vec![ Match { haystack: BYTES, at: 0, store: [0, 0, 0, 0, 0] }, Match { haystack: BYTES, at: 2, store: [0, 0, 0, 0, 0] }, Match { haystack: BYTES, at: 4, store: [0, 0, 0, 0, 0] }, ]);
通常您想使用此 crate 来扫描代码段中的签名(例如 .text
),为此,有一个对 pelite
crate 的可选依赖,以及从 &PeView
到 Scanner
的 From
转换。
设计
签名可能是一项繁琐的工作,这个 crate 尝试帮助解决一些常见问题,同时提供一些有用的功能。
-
签名可以从文本中解析,这使得签名可以方便地存储在外部配置文件中。
这是可选的,您也可以像示例中那样从组件构建您的签名。
-
除非您正在扫描特定函数,否则您对匹配发生的位置不感兴趣,而是从指令参数中提取一些参数,这在 C 中看起来像这样
unsigned char* match = ...; float* interesting = *(float**)(match + 0x7);
有两个方面可能非常棘手;首先,您需要从匹配中获取正确的偏移量,其次,您需要正确地执行指定次数的强制转换和间接引用。请相信我,我永远不会第一次就做对。如果参数是相对于当前指针的 RIP,则会更复杂。
为了解决“正确的偏移量”问题,签名可以使用
*
,这将在Match
的store
数组中保存 ptr。目前这限制为每个签名 5 个存储。为了解决“正确的间接引用”问题,签名可以告诉扫描器使用
r1
(有符号字节)或r4
(有符号双字)跟随相对地址,并使用j
保存绝对地址。要在间接引用之前继续匹配,请在跳转前放置一个+
,然后使用-
回到扫描留下的地方。最大递归深度为 4。请注意,
j
在 32 位和 64 位(取决于您是否选择将签名解析为 32 位或 64 位)中工作正确。PIC 支持正在等待。 -
在大多数情况下,您希望得到一个唯一的匹配结果,因为签名错误地匹配了错误的对象而不是唯一的对象,调试崩溃并不是一件愉快的事情。为了解决这个问题,
Scanner::find
将检查以确保匹配是唯一的,这以牺牲一些速度为代价来换取“正确性”,但可以节省大量的麻烦。 -
速度很重要,因此这个crate限制了扫描范围并实现了优化的快速搜索。这比简单的查找模式要快!
许可证
MIT - 查看 license.txt
依赖项
~480KB