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