1use rayon::prelude::*;
2use std::str::FromStr;
3use subslice_index::subslice_index;
4
5pub struct Pattern {
8 buf: Vec<u8>,
9}
10
11impl Pattern {
12 pub fn matches(&self, buf: &[u8]) -> bool {
18 self.buf
19 .par_iter()
20 .zip(buf.par_iter())
21 .all(|(&pattern_byte, &buffer_byte)| {
22 pattern_byte == 0x00 || pattern_byte == buffer_byte
23 })
24 }
25}
26
27impl From<&[u8]> for Pattern {
28 fn from(buf: &[u8]) -> Pattern {
29 Pattern {
30 buf: Vec::from(buf),
31 }
32 }
33}
34
35impl FromStr for Pattern {
38 type Err = usize;
39
40 fn from_str(buf_str: &str) -> Result<Pattern, Self::Err> {
42 let mut buf = Vec::new();
43 for byte_str in buf_str.split_ascii_whitespace() {
44 if byte_str == "?" {
45 buf.push(0x00);
46 } else {
47 match u8::from_str_radix(byte_str, 16) {
48 Ok(byte) => {
49 buf.push(byte);
50 }
51 Err(_) => return Err(subslice_index(buf_str.as_bytes(), byte_str.as_bytes())),
52 };
53 }
54 }
55 Ok(Pattern { buf })
56 }
57}
58
59pub fn find_pattern(buf: &[u8], pattern: Pattern) -> Vec<&[u8]> {
66 buf.par_windows(pattern.buf.len())
67 .filter(|&window| pattern.matches(window))
68 .collect()
69}
70
71#[cfg(test)]
72mod test {
73 use super::*;
74
75 #[test]
76 #[should_panic]
77 fn empty_pattern() {
78 let buf = &[1, 2, 3];
79 let pattern = Pattern::from(&[][..]);
80 find_pattern(buf, pattern);
81 }
82
83 #[test]
84 fn not_empty() {
85 let buf = &[1, 2, 3];
86 let pattern = Pattern::from(&[1, 2][..]);
87 assert!(!find_pattern(buf, pattern).is_empty());
88 }
89
90 #[test]
91 fn empty() {
92 let buf = &[1, 2, 3];
93 let pattern = Pattern::from(&[1, 3][..]);
94 assert!(find_pattern(buf, pattern).is_empty());
95 }
96
97 #[test]
98 fn simple_wildcard_not_empty() {
99 let buf = &[1, 2, 3];
100 let pattern = Pattern::from(&[1, 0x00, 3][..]);
101 assert!(!find_pattern(buf, pattern).is_empty());
102 }
103
104 #[test]
105 fn simple_wildcard_empty() {
106 let buf = &[1, 2, 3];
107 let pattern = Pattern::from(&[1, 0x00, 4][..]);
108 assert!(find_pattern(buf, pattern).is_empty());
109 }
110
111 #[test]
112 fn wildcard_start_not_empty() {
113 let buf = &[1, 2, 3];
114 let pattern = Pattern::from(&[0x00, 3][..]);
115 assert!(!find_pattern(buf, pattern).is_empty());
116 }
117
118 #[test]
119 fn wildcard_start_empty() {
120 let buf = &[1, 2, 3];
121 let pattern = Pattern::from(&[0x00, 1][..]);
122 assert!(find_pattern(buf, pattern).is_empty());
123 }
124
125 #[test]
126 fn wildcard_end_not_empty() {
127 let buf = &[1, 2, 3];
128 let pattern = Pattern::from(&[1, 2, 0x00][..]);
129 assert!(!find_pattern(buf, pattern).is_empty());
130 }
131
132 #[test]
133 fn wildcard_end_empty() {
134 let buf = &[1, 2, 3];
135 let pattern = Pattern::from(&[2, 3, 0x00][..]);
136 assert!(find_pattern(buf, pattern).is_empty());
137 }
138
139 #[test]
140 fn multi_match() {
141 let buf = &[1, 2, 3, 4, 3, 2, 1, 2, 3];
142 let pattern = Pattern::from(&[1, 2, 0x00][..]);
143 assert_eq!(find_pattern(buf, pattern).len(), 2);
144 }
145
146 #[test]
147 fn function_signature() {
148 let buf = include_bytes!("..\\test\\crt.exe");
149 let pattern = Pattern::from(
150 &[
151 0xe8, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xd8,
152 ][..],
153 );
154 let result = find_pattern(buf, pattern);
155 assert!(!result.is_empty());
156 assert_eq!(
157 result[0],
158 &[0xe8, 0x1c, 0x04, 0x00, 0x00, 0xe8, 0xcb, 0x05, 0x00, 0x00, 0x48, 0x8b, 0xd8][..]
159 );
160 assert_eq!(subslice_index(buf, result[0]), 0x5bb);
161 }
162}