#pattern #find #sig #sigscan

scanner

二进制签名扫描器

1 个不稳定版本

使用旧的 Rust 2015

0.1.0 2016年4月7日

#3 in #sig

MIT 许可证

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 的可选依赖,以及从 &PeViewScannerFrom 转换。

设计

签名可能是一项繁琐的工作,这个 crate 尝试帮助解决一些常见问题,同时提供一些有用的功能。

  • 签名可以从文本中解析,这使得签名可以方便地存储在外部配置文件中。

    这是可选的,您也可以像示例中那样从组件构建您的签名。

  • 除非您正在扫描特定函数,否则您对匹配发生的位置不感兴趣,而是从指令参数中提取一些参数,这在 C 中看起来像这样

    unsigned char* match = ...;
    float* interesting = *(float**)(match + 0x7);
    

    有两个方面可能非常棘手;首先,您需要从匹配中获取正确的偏移量,其次,您需要正确地执行指定次数的强制转换和间接引用。请相信我,我永远不会第一次就做对。如果参数是相对于当前指针的 RIP,则会更复杂。

    为了解决“正确的偏移量”问题,签名可以使用 *,这将在 Matchstore 数组中保存 ptr。目前这限制为每个签名 5 个存储。

    为了解决“正确的间接引用”问题,签名可以告诉扫描器使用 r1(有符号字节)或 r4(有符号双字)跟随相对地址,并使用 j 保存绝对地址。要在间接引用之前继续匹配,请在跳转前放置一个 +,然后使用 - 回到扫描留下的地方。最大递归深度为 4。

    请注意,j 在 32 位和 64 位(取决于您是否选择将签名解析为 32 位或 64 位)中工作正确。PIC 支持正在等待。

  • 在大多数情况下,您希望得到一个唯一的匹配结果,因为签名错误地匹配了错误的对象而不是唯一的对象,调试崩溃并不是一件愉快的事情。为了解决这个问题,Scanner::find将检查以确保匹配是唯一的,这以牺牲一些速度为代价来换取“正确性”,但可以节省大量的麻烦。

  • 速度很重要,因此这个crate限制了扫描范围并实现了优化的快速搜索。这比简单的查找模式要快!

许可证

MIT - 查看 license.txt

依赖项

~480KB