yaxpeax_core/analyses/function_signatures/
mod.rs

1use yaxpeax_arch::Arch;
2use siphasher::sip128::SipHasher13;
3use memory::MemoryRepr;
4use analyses::control_flow::ControlFlowGraph;
5
6pub enum IncompleteSignature {
7    MissingData,
8    Uncomputable
9}
10
11type SignatureResult<T> = Result<T, IncompleteSignature>;
12
13trait FunctionSignatory<A: Arch> {
14    type Signature;
15    type Data;
16
17    fn signature_of<M: MemoryRepr<A> + ?Sized>(cfg: &ControlFlowGraph<A::Address>, data: &Self::Data, memory: &M) -> SignatureResult<Self::Signature>;
18}
19
20pub struct FunctionByteSignatory;
21
22/*
23impl FunctionSignatory<x86_64> for FunctionByteSignatory {
24    type Signature = u64;
25    type Data = ();
26
27    /// A signature built from siphash 1-3 over instructions, in a BFS traversal
28    /// with a particular depth ordered by start address. Additionally, this discards immediate
29    /// offsets larger than some magic number. This is to have some semblance of generalizability
30    /// if functions move relative to each other.
31    fn signature_of<M: MemoryRepr<A>>(
32        cfg: &ControlFlowGraph<A::Address>,
33        data: &Self::Data,
34        memory: &M
35    ) -> SignatureResult<Self::Signature> {
36        let _hasher = SipHasher13::new();
37    }
38}
39*/
40
41pub struct FunctionMnemonicSignatory;
42
43impl <A: Arch> FunctionSignatory<A> for FunctionMnemonicSignatory {
44    type Signature = u64;
45    type Data = ();
46
47    /// A signature built from siphash 1-3 over instruction mnemonics, in a BFS traversal
48    /// with a particular depth ordered by start address. This, subsequently, is not
49    /// robust in the face of basic block reordering.
50    fn signature_of<M: MemoryRepr<A> + ?Sized>(
51        _cfg: &ControlFlowGraph<A::Address>,
52        _data: &Self::Data,
53        _memory: &M
54    ) -> SignatureResult<Self::Signature> {
55        let _hasher = SipHasher13::new();
56        Err(IncompleteSignature::Uncomputable)
57    }
58}
59
60pub struct FunctionBlockSignatory;
61
62impl <A: Arch> FunctionSignatory<A> for FunctionBlockSignatory {
63    type Signature = Vec<u64>;
64    type Data = ();
65
66    /// A signature in the form of siphash 1-3 signatures of basic blocks in this function
67    /// topologically ordered from the function entry point. This should be robust to
68    /// basic block reordering, and also permits an edit distance style fuzzy equivalence
69    fn signature_of<M: MemoryRepr<A> + ?Sized>(
70        _cfg: &ControlFlowGraph<A::Address>,
71        _data: &Self::Data,
72        _memory: &M
73    ) -> SignatureResult<Self::Signature> {
74        let _hasher = SipHasher13::new();
75        Err(IncompleteSignature::Uncomputable)
76    }
77}
78
79pub struct FunctionOrderFreeSignatory;
80
81impl <A: Arch> FunctionSignatory<A> for FunctionOrderFreeSignatory {
82    type Signature = Vec<u64>;
83    type Data = ();
84
85    /// A signature in the form of siphash 1-3 signatures of basic blocks in this function with
86    /// control flow-sensitive instructions normalized to some branch-insensitive constant.
87    /// This is ad-hoc, but the intention is to be robust in the face of changes like branches
88    /// being negated due to compilers changing code layout or something similar. For an x86
89    /// example, the following snippets should have the same signature:
90    ///
91    /// mov eax, [rsp + 0x124]
92    /// xor ecx, ecx
93    /// cmp eax, ecx
94    /// jb B
95    ///A:
96    /// ; do A
97    /// jmp C
98    ///B
99    /// ; do B
100    ///C
101    /// ret
102    ///
103    /// mov eax, [rsp + 0x124]
104    /// xor ecx, ecx
105    /// cmp eax, ecx
106    /// jae B
107    ///A:
108    /// ; do B
109    /// jmp C
110    ///B
111    /// ; do A
112    ///C
113    /// ret
114    ///
115    /// by virtue of nulling the jb/jae.
116    fn signature_of<M: MemoryRepr<A> + ?Sized>(
117        _cfg: &ControlFlowGraph<A::Address>,
118        _data: &Self::Data,
119        _memory: &M
120    ) -> SignatureResult<Self::Signature> {
121        let _hasher = SipHasher13::new();
122        Err(IncompleteSignature::Uncomputable)
123    }
124}
125
126// and something clever about data flow to ditch architecture-specific signatures