smallworld-re 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- smallworld/__init__.py +35 -0
- smallworld/analyses/__init__.py +14 -0
- smallworld/analyses/analysis.py +88 -0
- smallworld/analyses/code_coverage.py +31 -0
- smallworld/analyses/colorizer.py +682 -0
- smallworld/analyses/colorizer_summary.py +100 -0
- smallworld/analyses/field_detection/__init__.py +14 -0
- smallworld/analyses/field_detection/field_analysis.py +536 -0
- smallworld/analyses/field_detection/guards.py +26 -0
- smallworld/analyses/field_detection/hints.py +133 -0
- smallworld/analyses/field_detection/malloc.py +211 -0
- smallworld/analyses/forced_exec/__init__.py +3 -0
- smallworld/analyses/forced_exec/forced_exec.py +87 -0
- smallworld/analyses/underlays/__init__.py +4 -0
- smallworld/analyses/underlays/basic.py +13 -0
- smallworld/analyses/underlays/underlay.py +31 -0
- smallworld/analyses/unstable/__init__.py +4 -0
- smallworld/analyses/unstable/angr/__init__.py +0 -0
- smallworld/analyses/unstable/angr/base.py +12 -0
- smallworld/analyses/unstable/angr/divergence.py +274 -0
- smallworld/analyses/unstable/angr/model.py +383 -0
- smallworld/analyses/unstable/angr/nwbt.py +63 -0
- smallworld/analyses/unstable/angr/typedefs.py +170 -0
- smallworld/analyses/unstable/angr/utils.py +25 -0
- smallworld/analyses/unstable/angr/visitor.py +315 -0
- smallworld/analyses/unstable/angr_nwbt.py +106 -0
- smallworld/analyses/unstable/code_coverage.py +54 -0
- smallworld/analyses/unstable/code_reachable.py +44 -0
- smallworld/analyses/unstable/control_flow_tracer.py +71 -0
- smallworld/analyses/unstable/pointer_finder.py +90 -0
- smallworld/arch/__init__.py +0 -0
- smallworld/arch/aarch64_arch.py +286 -0
- smallworld/arch/amd64_arch.py +86 -0
- smallworld/arch/i386_arch.py +44 -0
- smallworld/emulators/__init__.py +14 -0
- smallworld/emulators/angr/__init__.py +7 -0
- smallworld/emulators/angr/angr.py +1652 -0
- smallworld/emulators/angr/default.py +15 -0
- smallworld/emulators/angr/exceptions.py +7 -0
- smallworld/emulators/angr/exploration/__init__.py +9 -0
- smallworld/emulators/angr/exploration/bounds.py +27 -0
- smallworld/emulators/angr/exploration/default.py +17 -0
- smallworld/emulators/angr/exploration/terminate.py +22 -0
- smallworld/emulators/angr/factory.py +55 -0
- smallworld/emulators/angr/machdefs/__init__.py +35 -0
- smallworld/emulators/angr/machdefs/aarch64.py +292 -0
- smallworld/emulators/angr/machdefs/amd64.py +192 -0
- smallworld/emulators/angr/machdefs/arm.py +387 -0
- smallworld/emulators/angr/machdefs/i386.py +221 -0
- smallworld/emulators/angr/machdefs/machdef.py +138 -0
- smallworld/emulators/angr/machdefs/mips.py +184 -0
- smallworld/emulators/angr/machdefs/mips64.py +189 -0
- smallworld/emulators/angr/machdefs/ppc.py +101 -0
- smallworld/emulators/angr/machdefs/riscv.py +261 -0
- smallworld/emulators/angr/machdefs/xtensa.py +255 -0
- smallworld/emulators/angr/memory/__init__.py +7 -0
- smallworld/emulators/angr/memory/default.py +10 -0
- smallworld/emulators/angr/memory/fixups.py +43 -0
- smallworld/emulators/angr/memory/memtrack.py +105 -0
- smallworld/emulators/angr/scratch.py +43 -0
- smallworld/emulators/angr/simos.py +53 -0
- smallworld/emulators/angr/utils.py +70 -0
- smallworld/emulators/emulator.py +1013 -0
- smallworld/emulators/hookable.py +252 -0
- smallworld/emulators/panda/__init__.py +5 -0
- smallworld/emulators/panda/machdefs/__init__.py +28 -0
- smallworld/emulators/panda/machdefs/aarch64.py +93 -0
- smallworld/emulators/panda/machdefs/amd64.py +71 -0
- smallworld/emulators/panda/machdefs/arm.py +89 -0
- smallworld/emulators/panda/machdefs/i386.py +36 -0
- smallworld/emulators/panda/machdefs/machdef.py +86 -0
- smallworld/emulators/panda/machdefs/mips.py +94 -0
- smallworld/emulators/panda/machdefs/mips64.py +91 -0
- smallworld/emulators/panda/machdefs/ppc.py +79 -0
- smallworld/emulators/panda/panda.py +575 -0
- smallworld/emulators/unicorn/__init__.py +13 -0
- smallworld/emulators/unicorn/machdefs/__init__.py +28 -0
- smallworld/emulators/unicorn/machdefs/aarch64.py +310 -0
- smallworld/emulators/unicorn/machdefs/amd64.py +326 -0
- smallworld/emulators/unicorn/machdefs/arm.py +321 -0
- smallworld/emulators/unicorn/machdefs/i386.py +137 -0
- smallworld/emulators/unicorn/machdefs/machdef.py +117 -0
- smallworld/emulators/unicorn/machdefs/mips.py +202 -0
- smallworld/emulators/unicorn/unicorn.py +684 -0
- smallworld/exceptions/__init__.py +5 -0
- smallworld/exceptions/exceptions.py +85 -0
- smallworld/exceptions/unstable/__init__.py +1 -0
- smallworld/exceptions/unstable/exceptions.py +25 -0
- smallworld/extern/__init__.py +4 -0
- smallworld/extern/ctypes.py +94 -0
- smallworld/extern/unstable/__init__.py +1 -0
- smallworld/extern/unstable/ghidra.py +129 -0
- smallworld/helpers.py +107 -0
- smallworld/hinting/__init__.py +8 -0
- smallworld/hinting/hinting.py +214 -0
- smallworld/hinting/hints.py +427 -0
- smallworld/hinting/unstable/__init__.py +2 -0
- smallworld/hinting/utils.py +19 -0
- smallworld/instructions/__init__.py +18 -0
- smallworld/instructions/aarch64.py +20 -0
- smallworld/instructions/arm.py +18 -0
- smallworld/instructions/bsid.py +67 -0
- smallworld/instructions/instructions.py +258 -0
- smallworld/instructions/mips.py +21 -0
- smallworld/instructions/x86.py +100 -0
- smallworld/logging.py +90 -0
- smallworld/platforms.py +95 -0
- smallworld/py.typed +0 -0
- smallworld/state/__init__.py +6 -0
- smallworld/state/cpus/__init__.py +32 -0
- smallworld/state/cpus/aarch64.py +563 -0
- smallworld/state/cpus/amd64.py +676 -0
- smallworld/state/cpus/arm.py +630 -0
- smallworld/state/cpus/cpu.py +71 -0
- smallworld/state/cpus/i386.py +239 -0
- smallworld/state/cpus/mips.py +374 -0
- smallworld/state/cpus/mips64.py +372 -0
- smallworld/state/cpus/powerpc.py +229 -0
- smallworld/state/cpus/riscv.py +357 -0
- smallworld/state/cpus/xtensa.py +80 -0
- smallworld/state/memory/__init__.py +7 -0
- smallworld/state/memory/code.py +70 -0
- smallworld/state/memory/elf/__init__.py +3 -0
- smallworld/state/memory/elf/elf.py +564 -0
- smallworld/state/memory/elf/rela/__init__.py +32 -0
- smallworld/state/memory/elf/rela/aarch64.py +27 -0
- smallworld/state/memory/elf/rela/amd64.py +32 -0
- smallworld/state/memory/elf/rela/arm.py +51 -0
- smallworld/state/memory/elf/rela/i386.py +32 -0
- smallworld/state/memory/elf/rela/mips.py +45 -0
- smallworld/state/memory/elf/rela/ppc.py +45 -0
- smallworld/state/memory/elf/rela/rela.py +63 -0
- smallworld/state/memory/elf/rela/riscv64.py +27 -0
- smallworld/state/memory/elf/rela/xtensa.py +15 -0
- smallworld/state/memory/elf/structs.py +55 -0
- smallworld/state/memory/heap.py +85 -0
- smallworld/state/memory/memory.py +181 -0
- smallworld/state/memory/stack/__init__.py +31 -0
- smallworld/state/memory/stack/aarch64.py +22 -0
- smallworld/state/memory/stack/amd64.py +42 -0
- smallworld/state/memory/stack/arm.py +66 -0
- smallworld/state/memory/stack/i386.py +22 -0
- smallworld/state/memory/stack/mips.py +34 -0
- smallworld/state/memory/stack/mips64.py +34 -0
- smallworld/state/memory/stack/ppc.py +34 -0
- smallworld/state/memory/stack/riscv.py +22 -0
- smallworld/state/memory/stack/stack.py +127 -0
- smallworld/state/memory/stack/xtensa.py +34 -0
- smallworld/state/models/__init__.py +6 -0
- smallworld/state/models/mmio.py +186 -0
- smallworld/state/models/model.py +163 -0
- smallworld/state/models/posix.py +455 -0
- smallworld/state/models/x86/__init__.py +2 -0
- smallworld/state/models/x86/microsoftcdecl.py +35 -0
- smallworld/state/models/x86/systemv.py +240 -0
- smallworld/state/state.py +962 -0
- smallworld/state/unstable/__init__.py +0 -0
- smallworld/state/unstable/elf.py +393 -0
- smallworld/state/x86_registers.py +30 -0
- smallworld/utils.py +935 -0
- smallworld_re-1.0.0.dist-info/LICENSE.txt +21 -0
- smallworld_re-1.0.0.dist-info/METADATA +189 -0
- smallworld_re-1.0.0.dist-info/RECORD +166 -0
- smallworld_re-1.0.0.dist-info/WHEEL +5 -0
- smallworld_re-1.0.0.dist-info/entry_points.txt +2 -0
- smallworld_re-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1013 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import abc
|
4
|
+
import typing
|
5
|
+
|
6
|
+
import claripy
|
7
|
+
|
8
|
+
from .. import platforms, utils
|
9
|
+
|
10
|
+
|
11
|
+
class Emulator(utils.MetadataMixin, metaclass=abc.ABCMeta):
|
12
|
+
"""An emulation environment.
|
13
|
+
|
14
|
+
Arguments:
|
15
|
+
platform: Platform metadata for emulation.
|
16
|
+
"""
|
17
|
+
|
18
|
+
def __init__(self, platform: platforms.Platform):
|
19
|
+
self.platform: platforms.Platform = platform
|
20
|
+
super().__init__()
|
21
|
+
self._bounds: utils.RangeCollection = utils.RangeCollection()
|
22
|
+
self._exit_points: typing.Set[int] = set()
|
23
|
+
"""Configured platform metadata."""
|
24
|
+
|
25
|
+
@abc.abstractmethod
|
26
|
+
def read_register_content(self, name: str) -> int:
|
27
|
+
"""Read the content of a register.
|
28
|
+
|
29
|
+
Arguments:
|
30
|
+
name: The name of the register.
|
31
|
+
|
32
|
+
Returns:
|
33
|
+
The register's content.
|
34
|
+
|
35
|
+
Raises:
|
36
|
+
SymbolicValueError: If the register contains a non-collapsible symbolic value
|
37
|
+
"""
|
38
|
+
|
39
|
+
return 0
|
40
|
+
|
41
|
+
def read_register_symbolic(self, name: str) -> claripy.ast.bv.BV:
|
42
|
+
"""Read the content of a register, allowing symbolic output.
|
43
|
+
|
44
|
+
If the implementation of read_register_content()
|
45
|
+
raises SymbolicValueError, this must be implemented.
|
46
|
+
|
47
|
+
Arguments:
|
48
|
+
name: The name of the register
|
49
|
+
|
50
|
+
Returns:
|
51
|
+
The register's content as a z3 expression
|
52
|
+
"""
|
53
|
+
raise NotImplementedError("This emulator does not support symbolic values")
|
54
|
+
|
55
|
+
def read_register_type(self, name: str) -> typing.Optional[typing.Any]:
|
56
|
+
"""Read the type of a register.
|
57
|
+
|
58
|
+
Note:
|
59
|
+
Implementing this behavior is optional and not necessarily
|
60
|
+
supported by all Emulators.
|
61
|
+
|
62
|
+
Arguments:
|
63
|
+
name: The name of the register.
|
64
|
+
|
65
|
+
Returns:
|
66
|
+
The register's type
|
67
|
+
"""
|
68
|
+
|
69
|
+
return None
|
70
|
+
|
71
|
+
def read_register_label(self, name: str) -> typing.Optional[str]:
|
72
|
+
"""Read the label of a register.
|
73
|
+
|
74
|
+
Note:
|
75
|
+
Implementing this behavior is optional and not necessarily
|
76
|
+
supported by all Emulators.
|
77
|
+
|
78
|
+
Arguments:
|
79
|
+
name: The name of the register.
|
80
|
+
|
81
|
+
Returns:
|
82
|
+
The register's label.
|
83
|
+
"""
|
84
|
+
|
85
|
+
return None
|
86
|
+
|
87
|
+
def read_register(self, name: str) -> int:
|
88
|
+
"""A helper to read the content of a register.
|
89
|
+
|
90
|
+
Arguments:
|
91
|
+
name: The name of the register.
|
92
|
+
|
93
|
+
Returns:
|
94
|
+
The register's content.
|
95
|
+
"""
|
96
|
+
|
97
|
+
return self.read_register_content(name)
|
98
|
+
|
99
|
+
@abc.abstractmethod
|
100
|
+
def write_register_content(
|
101
|
+
self, name: str, content: typing.Union[None, int, claripy.ast.bv.BV]
|
102
|
+
) -> None:
|
103
|
+
"""Write some content to a register.
|
104
|
+
|
105
|
+
Arguments:
|
106
|
+
name: The name of the register to write.
|
107
|
+
content: The content to write.
|
108
|
+
|
109
|
+
Raises:
|
110
|
+
SymbolicValueError: If content is a bitvector expression, and this emulator doesn't support them.
|
111
|
+
"""
|
112
|
+
|
113
|
+
pass
|
114
|
+
|
115
|
+
def write_register_type(
|
116
|
+
self, name: str, type: typing.Optional[typing.Any] = None
|
117
|
+
) -> None:
|
118
|
+
"""Write the type of a register.
|
119
|
+
|
120
|
+
Note:
|
121
|
+
Implementing this behavior is optional and not necessarily
|
122
|
+
supported by all Emulators.
|
123
|
+
|
124
|
+
Arguments:
|
125
|
+
name: The name of the register.
|
126
|
+
type: The type of the register to write. To unset the register
|
127
|
+
type, this may be set to None.
|
128
|
+
"""
|
129
|
+
|
130
|
+
pass
|
131
|
+
|
132
|
+
def write_register_label(
|
133
|
+
self, name: str, label: typing.Optional[str] = None
|
134
|
+
) -> None:
|
135
|
+
"""Write the label of a register.
|
136
|
+
|
137
|
+
Note:
|
138
|
+
Implementing this behavior is optional and not necessarily
|
139
|
+
supported by all Emulators.
|
140
|
+
|
141
|
+
Arguments:
|
142
|
+
name: The name of the register.
|
143
|
+
label: The label of the register to write. To unset the register
|
144
|
+
label, this may be set to None.
|
145
|
+
"""
|
146
|
+
|
147
|
+
pass
|
148
|
+
|
149
|
+
def write_register(
|
150
|
+
self, name: str, content: typing.Union[None, int, claripy.ast.bv.BV]
|
151
|
+
) -> None:
|
152
|
+
"""A helper to write the content of a register.
|
153
|
+
|
154
|
+
Arguments:
|
155
|
+
name: The name of the register.
|
156
|
+
content: The content to write.
|
157
|
+
|
158
|
+
Raises:
|
159
|
+
TypeError: If content is a BV, and this emulator cannot handle bitvector expressions
|
160
|
+
"""
|
161
|
+
|
162
|
+
return self.write_register_content(name, content)
|
163
|
+
|
164
|
+
@abc.abstractmethod
|
165
|
+
def read_memory_content(self, address: int, size: int) -> bytes:
|
166
|
+
"""Read memory content from a specific address.
|
167
|
+
|
168
|
+
Arguments:
|
169
|
+
address: The address of the memory region.
|
170
|
+
size: The size of the memory region.
|
171
|
+
|
172
|
+
Returns:
|
173
|
+
`size` bytes read from `address`
|
174
|
+
|
175
|
+
Raises:
|
176
|
+
SymbolicValueError: If the memory range contains a non-collapsible symbolic value
|
177
|
+
"""
|
178
|
+
|
179
|
+
return b""
|
180
|
+
|
181
|
+
def read_memory_symbolic(self, address: int, size: int) -> claripy.ast.bv.BV:
|
182
|
+
"""Read memory content from a specific address as a symbolic expression.
|
183
|
+
|
184
|
+
If the implementation of read_register_content()
|
185
|
+
raises SymbolicValueError, this must be implemented.
|
186
|
+
|
187
|
+
Arguments:
|
188
|
+
address: The address of the memory region.
|
189
|
+
size: The size of the memory region.
|
190
|
+
|
191
|
+
Returns:
|
192
|
+
A z3 expression of `size * 8` bits read from `address`
|
193
|
+
"""
|
194
|
+
raise NotImplementedError("This emulator does not support symbolic values")
|
195
|
+
|
196
|
+
def read_memory_type(self, address: int, size: int) -> typing.Optional[typing.Any]:
|
197
|
+
"""Read memory type from a specific address.
|
198
|
+
|
199
|
+
Note:
|
200
|
+
Implementing this behavior is optional and not necessarily
|
201
|
+
supported by all Emulators.
|
202
|
+
|
203
|
+
Arguments:
|
204
|
+
address: The address of the memory region.
|
205
|
+
size: The size of the memory region.
|
206
|
+
|
207
|
+
Returns:
|
208
|
+
The memory region's type.
|
209
|
+
"""
|
210
|
+
|
211
|
+
return None
|
212
|
+
|
213
|
+
def read_memory_label(self, address: int, size: int) -> typing.Optional[str]:
|
214
|
+
"""Read memory label from a specific address.
|
215
|
+
|
216
|
+
Note:
|
217
|
+
Implementing this behavior is optional and not necessarily
|
218
|
+
supported by all Emulators.
|
219
|
+
|
220
|
+
Arguments:
|
221
|
+
address: The address of the memory region.
|
222
|
+
size: The size of the memory region.
|
223
|
+
|
224
|
+
Returns:
|
225
|
+
The memory region's label.
|
226
|
+
"""
|
227
|
+
|
228
|
+
return None
|
229
|
+
|
230
|
+
def read_memory(self, address: int, size: int) -> bytes:
|
231
|
+
"""A helper to read memory content from a specific address.
|
232
|
+
|
233
|
+
Arguments:
|
234
|
+
address: The address of the memory region.
|
235
|
+
size: The size of the memory region.
|
236
|
+
|
237
|
+
Returns:
|
238
|
+
`size` bytes read from `address`.
|
239
|
+
|
240
|
+
Raises:
|
241
|
+
SymbolicValueError: If the memory range contains a non-collapsible symbolic value
|
242
|
+
"""
|
243
|
+
|
244
|
+
return self.read_memory_content(address, size)
|
245
|
+
|
246
|
+
@abc.abstractmethod
|
247
|
+
def map_memory(self, address: int, size: int) -> None:
|
248
|
+
"""Map memory of a given size.
|
249
|
+
|
250
|
+
If the requested allocation overlaps with existing regions,
|
251
|
+
this will fill in the gaps.
|
252
|
+
|
253
|
+
Arguments:
|
254
|
+
address: The requested address of the allocation.
|
255
|
+
size: The size of the allocation.
|
256
|
+
"""
|
257
|
+
|
258
|
+
pass
|
259
|
+
|
260
|
+
@abc.abstractmethod
|
261
|
+
def get_memory_map(self) -> typing.List[typing.Tuple[int, int]]:
|
262
|
+
"""Retrieve the memory map as understood by the emulator.
|
263
|
+
|
264
|
+
Returns:
|
265
|
+
The list of tuples (start, end) of the mapped segments
|
266
|
+
"""
|
267
|
+
|
268
|
+
return []
|
269
|
+
|
270
|
+
@abc.abstractmethod
|
271
|
+
def write_memory_content(
|
272
|
+
self, address: int, content: typing.Union[bytes, claripy.ast.bv.BV]
|
273
|
+
) -> None:
|
274
|
+
"""Write content to memory at a specific address.
|
275
|
+
|
276
|
+
Note:
|
277
|
+
Written memory should already be mapped by some call to
|
278
|
+
`map_memory()`.
|
279
|
+
|
280
|
+
Arguments:
|
281
|
+
address: The address of the memory region.
|
282
|
+
content: The content to write.
|
283
|
+
|
284
|
+
Raises:
|
285
|
+
TypeError: If content is a BV, and this emulator can't handle them
|
286
|
+
"""
|
287
|
+
|
288
|
+
pass
|
289
|
+
|
290
|
+
def write_memory_type(
|
291
|
+
self, address: int, size: int, type: typing.Optional[typing.Any] = None
|
292
|
+
) -> None:
|
293
|
+
"""Set the type of memory at a specific address.
|
294
|
+
|
295
|
+
Note:
|
296
|
+
Implementing this behavior is optional and not necessarily
|
297
|
+
supported by all Emulators.
|
298
|
+
|
299
|
+
Arguments:
|
300
|
+
address: The address of the memory region.
|
301
|
+
size: The size of the memory region
|
302
|
+
type: The type of the register to write. To unset the register
|
303
|
+
type, this may be set to None.
|
304
|
+
"""
|
305
|
+
|
306
|
+
pass
|
307
|
+
|
308
|
+
def write_memory_label(
|
309
|
+
self, address: int, size: int, label: typing.Optional[str] = None
|
310
|
+
) -> None:
|
311
|
+
"""Set the label of memory at a specific address.
|
312
|
+
|
313
|
+
Note:
|
314
|
+
Implementing this behavior is optional and not necessarily
|
315
|
+
supported by all Emulators.
|
316
|
+
|
317
|
+
Arguments:
|
318
|
+
address: The address of the memory region.
|
319
|
+
size: The size of the memory region
|
320
|
+
label: The label of the register to write. To unset the register
|
321
|
+
label, this may be set to None.
|
322
|
+
"""
|
323
|
+
|
324
|
+
pass
|
325
|
+
|
326
|
+
def write_memory(
|
327
|
+
self, address: int, content: typing.Union[bytes, claripy.ast.bv.BV]
|
328
|
+
) -> None:
|
329
|
+
"""A helper to write content to memory at a specific address.
|
330
|
+
|
331
|
+
Note:
|
332
|
+
Written memory should already be mapped by some call to
|
333
|
+
`map_memory()`.
|
334
|
+
|
335
|
+
Arguments:
|
336
|
+
address: The address of the memory region.
|
337
|
+
content: The content to write.
|
338
|
+
|
339
|
+
Raises:
|
340
|
+
SymbolicValueError: If `content` is a bitvector expression, and this emulator doesn't support them.
|
341
|
+
"""
|
342
|
+
|
343
|
+
self.write_memory_content(address, content)
|
344
|
+
|
345
|
+
def write_code(self, address: int, content: bytes) -> None:
|
346
|
+
"""Write executable memory at a specific address.
|
347
|
+
|
348
|
+
Implementations can take advantage of this
|
349
|
+
if they store code and memory differently.
|
350
|
+
|
351
|
+
Otherwise, it should be identical to `write_memory()`.
|
352
|
+
|
353
|
+
Note:
|
354
|
+
Written memory should already be mapped by some call to
|
355
|
+
`map_memory()`.
|
356
|
+
|
357
|
+
Arguments:
|
358
|
+
address: The address of the memory region.
|
359
|
+
content: The content to write.
|
360
|
+
|
361
|
+
"""
|
362
|
+
self.write_memory_content(address, content)
|
363
|
+
|
364
|
+
def get_bounds(self) -> typing.List[typing.Tuple[int, int]]:
|
365
|
+
"""Get a list of all registered execution bounds.
|
366
|
+
|
367
|
+
Returns:
|
368
|
+
A list of registered execution bounds.
|
369
|
+
"""
|
370
|
+
|
371
|
+
return list(self._bounds.ranges)
|
372
|
+
|
373
|
+
def add_bound(self, start: int, end: int) -> None:
|
374
|
+
"""Add valid execution bounds.
|
375
|
+
|
376
|
+
If execution leaves these bounds Emulators should raise
|
377
|
+
EmulationBoundsError.
|
378
|
+
|
379
|
+
If execution bounds are not specified, Emulators should allow execution
|
380
|
+
anywhere.
|
381
|
+
|
382
|
+
Arguments:
|
383
|
+
start: The start address of a valid executable region.
|
384
|
+
end: The end address of a valid executable region.
|
385
|
+
"""
|
386
|
+
|
387
|
+
self._bounds.add_range((start, end))
|
388
|
+
|
389
|
+
def remove_bound(self, start: int, end: int) -> None:
|
390
|
+
self._bounds.remove_range((start, end))
|
391
|
+
|
392
|
+
_exit_points: typing.Set[int] = set()
|
393
|
+
|
394
|
+
def get_exit_points(self) -> typing.Set[int]:
|
395
|
+
"""Get a list of all registered exit points.
|
396
|
+
|
397
|
+
Returns:
|
398
|
+
A list of registered exit points.
|
399
|
+
"""
|
400
|
+
|
401
|
+
return self._exit_points
|
402
|
+
|
403
|
+
def add_exit_point(self, address: int) -> None:
|
404
|
+
"""Add an exit point.
|
405
|
+
|
406
|
+
If execution reaches an exit point emulation should stop.
|
407
|
+
|
408
|
+
Arguments:
|
409
|
+
address: The address of the exit point.
|
410
|
+
"""
|
411
|
+
|
412
|
+
self._exit_points.add(address)
|
413
|
+
|
414
|
+
@abc.abstractmethod
|
415
|
+
def step_instruction(self) -> None:
|
416
|
+
"""Single instruction step execution.
|
417
|
+
|
418
|
+
Raises:
|
419
|
+
EmulationBoundsError: if execution steps out of bounds.
|
420
|
+
"""
|
421
|
+
|
422
|
+
pass
|
423
|
+
|
424
|
+
@abc.abstractmethod
|
425
|
+
def step_block(self) -> None:
|
426
|
+
"""Single block step execution.
|
427
|
+
|
428
|
+
Raises:
|
429
|
+
EmulationBoundsError: if execution steps out of bounds.
|
430
|
+
"""
|
431
|
+
|
432
|
+
pass
|
433
|
+
|
434
|
+
def step(self) -> None:
|
435
|
+
"""Helper for single instruction step execution.
|
436
|
+
|
437
|
+
Raises:
|
438
|
+
EmulationBoundsError: if execution steps out of bounds.
|
439
|
+
"""
|
440
|
+
|
441
|
+
return self.step_instruction()
|
442
|
+
|
443
|
+
@abc.abstractmethod
|
444
|
+
def run(self) -> None:
|
445
|
+
"""Run execution indefinitely.
|
446
|
+
|
447
|
+
Emulation should stop if an exit point is reached or execution leaves
|
448
|
+
valid bounds.
|
449
|
+
|
450
|
+
Raises:
|
451
|
+
EmulationBoundsError: if execution steps out of bounds.
|
452
|
+
"""
|
453
|
+
|
454
|
+
pass
|
455
|
+
|
456
|
+
@abc.abstractmethod
|
457
|
+
def __repr__(self) -> str:
|
458
|
+
return ""
|
459
|
+
|
460
|
+
|
461
|
+
class InstructionHookable(metaclass=abc.ABCMeta):
|
462
|
+
"""An Emulator mixin that supports instruction hooking."""
|
463
|
+
|
464
|
+
@abc.abstractmethod
|
465
|
+
def hook_instruction(
|
466
|
+
self, address: int, function: typing.Callable[[Emulator], None]
|
467
|
+
) -> None:
|
468
|
+
"""Hook a specific instruction by address.
|
469
|
+
|
470
|
+
Arguments:
|
471
|
+
address: The address of the hook.
|
472
|
+
function: The function to execute when the address is reached.
|
473
|
+
|
474
|
+
Example:
|
475
|
+
The hook function looks like::
|
476
|
+
|
477
|
+
def hook(emulator: Emulator) -> None:
|
478
|
+
...
|
479
|
+
"""
|
480
|
+
|
481
|
+
pass
|
482
|
+
|
483
|
+
@abc.abstractmethod
|
484
|
+
def unhook_instruction(self, address: int) -> None:
|
485
|
+
"""Unhook a specific instruction by address.
|
486
|
+
|
487
|
+
Arguments:
|
488
|
+
address: The address of the hook to remove.
|
489
|
+
"""
|
490
|
+
|
491
|
+
pass
|
492
|
+
|
493
|
+
@abc.abstractmethod
|
494
|
+
def hook_instructions(self, function: typing.Callable[[Emulator], None]) -> None:
|
495
|
+
pass
|
496
|
+
|
497
|
+
@abc.abstractmethod
|
498
|
+
def unhook_instructions(self) -> None:
|
499
|
+
"""Unhook all system interrupts."""
|
500
|
+
|
501
|
+
pass
|
502
|
+
|
503
|
+
|
504
|
+
class FunctionHookable(metaclass=abc.ABCMeta):
|
505
|
+
"""An Emulator mixin that supports function hooking."""
|
506
|
+
|
507
|
+
@abc.abstractmethod
|
508
|
+
def hook_function(
|
509
|
+
self, address: int, function: typing.Callable[[Emulator], None]
|
510
|
+
) -> None:
|
511
|
+
"""Hook a specific function by address.
|
512
|
+
|
513
|
+
After the hook function is called, the Emulator will step out of the
|
514
|
+
current function so that the hook essentially replaces a function call
|
515
|
+
to the given address.
|
516
|
+
|
517
|
+
Arguments:
|
518
|
+
address: The address of the hook.
|
519
|
+
function: The function to execute when the address is reached.
|
520
|
+
|
521
|
+
Example:
|
522
|
+
The hook function looks like::
|
523
|
+
|
524
|
+
def hook(emulator: Emulator) -> None:
|
525
|
+
...
|
526
|
+
"""
|
527
|
+
|
528
|
+
pass
|
529
|
+
|
530
|
+
@abc.abstractmethod
|
531
|
+
def unhook_function(self, address: int) -> None:
|
532
|
+
"""Unhook a specific function by address.
|
533
|
+
|
534
|
+
Arguments:
|
535
|
+
address: The address of the hook to remove.
|
536
|
+
"""
|
537
|
+
|
538
|
+
pass
|
539
|
+
|
540
|
+
|
541
|
+
class SyscallHookable(metaclass=abc.ABCMeta):
|
542
|
+
"""An emulator mixin that supports syscall hooking."""
|
543
|
+
|
544
|
+
@abc.abstractmethod
|
545
|
+
def hook_syscall(
|
546
|
+
self, number: int, function: typing.Callable[[Emulator], None]
|
547
|
+
) -> None:
|
548
|
+
"""Hook a specific syscall by number.
|
549
|
+
|
550
|
+
This hook will fire if emulation hits a platform-specific syscall instruction
|
551
|
+
invoking the specified syscall number.
|
552
|
+
|
553
|
+
Emulation will resume at the instruction after the syscall.
|
554
|
+
To change this, the handler should modify the PC register in the emulator.
|
555
|
+
|
556
|
+
Arguments:
|
557
|
+
number: The syscall number to handle
|
558
|
+
function: The handler function for this syscall
|
559
|
+
"""
|
560
|
+
pass
|
561
|
+
|
562
|
+
@abc.abstractmethod
|
563
|
+
def unhook_syscall(self, number: int) -> None:
|
564
|
+
"""Unhook a specific syscall by number.
|
565
|
+
|
566
|
+
Arguments:
|
567
|
+
number: The syscall number to unhook
|
568
|
+
"""
|
569
|
+
pass
|
570
|
+
|
571
|
+
@abc.abstractmethod
|
572
|
+
def hook_syscalls(self, function: typing.Callable[[Emulator, int], None]) -> None:
|
573
|
+
"""Hook all syscalls
|
574
|
+
|
575
|
+
This hook will fire if emulation hits a platform-specific syscall instruction.
|
576
|
+
|
577
|
+
Emulation will resume at the instruction after the syscall.
|
578
|
+
To change this, the handler should modify the PC register in the emulator.
|
579
|
+
|
580
|
+
Arguments:
|
581
|
+
function: The handler function for all syscalls
|
582
|
+
"""
|
583
|
+
pass
|
584
|
+
|
585
|
+
@abc.abstractmethod
|
586
|
+
def unhook_syscalls(self) -> None:
|
587
|
+
"""Unhook all syscalls"""
|
588
|
+
pass
|
589
|
+
|
590
|
+
|
591
|
+
class MemoryReadHookable(metaclass=abc.ABCMeta):
|
592
|
+
"""An Emulator mixin that supports memory read hooking."""
|
593
|
+
|
594
|
+
@abc.abstractmethod
|
595
|
+
def hook_memory_read(
|
596
|
+
self,
|
597
|
+
start: int,
|
598
|
+
end: int,
|
599
|
+
function: typing.Callable[[Emulator, int, int, bytes], typing.Optional[bytes]],
|
600
|
+
) -> None:
|
601
|
+
"""Hook memory reads within a given range, handling concrete values
|
602
|
+
|
603
|
+
Arguments:
|
604
|
+
start: The start address of the memory range to hook.
|
605
|
+
end: The end address of the memory range to hook.
|
606
|
+
function: The function to execute when the memory region is read.
|
607
|
+
|
608
|
+
Example:
|
609
|
+
The hook function looks like::
|
610
|
+
|
611
|
+
def hook(
|
612
|
+
emulator: Emulator,
|
613
|
+
address: int,
|
614
|
+
size: int,
|
615
|
+
content: bytes
|
616
|
+
) -> bytes:
|
617
|
+
# "content" represents the information the emulator would have fetched.
|
618
|
+
# The return value is what should be reported to the emulator.
|
619
|
+
# If return is "None", the original value of "content" will be reported.
|
620
|
+
...
|
621
|
+
|
622
|
+
"""
|
623
|
+
|
624
|
+
pass
|
625
|
+
|
626
|
+
def hook_memory_read_symbolic(
|
627
|
+
self,
|
628
|
+
start: int,
|
629
|
+
end: int,
|
630
|
+
function: typing.Callable[
|
631
|
+
[Emulator, int, int, claripy.ast.bv.BV], typing.Optional[claripy.ast.bv.BV]
|
632
|
+
],
|
633
|
+
) -> None:
|
634
|
+
"""Hook memory reads within a given range, handling symbolic values
|
635
|
+
|
636
|
+
Arguments:
|
637
|
+
start: The start address of the memory range to hook.
|
638
|
+
end: The end address of the memory range to hook.
|
639
|
+
function: The function to execute when the memory region is read.
|
640
|
+
|
641
|
+
Raises:
|
642
|
+
NotImplementedError: If this emulator doesn't support symbolic operations
|
643
|
+
|
644
|
+
Example:
|
645
|
+
The hook function looks like::
|
646
|
+
|
647
|
+
def hook(
|
648
|
+
emulator: Emulator,
|
649
|
+
address: int,
|
650
|
+
size: int,
|
651
|
+
content: claripy.ast.bv.BV
|
652
|
+
) -> typing.Optional[claripy.ast.bv.BV]:
|
653
|
+
# "content" represents the information the emulator would have fetched.
|
654
|
+
# The return value is what should be reported to the emulator.
|
655
|
+
# If return is "None", the original value of "content" will be reported.
|
656
|
+
...
|
657
|
+
"""
|
658
|
+
raise NotImplementedError("This emulator doesn't support symbolic operations")
|
659
|
+
|
660
|
+
@abc.abstractmethod
|
661
|
+
def unhook_memory_read(self, start: int, end: int) -> None:
|
662
|
+
"""Unhook a specific memory region read by address range.
|
663
|
+
|
664
|
+
Arguments:
|
665
|
+
start: The start address of the memory read hook to remove.
|
666
|
+
end: The end address of the memory read hook to remove.
|
667
|
+
"""
|
668
|
+
|
669
|
+
pass
|
670
|
+
|
671
|
+
@abc.abstractmethod
|
672
|
+
def hook_memory_reads(
|
673
|
+
self,
|
674
|
+
function: typing.Callable[[Emulator, int, int, bytes], typing.Optional[bytes]],
|
675
|
+
) -> None:
|
676
|
+
"""Hook all memory reads, handling concrete values
|
677
|
+
|
678
|
+
Arguments:
|
679
|
+
function: The function to execute when the memory region is read.
|
680
|
+
|
681
|
+
Example:
|
682
|
+
The hook function looks like::
|
683
|
+
|
684
|
+
def hook(
|
685
|
+
emulator: Emulator,
|
686
|
+
address: int,
|
687
|
+
size: int,
|
688
|
+
data: bytes
|
689
|
+
) -> typing.Optional[bytes]:
|
690
|
+
# "data" represents the information the emulator would have fetched.
|
691
|
+
# The return value is what should be reported to the emulator.
|
692
|
+
# If return is "None", the original value of "content" will be reported.
|
693
|
+
...
|
694
|
+
"""
|
695
|
+
pass
|
696
|
+
|
697
|
+
def hook_memory_reads_symbolic(
|
698
|
+
self,
|
699
|
+
function: typing.Callable[
|
700
|
+
[Emulator, int, int, claripy.ast.bv.BV], typing.Optional[claripy.ast.bv.BV]
|
701
|
+
],
|
702
|
+
) -> None:
|
703
|
+
"""Hook all memory reads, handling concrete values
|
704
|
+
|
705
|
+
Arguments:
|
706
|
+
function: The function to execute when the memory region is read.
|
707
|
+
|
708
|
+
Example:
|
709
|
+
The hook function looks like::
|
710
|
+
|
711
|
+
def hook(
|
712
|
+
emulator: Emulator,
|
713
|
+
address: int,
|
714
|
+
size: int,
|
715
|
+
content: claripy.ast.bv.BV
|
716
|
+
) -> typing.Optional[claripy.ast.bv.BV]:
|
717
|
+
# "data" represents the data fetched by the emulator
|
718
|
+
# The return value is what should be reported to the guest
|
719
|
+
...
|
720
|
+
"""
|
721
|
+
raise NotImplementedError("This emulator doesn't support symbolic operations")
|
722
|
+
|
723
|
+
@abc.abstractmethod
|
724
|
+
def unhook_memory_reads(self) -> None:
|
725
|
+
"""Unhook any 'all reads' handlers"""
|
726
|
+
|
727
|
+
pass
|
728
|
+
|
729
|
+
|
730
|
+
class MemoryWriteHookable(metaclass=abc.ABCMeta):
|
731
|
+
"""An Emulator mixin that supports memory write hooking."""
|
732
|
+
|
733
|
+
@abc.abstractmethod
|
734
|
+
def hook_memory_write(
|
735
|
+
self,
|
736
|
+
start: int,
|
737
|
+
end: int,
|
738
|
+
function: typing.Callable[[Emulator, int, int, bytes], None],
|
739
|
+
) -> None:
|
740
|
+
"""Hook memory writes within a given range, handling concrete values.
|
741
|
+
|
742
|
+
Arguments:
|
743
|
+
start: The start address of the memory range to hook.
|
744
|
+
end: The end address of the memory range to hook.
|
745
|
+
function: The function to execute when the memory region is written.
|
746
|
+
|
747
|
+
Example:
|
748
|
+
The hook function looks like::
|
749
|
+
|
750
|
+
def hook(emulator: Emulator, address: int, size: int, content: bytes) -> None:
|
751
|
+
# "content" is the value written by the guest.
|
752
|
+
# Hooks are responsible for completing the write to the emulator's state
|
753
|
+
...
|
754
|
+
"""
|
755
|
+
|
756
|
+
pass
|
757
|
+
|
758
|
+
def hook_memory_write_symbolic(
|
759
|
+
self,
|
760
|
+
start: int,
|
761
|
+
end: int,
|
762
|
+
function: typing.Callable[[Emulator, int, int, claripy.ast.bv.BV], None],
|
763
|
+
) -> None:
|
764
|
+
"""Hook memory writes within a given range, handling symbolic values
|
765
|
+
|
766
|
+
Arguments:
|
767
|
+
start: The start address of the memory range to hook.
|
768
|
+
end: The end address of the memory range to hook.
|
769
|
+
function: The function to execute when the memory region is written.
|
770
|
+
|
771
|
+
Raises:
|
772
|
+
NotImplementedError: If this emulator doesn't support symbolic operations
|
773
|
+
|
774
|
+
Example:
|
775
|
+
The hook function looks like::
|
776
|
+
|
777
|
+
def hook(emulator: Emulator, address: int, size: int, content: claripy.ast.bv.BV) -> None:
|
778
|
+
# "content" is the value written by the guest.
|
779
|
+
# Hooks are responsible for completing the write to the emulator's state
|
780
|
+
...
|
781
|
+
"""
|
782
|
+
raise NotImplementedError("This emulator doesn't support symbolic operations")
|
783
|
+
|
784
|
+
@abc.abstractmethod
|
785
|
+
def unhook_memory_write(self, start: int, end: int) -> None:
|
786
|
+
"""Unhook a specific memory region write by address range.
|
787
|
+
|
788
|
+
Arguments:
|
789
|
+
start: The start address of the memory write hook to remove.
|
790
|
+
end: The end address of the memory write hook to remove.
|
791
|
+
"""
|
792
|
+
|
793
|
+
pass
|
794
|
+
|
795
|
+
@abc.abstractmethod
|
796
|
+
def hook_memory_writes(
|
797
|
+
self, function: typing.Callable[[Emulator, int, int, bytes], None]
|
798
|
+
) -> None:
|
799
|
+
"""Hook all memory writes, handling concrete values.
|
800
|
+
|
801
|
+
Arguments:
|
802
|
+
function: The function to execute when the memory region is written.
|
803
|
+
|
804
|
+
Example:
|
805
|
+
The hook function looks like::
|
806
|
+
|
807
|
+
def hook(emulator: Emulator, address: int, size: int, content: bytes) -> None:
|
808
|
+
# "content" is the value written by the guest.
|
809
|
+
# Hooks are responsible for completing the write to the emulator's state
|
810
|
+
...
|
811
|
+
"""
|
812
|
+
|
813
|
+
pass
|
814
|
+
|
815
|
+
def hook_memory_writes_symbolic(
|
816
|
+
self,
|
817
|
+
function: typing.Callable[[Emulator, int, int, claripy.ast.bv.BV], None],
|
818
|
+
) -> None:
|
819
|
+
"""Hook all memory writes, handling symbolic values
|
820
|
+
|
821
|
+
Arguments:
|
822
|
+
function: The function to execute when the memory region is written.
|
823
|
+
|
824
|
+
Raises:
|
825
|
+
NotImplementedError: If this emulator doesn't support symbolic operations
|
826
|
+
|
827
|
+
Example:
|
828
|
+
The hook function looks like::
|
829
|
+
|
830
|
+
def hook(emulator: Emulator, address: int, size: int, content: claripy.ast.bv.BV) -> None:
|
831
|
+
# "content" is the value written by the guest.
|
832
|
+
# Hooks are responsible for completing the write to the emulator's state
|
833
|
+
...
|
834
|
+
"""
|
835
|
+
raise NotImplementedError("This emulator doesn't support symbolic operations")
|
836
|
+
|
837
|
+
@abc.abstractmethod
|
838
|
+
def unhook_memory_writes(self) -> None:
|
839
|
+
"""Unhook any global memory write hook."""
|
840
|
+
|
841
|
+
pass
|
842
|
+
|
843
|
+
|
844
|
+
class InterruptHookable(metaclass=abc.ABCMeta):
|
845
|
+
"""An Emulator mixin that supports interrupt hooking."""
|
846
|
+
|
847
|
+
@abc.abstractmethod
|
848
|
+
def hook_interrupts(self, function: typing.Callable[[Emulator, int], None]) -> None:
|
849
|
+
"""Hook any system interrupts.
|
850
|
+
|
851
|
+
Arguments:
|
852
|
+
function: The function to execute when an interrupt is triggered.
|
853
|
+
|
854
|
+
Example:
|
855
|
+
The hook function looks like::
|
856
|
+
|
857
|
+
def hook(emulator: Emulator, interrupt: int) -> None:
|
858
|
+
...
|
859
|
+
"""
|
860
|
+
|
861
|
+
pass
|
862
|
+
|
863
|
+
@abc.abstractmethod
|
864
|
+
def unhook_interrupts(self) -> None:
|
865
|
+
"""Unhook all system interrupts."""
|
866
|
+
|
867
|
+
pass
|
868
|
+
|
869
|
+
@abc.abstractmethod
|
870
|
+
def hook_interrupt(
|
871
|
+
self, interrupt: int, function: typing.Callable[[Emulator], None]
|
872
|
+
) -> None:
|
873
|
+
"""Hook a specific system interrupt.
|
874
|
+
|
875
|
+
Arguments:
|
876
|
+
function: The function to execute when the interrupt is triggered.
|
877
|
+
|
878
|
+
Example:
|
879
|
+
The hook function looks like::
|
880
|
+
|
881
|
+
def hook(emulator: Emulator) -> None:
|
882
|
+
...
|
883
|
+
"""
|
884
|
+
|
885
|
+
pass
|
886
|
+
|
887
|
+
@abc.abstractmethod
|
888
|
+
def unhook_interrupt(self, interupt: int) -> None:
|
889
|
+
"""Unhook a specific system interrupt.
|
890
|
+
|
891
|
+
Arguments:
|
892
|
+
interrupt: The interrupt to unhook.
|
893
|
+
"""
|
894
|
+
|
895
|
+
pass
|
896
|
+
|
897
|
+
|
898
|
+
class ConstrainedEmulator:
|
899
|
+
"""Emulator that supports constraints
|
900
|
+
|
901
|
+
It must also support some means of evaluating constraints,
|
902
|
+
probably an SMT solver or similar.
|
903
|
+
"""
|
904
|
+
|
905
|
+
@abc.abstractmethod
|
906
|
+
def add_constraint(self, expr: claripy.ast.bool.Bool) -> None:
|
907
|
+
"""Add a constraint to the emulator
|
908
|
+
|
909
|
+
A constraint is an expression that
|
910
|
+
this emulator will use to limit the possible values
|
911
|
+
of unbound variables.
|
912
|
+
It will only consider execution states
|
913
|
+
where all constraints can evaluate to True.
|
914
|
+
|
915
|
+
Constraints must be Boolean expressions;
|
916
|
+
the easiest form is the equality or inequality
|
917
|
+
of two bitvector expressions.
|
918
|
+
|
919
|
+
Arguments:
|
920
|
+
expr: The constraint expression to add
|
921
|
+
"""
|
922
|
+
pass
|
923
|
+
|
924
|
+
@abc.abstractmethod
|
925
|
+
def get_constraints(self) -> typing.List[claripy.ast.bool.Bool]:
|
926
|
+
"""Retrieve all constraints applied to this emulator.
|
927
|
+
|
928
|
+
Returns:
|
929
|
+
A list of constraint expressions
|
930
|
+
"""
|
931
|
+
raise NotImplementedError("Abstract method")
|
932
|
+
|
933
|
+
@abc.abstractmethod
|
934
|
+
def satisfiable(
|
935
|
+
self,
|
936
|
+
extra_constraints: typing.List[claripy.ast.bool.Bool] = [],
|
937
|
+
) -> bool:
|
938
|
+
"""Check if the current set of constraints is satisfiable
|
939
|
+
|
940
|
+
This checks if there's a way to assign variables
|
941
|
+
such that all constraint expressions evaluate to "True".
|
942
|
+
If not, the state can't exist as described.
|
943
|
+
|
944
|
+
The emulator tracks its own set of constraints,
|
945
|
+
added by the harness or built up durring execution.
|
946
|
+
The caller can provide additional constraints
|
947
|
+
for testing. These are not permanently added to the emulator.
|
948
|
+
|
949
|
+
Arguments:
|
950
|
+
extra_constraints: A list of additional constraints to consider.
|
951
|
+
|
952
|
+
Returns:
|
953
|
+
True if the constraint system is satisfiable. False otherwise.
|
954
|
+
"""
|
955
|
+
return False
|
956
|
+
|
957
|
+
@abc.abstractmethod
|
958
|
+
def eval_atmost(self, expr: claripy.ast.bv.BV, most: int) -> typing.List[int]:
|
959
|
+
"""Find a maximum number of solutions to a bitvector expression
|
960
|
+
|
961
|
+
This attempts to find concrete solutions to `expr`
|
962
|
+
given the constraints on the emulator.
|
963
|
+
|
964
|
+
It will return between 1 and `most` solutions, inclusive.
|
965
|
+
It will raise exceptions if there are no solutions,
|
966
|
+
or more than requested.
|
967
|
+
|
968
|
+
Arguments:
|
969
|
+
expr: The expression to evaluate
|
970
|
+
most: The inclusive upper limit on solutions
|
971
|
+
|
972
|
+
Returns:
|
973
|
+
A list of integer solutions to `expr`
|
974
|
+
|
975
|
+
Raises:
|
976
|
+
UnsatError: If there are no solutions for `expr` given constraints
|
977
|
+
SymbolicValueError: If there are more than `most` solutions for `expr` given constraints
|
978
|
+
"""
|
979
|
+
raise NotImplementedError("Abstract method")
|
980
|
+
|
981
|
+
@abc.abstractmethod
|
982
|
+
def eval_atleast(self, expr: claripy.ast.bv.BV, least: int) -> typing.List[int]:
|
983
|
+
"""Find a minimum number of solutions to a bitvector expression
|
984
|
+
|
985
|
+
This attempts to find concrete solutions to `expr`
|
986
|
+
given the constraints on the emulator.
|
987
|
+
|
988
|
+
It will return `least` solutions.
|
989
|
+
It will raise an exception if there are fewer than `least` solutions possible.
|
990
|
+
|
991
|
+
Arguments:
|
992
|
+
expr: The expression to evaluate
|
993
|
+
least: The number of solutions to retrieve
|
994
|
+
|
995
|
+
Returns:
|
996
|
+
A list of integer solutions to `expr`
|
997
|
+
|
998
|
+
Raises:
|
999
|
+
UnsatError: If there are no solutions for `expr` given constraints
|
1000
|
+
SymbolicValueError: If there are fewer than `least` solutions for `expr` given constraints
|
1001
|
+
"""
|
1002
|
+
raise NotImplementedError("Abstract method")
|
1003
|
+
|
1004
|
+
|
1005
|
+
__all__ = [
|
1006
|
+
"Emulator",
|
1007
|
+
"InstructionHookable",
|
1008
|
+
"FunctionHookable",
|
1009
|
+
"MemoryReadHookable",
|
1010
|
+
"MemoryWriteHookable",
|
1011
|
+
"InterruptHookable",
|
1012
|
+
"ConstrainedEmulator",
|
1013
|
+
]
|