pub struct Sig {
pub name: &'static str,
pub min_size: usize,
pub mask: &'static [u8],
}
pub fn identify(bytes: &[u8], off: usize, size: usize) -> Option<&'static str> {
for sig in SIGS {
if size < sig.min_size || off + sig.mask.len() > bytes.len() {
continue;
}
let window = &bytes[off..off + sig.mask.len()];
if window
.iter()
.zip(sig.mask.iter())
.all(|(b, m)| *m == 0 || b == m)
{
return Some(sig.name);
}
}
None
}
const fn s(name: &'static str, min_size: usize, mask: &'static [u8]) -> Sig {
Sig {
name,
min_size,
mask,
}
}
const SIGS: &[Sig] = &[
s(
"__security_check_cookie",
15,
&[
0x48, 0x8b, 0x05, 0, 0, 0, 0, 0x48, 0x3b, 0x04, 0x24, 0x75, 0x02, 0xf3, 0xc3,
],
),
s(
"__security_check_cookie",
15,
&[
0x48, 0x8b, 0x05, 0, 0, 0, 0, 0x48, 0x3b, 0xc1, 0x75, 0x02, 0xf3, 0xc3,
],
),
s(
"__security_check_cookie",
10,
&[0x3b, 0x0d, 0, 0, 0, 0, 0x75, 0x02, 0xc3],
),
s(
"_chkstk",
16,
&[
0x48, 0x3d, 0x00, 0x10, 0x00, 0x00, 0x76, 0x10, 0x48, 0x8d, 0x4c, 0x24, 0x10, 0x00,
0x00, 0x00, 0x00,
],
),
s(
"__stack_chk_fail",
13,
&[
0x50, 0xe8, 0, 0, 0, 0, 0x58, 0x48, 0x83, 0xc0, 0x05, 0x50, 0xc3,
],
),
s(
"__stack_chk_fail",
8,
&[0xfd, 0x7b, 0xbf, 0xa9, 0x94, 0, 0, 0],
),
];
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn matches_the_x64_cookie_check() {
let body = [
0x48, 0x8b, 0x05, 0x12, 0x34, 0x56, 0x78, 0x48, 0x3b, 0x04, 0x24, 0x75, 0x02, 0xf3,
0xc3, 0xcc, 0xcc,
];
assert_eq!(
identify(&body, 0, body.len()),
Some("__security_check_cookie")
);
}
#[test]
fn displacement_bytes_may_differ() {
let body = [
0x48, 0x8b, 0x05, 0xde, 0xad, 0xbe, 0xef, 0x48, 0x3b, 0x04, 0x24, 0x75, 0x02, 0xf3,
0xc3,
];
assert_eq!(
identify(&body, 0, body.len()),
Some("__security_check_cookie")
);
}
#[test]
fn a_different_function_does_not_match() {
let body = [0x48, 0x89, 0x5c, 0x24, 0x08, 0x57, 0x48, 0x83, 0xec, 0x20];
assert!(identify(&body, 0, body.len()).is_none());
}
#[test]
fn the_cookie_check_signature_is_at_least_distinctive_against_rain() {
let noise = [0u8; 64];
assert!(identify(&noise, 1, 63).is_none());
assert!(identify(&noise, 0, 64).is_none());
}
#[test]
fn too_small_does_not_match() {
let body = [0x50, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x58];
assert!(identify(&body, 0, body.len()).is_none());
}
#[test]
fn matches_the_arm64_or_chkstk() {
let chkstk = [
0x48, 0x3d, 0x00, 0x10, 0x00, 0x00, 0x76, 0x10, 0x48, 0x8d, 0x4c, 0x24, 0x10, 0x00,
0x00, 0x00, 0x00, 0x5a, 0x48, 0x2b, 0xd1,
];
assert_eq!(identify(&chkstk, 0, chkstk.len()), Some("_chkstk"));
let arm = [0xfd, 0x7b, 0xbf, 0xa9, 0x94, 0xaa, 0xaa, 0xaa];
assert_eq!(identify(&arm, 0, arm.len()), Some("__stack_chk_fail"));
}
}