You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- Update to flatbuffers `25.2.10`
- Add fuzzing targets for type and function `from_bytes`
- Update examples
- Simplify type spec
- Make constraints generic and remove specialized constraint lists
- Space optimizations for type and functions specs
- More tests with greater coverage
- Introduce the concept of a WARP `File` and `Chunk`s
- Make chunk compression configurable
- Make `Type` objects class field unboxed (decreases memory pressure)
- Use standard directory structure for Rust API
- Move tests to `tests` directory for more easy discovery
- Remove almost all uses of `unwrap` (needed for server-side parsing)
- Refactor `TypeMetadata`
- Add `mock` module for easy mocking in tests and examples
- Make `Symbol` space optimized
- Switch to using `.warp` extension to represent general analysis data instead of just signatures
- Add format version to `File` and `Chunk` (allow for breaking changes later)
- Make analysis data (signatures and types) copy on write (See `ChunkHandler` impl's)
This work is being done to allow for networked WARP information and generally to make the WARP format more usable in a wider set of scenarios. After this commit any breaking changes to the format will be held off for 2.0, if that ever becomes a thing.
The namespace for Function GUID's is `0192a179-61ac-7cef-88ed-012296e9492f`.
59
+
The namespace for Function GUIDs is `0192a179-61ac-7cef-88ed-012296e9492f`.
60
60
61
61
### Creating a Basic Block GUID
62
62
63
63
The basic block GUID is the UUIDv5 of the byte sequence of the instructions (sorted in execution order) with the following properties:
64
64
65
-
1. Zero out all instructions containing a relocatable operand.
65
+
1. Zero out all relocatable instructions.
66
66
2. Exclude all NOP instructions.
67
67
3. Exclude all instructions that set a register to itself if they are effectively NOPs.
68
68
69
69
#### When are instructions that set a register to itself removed?
70
70
71
-
To support hot-patching we must remove them as they can be injected by the compiler at the start of a function (see: [1] and [2]).
71
+
To support hot-patching, we must remove them as they can be injected by the compiler at the start of a function (see: [1] and [2]).
72
72
This does not affect the accuracy of the function GUID as they are only removed when the instruction is a NOP:
73
73
74
74
- Register groups with no implicit extension will be removed (see: [3] (under 3.4.1.1))
75
75
76
76
For the `x86_64` architecture this means `mov edi, edi` will _not_ be removed, but it _will_ be removed for the `x86` architecture.
77
77
78
-
#### What is considered a relocatable operand?
78
+
#### What is considered a relocatable instruction?
79
79
80
-
An operand that is used as a pointer to a mapped region.
80
+
An instruction with an operand that is used as a_constant_ pointer to a mapped region.
81
81
82
-
For the `x86` architecture the instruction `e8b55b0100` (or `call 0x15bba`) would be zeroed.
82
+
- For the `x86` architecture the instruction `e8b55b0100` (or `call 0x15bba`) would be zeroed.
83
+
84
+
An instruction which is used to calculate a _constant_ pointer to a mapped region.
85
+
86
+
- For the `aarch64` architecture the instruction `21403c91` (or `add x1, x1, #0xf10`) would be zeroed if the incoming `x1` was a pointer into a mapped region.
83
87
84
88
#### What is the UUIDv5 namespace?
85
89
86
-
The namespace for Basic Block GUID's is `0192a178-7a5f-7936-8653-3cbaa7d6afe7`.
90
+
The namespace for Basic Block GUIDs is `0192a178-7a5f-7936-8653-3cbaa7d6afe7`.
87
91
88
-
### Function Constraints
92
+
### Constraints
89
93
90
-
Function constraints allow us to further disambiguate between functions with the same GUID, when creating the functions we store information about the following:
94
+
Constraints allow us to further disambiguate between functions with the same GUID; when creating the functions, we retrieve extra information
95
+
that is consistent between versions of the same function, some examples are:
91
96
92
97
- Called functions
93
98
- Caller functions
94
99
- Adjacent functions
95
100
96
-
Each entry in the lists above is referred to as a "constraint" that can be used to further reduce the number of matches for a given function GUID.
101
+
Each extra piece of information is referred to as a "constraint" that can be used to further reduce the number of matches for a given function GUID.
102
+
103
+
#### Creating a Constraint
104
+
105
+
Constraints are made up of a GUID and optionally, a matching offset. Adding a matching offset is preferred to give locality to the constraints,
106
+
for example, if you have a function `A` which calls into function `B` that is one constraint, but if the function `B` is also adjacent to function `A`
107
+
without a matching offset the two constraints may be merged into a single one, reducing the number of matching constraints.
108
+
109
+
- The adjacent function `B` as a constraint: `(9F188A12-3EA1-477D-B368-361936EEA213, -30)`
110
+
- The call to function `B` as a constraint: `(9F188A12-3EA1-477D-B368-361936EEA213, 48)`
111
+
112
+
#### Creating a Constraint GUID
113
+
114
+
The constraint GUID is the UUIDv5 of the relevant bytes that would be computable at creation time and lookup time.
115
+
116
+
##### What is the UUIDv5 namespace?
117
+
118
+
The namespace for Constraint GUIDs is `019701f3-e89c-7afa-9181-371a5e98a576`.
97
119
98
120
##### Why don't we require matching on constraints for trivial functions?
99
121
@@ -111,44 +133,46 @@ The main difference between **WARP** and **FLIRT** is the approach to identifica
111
133
#### Function Identification
112
134
113
135
-**WARP** the function identification is described [here](#function-identification).
114
-
-**FLIRT** uses incomplete function byte sequence with a mask where there is a single function entry (see: [IDA FLIRT Documentation] for a full description).
136
+
-**FLIRT** uses an incomplete function byte sequence with a mask where there is a single function entry (see: [IDA FLIRT Documentation] for a full description).
115
137
116
-
What this means in practice is **WARP** will have less false positives based solely off the initial function identification.
138
+
What this means in practice is **WARP** will have fewer false positives based solely off the initial function identification.
117
139
When the returned set of functions is greater than one, we can use the list of [Function Constraints](#function-constraints) to select the best possible match.
118
140
However, that comes at the cost of requiring a computed GUID to be created whenever the lookup is requested and that the function GUID is _**always**_ the same.
119
141
120
142
### WARP vs SigKit
121
143
122
-
Because WARP is a replacement for SigKit it makes sense to not only talk about the function identification approach, but also the integration with [Binary NInja].
144
+
Because WARP is a replacement for SigKit it makes sense to not only talk about the function identification approach, but also the integration with [Binary Ninja].
123
145
124
146
#### SigKit Function Identification
125
147
126
-
SigKit is rooted as a FLIRT-like signature matcher so to not repeat what is said above, see [here](#function-identification).
148
+
SigKit's function identification is similar to FLIRT so to not repeat what is said above, see [here](#function-identification).
149
+
150
+
One difference to point out is SigKit relies on relocations during signature generation. Because of this, firmware or other types of binaries lacking relocations will likely fail to mask off the required instructions.
127
151
128
152
#### Binary Ninja Integration
129
153
130
154
The two main processes that exist for both SigKit and WARP integration with Binary Ninja are the function lookup process and the signature generation process.
131
155
132
156
##### Function lookup
133
157
134
-
SigKit's function lookup process is integrated as a core component to Binary Ninja as such it is not open source, however the process is described [here](https://binary.ninja/2020/03/11/signature-libraries.html).
158
+
SigKit's function lookup process is integrated as a core component to Binary Ninja as such it is not open source, however, the process is described [here](https://binary.ninja/2020/03/11/signature-libraries.html).
135
159
136
-
What this means is **WARP** unlike SigKit can identify a greater number of smaller functions, ones which would be required to be pruned in generation process.
160
+
What this means is **WARP** unlike SigKit can identify a greater number of smaller functions, ones which would be required to be pruned in the generation process.
137
161
After looking up a function and successfully matching **WARP** will also be able to apply type information.
138
162
139
163
##### Signature generation
140
164
141
165
SigKit's signature generation is provided through user python scripts located [here](https://github.com/Vector35/sigkit/tree/master).
142
166
143
-
Because of the separation of the signature generation and the core integration the process becomes very cumbersome, specifically the process is too convoluted for smaller samples, and too slow for bigger samples.
167
+
Because of the separation of the signature generation and the core integration, the process becomes very cumbersome, specifically the process is too convoluted for smaller samples, and too slow for bigger samples.
144
168
145
169
#### What does this mean?
146
170
147
-
WARP can match on a greater number of functions which otherwise would be pruned at the generation process, this is obviously not without its tradeoffs, we generate this function UUID on both ends, meaning that the algorithm must be carefully upgraded to ensure that previously generate UUID's are no longer valid.
171
+
WARP can match on a greater number of functions which otherwise would be pruned at the generation process, this is not without its tradeoffs, we generate this function UUID on both ends, meaning that the algorithm must be carefully upgraded to ensure that previously generated UUID's are no longer valid.
148
172
149
-
Aside from just the matching of functions, we _never_ prune functions when added to the dataset this means we actually can store multiple functions for any given UUID, this is a major advantage for users who can now identify exactly what causes a collision and override, or otherwise understand more about the function.
173
+
Aside from just the matching of functions, we _never_ prune functions when added to the dataset this means we actually can store multiple functions for any given UUID. This is a major advantage for users who can now identify exactly what causes a collision and override, or otherwise understand more about the function.
150
174
151
-
After matching on a function successfully we can reconstruct the function signature not just the symbol name. SigKit has no information about the function calling convention or the function type.
175
+
After matching on a function successfully, we can reconstruct the function signature, not just the symbol name. SigKit has no information about the function calling convention or the function type.
0 commit comments