Skip to main content

goblin_sigscan/
lib.rs

1//! Goblin-powered multi-format pattern scanning with pelite-style signatures.
2//!
3//! `goblin-sigscan` combines:
4//!
5//! - pelite-inspired pattern syntax and semantics,
6//! - scanner APIs over PE/ELF/Mach binaries,
7//! - compile-time (`pattern!`) and runtime (`pattern::parse`) pattern parsing.
8//!
9//! This crate's design and pattern language are heavily inspired by pelite.
10//! See the original project by casualx:
11//! <https://github.com/CasualX/pelite> and
12//! <https://docs.rs/pelite/latest/pelite/pattern/>.
13//!
14//! # Docs map
15//!
16//! - Syntax overview and parser API: [`mod@crate::pattern`]
17//! - Parser internals/reference crate: [`goblin_sigscan_pattern`]
18//! - Scanner entry points: [`Scanner`], [`Matches`], [`PreparedPattern`]
19//! - Binary wrappers: [`pe64`], [`elf`], [`mach`]
20//!
21//! # Pattern Scanner Tutorial
22//!
23//! ## 1) Parse a pattern
24//!
25//! Runtime parse:
26//!
27//! ```
28//! use goblin_sigscan::pattern;
29//!
30//! let atoms = pattern::parse("48 8B ? ? ? ? 48 89")?;
31//! assert!(atoms.len() >= 3);
32//! # Ok::<(), pattern::ParsePatError>(())
33//! ```
34//!
35//! Compile-time parse via macro:
36//!
37//! ```no_run
38//! let atoms = goblin_sigscan::pattern!("48 8B ? ? ? ? 48 89");
39//! assert!(!atoms.is_empty());
40//! ```
41//!
42//! ## 2) Size your save buffer correctly
43//!
44//! Save-slot length and semantics are the easiest API to misuse.
45//!
46//! - Use [`pattern::save_len`] for parsed atom slices.
47//! - For prepared patterns, use [`PreparedPattern::required_slots`].
48//! - Parsed patterns always include an implicit `Save(0)`, so slot `0` is
49//!   always the match start cursor (RVA/VA/mapped offset based on wrapper).
50//! - Extra tail elements in larger `save` buffers are left untouched.
51//!
52//! ```
53//! use goblin_sigscan::pattern;
54//!
55//! let atoms = pattern::parse("e8 ${'}")?;
56//! let mut save = vec![0u64; pattern::save_len(&atoms)];
57//! assert!(save.len() >= 2);
58//! # Ok::<(), pattern::ParsePatError>(())
59//! ```
60//!
61//! ## 3) Scan binary code ranges
62//!
63//! ```no_run
64//! use std::error::Error;
65//!
66//! use goblin_sigscan::{pattern, pe64::PeFile};
67//!
68//! fn main() -> Result<(), Box<dyn Error>> {
69//!     // Provide real module bytes from your target binary in production code.
70//!     let bytes: &[u8] = &[];
71//!     let file = PeFile::from_bytes(bytes)?;
72//!     let atoms = pattern::parse("48 8B ? ? ? ? 48 89")?;
73//!     let mut save = vec![0u64; pattern::save_len(&atoms)];
74//!     let mut matches = file.scanner().matches_code(&atoms);
75//!     if matches.next(&mut save) {
76//!         let match_start = save[0];
77//!         let _ = match_start;
78//!     }
79//!     Ok(())
80//! }
81//! ```
82//!
83//! ## 4) Reuse prepared patterns for repeated scans
84//!
85//! ```no_run
86//! use std::error::Error;
87//!
88//! use goblin_sigscan::{pattern, pe64::PeFile};
89//!
90//! fn main() -> Result<(), Box<dyn Error>> {
91//!     // Provide real module bytes from your target binary in production code.
92//!     let bytes: &[u8] = &[];
93//!     let file = PeFile::from_bytes(bytes)?;
94//!     let atoms = pattern::parse("e8 ${'}")?;
95//!     let prepared = file.scanner().prepare_pattern(&atoms);
96//!     let mut save = vec![0u64; prepared.required_slots()];
97//!     let _is_unique = file.scanner().finds_prepared(&prepared, &mut save);
98//!     Ok(())
99//! }
100//! ```
101//!
102//! ## 5) Syntax tutorial
103//!
104//! For full syntax semantics and examples, use the canonical parser tutorial:
105//! [`goblin_sigscan_pattern::parse`].
106//!
107//! The `goblin_sigscan::pattern` module is a re-export convenience surface:
108//! [`mod@crate::pattern`].
109//!
110//! ## Common pitfalls
111//!
112//! - Allocating `save` too short for the parsed pattern.
113//! - Assuming slot `0` is optional (it is always present for parsed patterns).
114//! - Forgetting that `[a-b]` uses an exclusive upper parse convention (`b - 1`
115//!   is the maximum encoded skip).
116//! - Comparing benchmark runs with mismatched sample settings.
117//!
118//! For benchmark methodology guidance, see `scripts/README.md` in the repo.
119
120extern crate self as goblin_sigscan;
121
122pub use goblin_sigscan_macros::pattern;
123
124mod address;
125pub mod elf;
126pub mod mach;
127pub mod pattern;
128pub mod pe64;
129mod scan;
130mod typed;
131pub use address::{FromLeBytes, MappedAddressView};
132pub use scan::{BinaryView, CodeSpan, Matches, Offset, PreparedPattern, Scanner};
133pub use typed::{Pod, Ptr, TypedView, Va};