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.
Files changed (166) hide show
  1. smallworld/__init__.py +35 -0
  2. smallworld/analyses/__init__.py +14 -0
  3. smallworld/analyses/analysis.py +88 -0
  4. smallworld/analyses/code_coverage.py +31 -0
  5. smallworld/analyses/colorizer.py +682 -0
  6. smallworld/analyses/colorizer_summary.py +100 -0
  7. smallworld/analyses/field_detection/__init__.py +14 -0
  8. smallworld/analyses/field_detection/field_analysis.py +536 -0
  9. smallworld/analyses/field_detection/guards.py +26 -0
  10. smallworld/analyses/field_detection/hints.py +133 -0
  11. smallworld/analyses/field_detection/malloc.py +211 -0
  12. smallworld/analyses/forced_exec/__init__.py +3 -0
  13. smallworld/analyses/forced_exec/forced_exec.py +87 -0
  14. smallworld/analyses/underlays/__init__.py +4 -0
  15. smallworld/analyses/underlays/basic.py +13 -0
  16. smallworld/analyses/underlays/underlay.py +31 -0
  17. smallworld/analyses/unstable/__init__.py +4 -0
  18. smallworld/analyses/unstable/angr/__init__.py +0 -0
  19. smallworld/analyses/unstable/angr/base.py +12 -0
  20. smallworld/analyses/unstable/angr/divergence.py +274 -0
  21. smallworld/analyses/unstable/angr/model.py +383 -0
  22. smallworld/analyses/unstable/angr/nwbt.py +63 -0
  23. smallworld/analyses/unstable/angr/typedefs.py +170 -0
  24. smallworld/analyses/unstable/angr/utils.py +25 -0
  25. smallworld/analyses/unstable/angr/visitor.py +315 -0
  26. smallworld/analyses/unstable/angr_nwbt.py +106 -0
  27. smallworld/analyses/unstable/code_coverage.py +54 -0
  28. smallworld/analyses/unstable/code_reachable.py +44 -0
  29. smallworld/analyses/unstable/control_flow_tracer.py +71 -0
  30. smallworld/analyses/unstable/pointer_finder.py +90 -0
  31. smallworld/arch/__init__.py +0 -0
  32. smallworld/arch/aarch64_arch.py +286 -0
  33. smallworld/arch/amd64_arch.py +86 -0
  34. smallworld/arch/i386_arch.py +44 -0
  35. smallworld/emulators/__init__.py +14 -0
  36. smallworld/emulators/angr/__init__.py +7 -0
  37. smallworld/emulators/angr/angr.py +1652 -0
  38. smallworld/emulators/angr/default.py +15 -0
  39. smallworld/emulators/angr/exceptions.py +7 -0
  40. smallworld/emulators/angr/exploration/__init__.py +9 -0
  41. smallworld/emulators/angr/exploration/bounds.py +27 -0
  42. smallworld/emulators/angr/exploration/default.py +17 -0
  43. smallworld/emulators/angr/exploration/terminate.py +22 -0
  44. smallworld/emulators/angr/factory.py +55 -0
  45. smallworld/emulators/angr/machdefs/__init__.py +35 -0
  46. smallworld/emulators/angr/machdefs/aarch64.py +292 -0
  47. smallworld/emulators/angr/machdefs/amd64.py +192 -0
  48. smallworld/emulators/angr/machdefs/arm.py +387 -0
  49. smallworld/emulators/angr/machdefs/i386.py +221 -0
  50. smallworld/emulators/angr/machdefs/machdef.py +138 -0
  51. smallworld/emulators/angr/machdefs/mips.py +184 -0
  52. smallworld/emulators/angr/machdefs/mips64.py +189 -0
  53. smallworld/emulators/angr/machdefs/ppc.py +101 -0
  54. smallworld/emulators/angr/machdefs/riscv.py +261 -0
  55. smallworld/emulators/angr/machdefs/xtensa.py +255 -0
  56. smallworld/emulators/angr/memory/__init__.py +7 -0
  57. smallworld/emulators/angr/memory/default.py +10 -0
  58. smallworld/emulators/angr/memory/fixups.py +43 -0
  59. smallworld/emulators/angr/memory/memtrack.py +105 -0
  60. smallworld/emulators/angr/scratch.py +43 -0
  61. smallworld/emulators/angr/simos.py +53 -0
  62. smallworld/emulators/angr/utils.py +70 -0
  63. smallworld/emulators/emulator.py +1013 -0
  64. smallworld/emulators/hookable.py +252 -0
  65. smallworld/emulators/panda/__init__.py +5 -0
  66. smallworld/emulators/panda/machdefs/__init__.py +28 -0
  67. smallworld/emulators/panda/machdefs/aarch64.py +93 -0
  68. smallworld/emulators/panda/machdefs/amd64.py +71 -0
  69. smallworld/emulators/panda/machdefs/arm.py +89 -0
  70. smallworld/emulators/panda/machdefs/i386.py +36 -0
  71. smallworld/emulators/panda/machdefs/machdef.py +86 -0
  72. smallworld/emulators/panda/machdefs/mips.py +94 -0
  73. smallworld/emulators/panda/machdefs/mips64.py +91 -0
  74. smallworld/emulators/panda/machdefs/ppc.py +79 -0
  75. smallworld/emulators/panda/panda.py +575 -0
  76. smallworld/emulators/unicorn/__init__.py +13 -0
  77. smallworld/emulators/unicorn/machdefs/__init__.py +28 -0
  78. smallworld/emulators/unicorn/machdefs/aarch64.py +310 -0
  79. smallworld/emulators/unicorn/machdefs/amd64.py +326 -0
  80. smallworld/emulators/unicorn/machdefs/arm.py +321 -0
  81. smallworld/emulators/unicorn/machdefs/i386.py +137 -0
  82. smallworld/emulators/unicorn/machdefs/machdef.py +117 -0
  83. smallworld/emulators/unicorn/machdefs/mips.py +202 -0
  84. smallworld/emulators/unicorn/unicorn.py +684 -0
  85. smallworld/exceptions/__init__.py +5 -0
  86. smallworld/exceptions/exceptions.py +85 -0
  87. smallworld/exceptions/unstable/__init__.py +1 -0
  88. smallworld/exceptions/unstable/exceptions.py +25 -0
  89. smallworld/extern/__init__.py +4 -0
  90. smallworld/extern/ctypes.py +94 -0
  91. smallworld/extern/unstable/__init__.py +1 -0
  92. smallworld/extern/unstable/ghidra.py +129 -0
  93. smallworld/helpers.py +107 -0
  94. smallworld/hinting/__init__.py +8 -0
  95. smallworld/hinting/hinting.py +214 -0
  96. smallworld/hinting/hints.py +427 -0
  97. smallworld/hinting/unstable/__init__.py +2 -0
  98. smallworld/hinting/utils.py +19 -0
  99. smallworld/instructions/__init__.py +18 -0
  100. smallworld/instructions/aarch64.py +20 -0
  101. smallworld/instructions/arm.py +18 -0
  102. smallworld/instructions/bsid.py +67 -0
  103. smallworld/instructions/instructions.py +258 -0
  104. smallworld/instructions/mips.py +21 -0
  105. smallworld/instructions/x86.py +100 -0
  106. smallworld/logging.py +90 -0
  107. smallworld/platforms.py +95 -0
  108. smallworld/py.typed +0 -0
  109. smallworld/state/__init__.py +6 -0
  110. smallworld/state/cpus/__init__.py +32 -0
  111. smallworld/state/cpus/aarch64.py +563 -0
  112. smallworld/state/cpus/amd64.py +676 -0
  113. smallworld/state/cpus/arm.py +630 -0
  114. smallworld/state/cpus/cpu.py +71 -0
  115. smallworld/state/cpus/i386.py +239 -0
  116. smallworld/state/cpus/mips.py +374 -0
  117. smallworld/state/cpus/mips64.py +372 -0
  118. smallworld/state/cpus/powerpc.py +229 -0
  119. smallworld/state/cpus/riscv.py +357 -0
  120. smallworld/state/cpus/xtensa.py +80 -0
  121. smallworld/state/memory/__init__.py +7 -0
  122. smallworld/state/memory/code.py +70 -0
  123. smallworld/state/memory/elf/__init__.py +3 -0
  124. smallworld/state/memory/elf/elf.py +564 -0
  125. smallworld/state/memory/elf/rela/__init__.py +32 -0
  126. smallworld/state/memory/elf/rela/aarch64.py +27 -0
  127. smallworld/state/memory/elf/rela/amd64.py +32 -0
  128. smallworld/state/memory/elf/rela/arm.py +51 -0
  129. smallworld/state/memory/elf/rela/i386.py +32 -0
  130. smallworld/state/memory/elf/rela/mips.py +45 -0
  131. smallworld/state/memory/elf/rela/ppc.py +45 -0
  132. smallworld/state/memory/elf/rela/rela.py +63 -0
  133. smallworld/state/memory/elf/rela/riscv64.py +27 -0
  134. smallworld/state/memory/elf/rela/xtensa.py +15 -0
  135. smallworld/state/memory/elf/structs.py +55 -0
  136. smallworld/state/memory/heap.py +85 -0
  137. smallworld/state/memory/memory.py +181 -0
  138. smallworld/state/memory/stack/__init__.py +31 -0
  139. smallworld/state/memory/stack/aarch64.py +22 -0
  140. smallworld/state/memory/stack/amd64.py +42 -0
  141. smallworld/state/memory/stack/arm.py +66 -0
  142. smallworld/state/memory/stack/i386.py +22 -0
  143. smallworld/state/memory/stack/mips.py +34 -0
  144. smallworld/state/memory/stack/mips64.py +34 -0
  145. smallworld/state/memory/stack/ppc.py +34 -0
  146. smallworld/state/memory/stack/riscv.py +22 -0
  147. smallworld/state/memory/stack/stack.py +127 -0
  148. smallworld/state/memory/stack/xtensa.py +34 -0
  149. smallworld/state/models/__init__.py +6 -0
  150. smallworld/state/models/mmio.py +186 -0
  151. smallworld/state/models/model.py +163 -0
  152. smallworld/state/models/posix.py +455 -0
  153. smallworld/state/models/x86/__init__.py +2 -0
  154. smallworld/state/models/x86/microsoftcdecl.py +35 -0
  155. smallworld/state/models/x86/systemv.py +240 -0
  156. smallworld/state/state.py +962 -0
  157. smallworld/state/unstable/__init__.py +0 -0
  158. smallworld/state/unstable/elf.py +393 -0
  159. smallworld/state/x86_registers.py +30 -0
  160. smallworld/utils.py +935 -0
  161. smallworld_re-1.0.0.dist-info/LICENSE.txt +21 -0
  162. smallworld_re-1.0.0.dist-info/METADATA +189 -0
  163. smallworld_re-1.0.0.dist-info/RECORD +166 -0
  164. smallworld_re-1.0.0.dist-info/WHEEL +5 -0
  165. smallworld_re-1.0.0.dist-info/entry_points.txt +2 -0
  166. 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
+ ]