Expand description
Goblin-powered multi-format pattern scanning with pelite-style signatures.
goblin-sigscan combines:
- pelite-inspired pattern syntax and semantics,
- scanner APIs over PE/ELF/Mach binaries,
- compile-time (
pattern!) and runtime (pattern::parse) pattern parsing.
This crate’s design and pattern language are heavily inspired by pelite. See the original project by casualx: https://github.com/CasualX/pelite and https://docs.rs/pelite/latest/pelite/pattern/.
§Docs map
- Syntax overview and parser API:
crate::pattern - Parser internals/reference crate:
goblin_sigscan_pattern - Scanner entry points:
Scanner,Matches,PreparedPattern - Binary wrappers:
pe64,elf,mach
§Pattern Scanner Tutorial
§1) Parse a pattern
Runtime parse:
use goblin_sigscan::pattern;
let atoms = pattern::parse("48 8B ? ? ? ? 48 89")?;
assert!(atoms.len() >= 3);Compile-time parse via macro:
let atoms = goblin_sigscan::pattern!("48 8B ? ? ? ? 48 89");
assert!(!atoms.is_empty());§2) Size your save buffer correctly
Save-slot length and semantics are the easiest API to misuse.
- Use
pattern::save_lenfor parsed atom slices. - For prepared patterns, use
PreparedPattern::required_slots. - Parsed patterns always include an implicit
Save(0), so slot0is always the match start cursor (RVA/VA/mapped offset based on wrapper). - Extra tail elements in larger
savebuffers are left untouched.
use goblin_sigscan::pattern;
let atoms = pattern::parse("e8 ${'}")?;
let mut save = vec![0u64; pattern::save_len(&atoms)];
assert!(save.len() >= 2);§3) Scan binary code ranges
use std::error::Error;
use goblin_sigscan::{pattern, pe64::PeFile};
fn main() -> Result<(), Box<dyn Error>> {
// Provide real module bytes from your target binary in production code.
let bytes: &[u8] = &[];
let file = PeFile::from_bytes(bytes)?;
let atoms = pattern::parse("48 8B ? ? ? ? 48 89")?;
let mut save = vec![0u64; pattern::save_len(&atoms)];
let mut matches = file.scanner().matches_code(&atoms);
if matches.next(&mut save) {
let match_start = save[0];
let _ = match_start;
}
Ok(())
}§4) Reuse prepared patterns for repeated scans
use std::error::Error;
use goblin_sigscan::{pattern, pe64::PeFile};
fn main() -> Result<(), Box<dyn Error>> {
// Provide real module bytes from your target binary in production code.
let bytes: &[u8] = &[];
let file = PeFile::from_bytes(bytes)?;
let atoms = pattern::parse("e8 ${'}")?;
let prepared = file.scanner().prepare_pattern(&atoms);
let mut save = vec![0u64; prepared.required_slots()];
let _is_unique = file.scanner().finds_prepared(&prepared, &mut save);
Ok(())
}§5) Syntax tutorial
For full syntax semantics and examples, use the canonical parser tutorial:
goblin_sigscan_pattern::parse.
The goblin_sigscan::pattern module is a re-export convenience surface:
crate::pattern.
§Common pitfalls
- Allocating
savetoo short for the parsed pattern. - Assuming slot
0is optional (it is always present for parsed patterns). - Forgetting that
[a-b]uses an exclusive upper parse convention (b - 1is the maximum encoded skip). - Comparing benchmark runs with mismatched sample settings.
For benchmark methodology guidance, see scripts/README.md in the repo.
Modules§
Macros§
- pattern
- Compile-time pattern parser.
Structs§
- Code
Span - Matches
- Stateful matcher produced by
Scanner::matches_code. - Prepared
Pattern - Reusable scanner metadata and atoms for repeated scans.
- Ptr
- Typed mapped pointer into a parsed binary image.
- Scanner
- Pattern scanner over a
BinaryView.
Traits§
- Binary
View - Read-only view over a mapped binary image for scanner execution.
- From
LeBytes - Primitive type that can be decoded from little-endian bytes.
- Mapped
Address View - Shared mapped-address helpers used by PE/ELF/Mach wrappers.
- Pod
- Marker trait for plain-old-data values that can be read from bytes.
- Typed
View - Typed read helpers for any mapped-address view.