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,274 @@
1
+ import logging
2
+
3
+ import angr
4
+ from angr.storage.memory_mixins.memory_mixin import MemoryMixin
5
+
6
+ from .... import hinting
7
+ from ....emulators.angr import PathTerminationSignal
8
+ from ....exceptions import AnalysisSignal
9
+ from .base import BaseMemoryMixin
10
+ from .utils import print_state
11
+ from .visitor import ConditionalVisitor
12
+
13
+ log = logging.getLogger(__name__)
14
+ hinter = hinting.get_hinter(__name__)
15
+
16
+
17
+ class DivergentAddressSignal(AnalysisSignal):
18
+ """Fault for communicating divergent address data between plugins.
19
+
20
+ Divergent address concretizations are detected
21
+ in the memory plugin, but can only be resolved
22
+ in the exploration strategy.
23
+ """
24
+
25
+ def __init__(self, state, addr, results):
26
+ self.state = state
27
+ self.addr = addr
28
+ self.results = results
29
+
30
+
31
+ class DivergenceMemoryMixin(BaseMemoryMixin):
32
+ _visitor = ConditionalVisitor()
33
+ """Mixin for handling memory-side address concretization
34
+
35
+ This hooks the actual address concretization operation,
36
+ and looks for attempts to concretize conditional addresses.
37
+ angr's default concretization is extremely imprecise
38
+ when applied to conditional expressions,
39
+ so hooking the operation gives us freedom to handle things differently.
40
+
41
+ The current strategy I like is to fork the execution state
42
+ into separate copies, one per possible evaluation of the conditional.
43
+ The actual fork operation cannot be done from within this plugin,
44
+ so it needs to communicate with DivergenceExplorationMixin.
45
+ """
46
+
47
+ def __init__(self, **kwargs):
48
+ super().__init__(**kwargs)
49
+
50
+ @MemoryMixin.memo
51
+ def copy(self, memo):
52
+ o = super().copy(memo)
53
+ o._setup_tui()
54
+ return o
55
+
56
+ def _concretize_addr(self, supercall, addr, strategies=None, condition=None):
57
+ """Helper function for performing conditional concretization.
58
+
59
+ This replaces the normal concretization strategy,
60
+ which is to compute all possible suggestions for addr,
61
+ and to assert the OR of them.
62
+
63
+ This default strategy falls over badly for addresses computed
64
+ via conditional data flow, since said addresses will be
65
+ essentially a case-statement of several possible base addresses.
66
+ The resulting assertion becomes "one of these variables stores one of these addresses."
67
+ This loses a lot of precision.
68
+
69
+ This implementation works as follows:
70
+
71
+ - Carve apart the address expression into all possible non-conditional expressions
72
+ - Concretize each possible expression independently.
73
+ - If there is more than one possible sub-expression, raise an exception.
74
+ - The exception acts as a virtual pagefault, which carries data back to the exploration strategy.
75
+ - The exploration strategy creates one state per sub-expression, constrained so that said expression is picked.
76
+
77
+ N.B.: This is in a separate helper because the operation is identical
78
+ for concretizing reads and writes.
79
+ """
80
+ exprs = dict()
81
+ guards = dict()
82
+ res = set()
83
+
84
+ block = self.state.block()
85
+ (insn,) = list(
86
+ filter(
87
+ lambda x: x.address == self.state._ip.concrete_value,
88
+ block.disassembly.insns,
89
+ )
90
+ )
91
+
92
+ try:
93
+ # Split the address into non-conditional sub-expressions.
94
+ for expr, guard in self._visitor.visit(addr):
95
+ try:
96
+ # Concretize the sub-expression normally
97
+ for tmp in supercall(
98
+ expr, strategies=strategies, condition=condition
99
+ ):
100
+ # check that the suggestion is satisfiable.
101
+ # I'd have hoped that angr does this automatically,
102
+ # but it doesn't seem to.
103
+ if self.state.satisfiable(extra_constraints=[addr == tmp]):
104
+ log.debug(
105
+ f"Concrete result for {expr}, slice of {addr}: {tmp:x} -> {self.state.memory.load(tmp, 8)}"
106
+ )
107
+ # TODO: Handle multiple concretizations from non-conditional source.
108
+ # I've never actually seen this, but you never know.
109
+ guards[expr] = guard
110
+ exprs[expr] = tmp
111
+ res.add(tmp)
112
+ else:
113
+ log.debug(
114
+ f"Ignoring result for {expr}, slice of {addr}: {tmp:x}"
115
+ )
116
+ for expr in self.state.solver.constraints:
117
+ log.debug(f"\t{expr}")
118
+ except angr.errors.SimMemoryAddressError as e:
119
+ # Something went wrong that shouldn't go wrong.
120
+ log.error(
121
+ f"Could not concretize expression {expr} with following constraints:"
122
+ )
123
+ for expr in self.state.solver.constraints:
124
+ log.error(f"\t{expr}")
125
+ log.error(f"Cause: {e}")
126
+ raise e
127
+ except AnalysisSignal as s:
128
+ # A lower analysis raised a signal.
129
+ # Raise it upwards.
130
+ raise s
131
+ except Exception as e:
132
+ # Something went wrong that shouldn't go wrong.
133
+ log.error(f"Fatal error concretizing {addr}")
134
+ log.exception(f"Cause: {type(e)} {e}")
135
+ raise e
136
+ log.debug("All recommendations:")
137
+ for expr, val in exprs.items():
138
+ log.debug(f" {expr} := {hex(val)}")
139
+ if len(exprs) > 1:
140
+ # We've got a conditional dereference.
141
+ hint = hinting.UnderSpecifiedMemoryBranchHint(
142
+ message="Conditional address dereference",
143
+ instruction=self.state._ip.concrete_value,
144
+ address=str(addr),
145
+ options=[(str(k), str(v)) for (k, v) in guards.items()],
146
+ )
147
+ hinter.info(hint)
148
+ options = {
149
+ "fork": self.divergence_fork,
150
+ "choose": self.divergence_choose,
151
+ "ignore": self.divergence_ignore,
152
+ "details": self.divergence_details,
153
+ "stop": self.divergence_stop,
154
+ "quit": self.divergence_quit,
155
+ }
156
+ option = "fork"
157
+ options[option](this=self, addr=addr, exprs=exprs)
158
+
159
+ return list(res)
160
+
161
+ def concretize_read_addr(self, addr, strategies=None, condition=None):
162
+ log.debug(f"Concretizing read addr {addr}")
163
+ return self._concretize_addr(
164
+ super().concretize_read_addr,
165
+ addr,
166
+ strategies=strategies,
167
+ condition=condition,
168
+ )
169
+
170
+ def concretize_write_addr(self, addr, strategies=None, condition=None):
171
+ log.debug(f"Concretizing write addr {addr}")
172
+ return self._concretize_addr(
173
+ super().concretize_write_addr,
174
+ addr,
175
+ strategies=strategies,
176
+ condition=condition,
177
+ )
178
+
179
+ # TUI handler methods. Fear the boilerplate.
180
+ def divergence_fork(self, addr=None, exprs=None, **kwargs):
181
+ log.warn("Rewinding and forking to avoid conditional dereference")
182
+ raise DivergentAddressSignal(self.state, addr, exprs)
183
+
184
+ def divergence_choose(**kwargs):
185
+ raise NotImplementedError(
186
+ "Chosing a specific evaluation is not yet implemented"
187
+ )
188
+
189
+ def divergence_ignore(self, **kwargs):
190
+ log.warn("Accepting conditional dereference")
191
+
192
+ def divergence_details(self, addr=None, exprs=None, **kwargs):
193
+ log.warn(f"Details of dereference at {self.state.ip}:")
194
+ print_state(log.warn, self.state, "conditional dereference")
195
+ log.warn(f"Address: {addr}")
196
+ log.warn("Possible Evaluations:")
197
+ for expr, result in exprs.items():
198
+ log.warn(f"\t{expr}: {result:x}")
199
+
200
+ def divergence_stop(self, **kwargs):
201
+ log.warn("Killing execution path")
202
+ raise PathTerminationSignal()
203
+
204
+ def divergence_quit(self, **kwargs):
205
+ log.warn("Aborting execution")
206
+ quit()
207
+
208
+
209
+ class DivergenceExplorationMixin:
210
+ """Mixin for handling exploration-side address concretization
211
+
212
+ A memory mixin can detect problematic address concretizations,
213
+ but it can't do anything about them beyond modifying
214
+ a single state.
215
+
216
+ This exploration strategy mixin allows the memory mixin
217
+ to handle exceptional cases that need to fork a state.
218
+ """
219
+
220
+ def step_state(self, simgr, state, **kwargs):
221
+ try:
222
+ out = super().step_state(simgr, state, **kwargs)
223
+ log.debug(f"Clean Successors: {state} -> {out}")
224
+ for stash, states in out.items():
225
+ if len(states) > 0:
226
+ if stash is None:
227
+ stash = "active"
228
+ for state in states:
229
+ log.debug(f"\t{state} ({stash}): {state.scratch.guard}")
230
+
231
+ except DivergentAddressSignal as e:
232
+ # Fault: we got a divergent address.
233
+ #
234
+ # This means that we tried to dereference a
235
+ # conditional symbolic expression.
236
+ # Normal address concretization causes a big loss of precision;
237
+ # binding a conditional expression doesn't clearly bind any
238
+ # one symbol.
239
+ #
240
+ # One way to handle this is to fork the state,
241
+ # with one state per possible evaluation of the
242
+ # conditional expression.
243
+ #
244
+ # The possible values and their concretizations
245
+ # are computed in the memory plugin,
246
+ # but it's not possible to fork a state in that plugin.
247
+ # It sends us its results via a DivergentAddressException,
248
+ # and we fix it up here.
249
+
250
+ # Set up the successors dict.
251
+ out = {None: list(), "unsat": list()}
252
+ log.debug(f"Divergent successors: {state} ->")
253
+
254
+ # Bind all address concretizations
255
+ backup = e.state.copy()
256
+ for expr, addr in e.results.items():
257
+ backup.solver.add(expr == addr)
258
+
259
+ # Fork a new state for each possible
260
+ # binding of the conditional address.
261
+ for expr, addr in e.results.items():
262
+ new_state = backup.copy()
263
+ new_state.solver.add(e.addr == addr)
264
+
265
+ # Test the new state for satisfiability,
266
+ # just in case the concretizer misses something.
267
+ # I wish I didn't have to do this, since it's slow.
268
+ if new_state.solver.satisfiable():
269
+ log.debug(f"\t{new_state} (active): {e.addr == addr}")
270
+ out[None].append(new_state)
271
+ else:
272
+ out["unsat"].append(new_state)
273
+ log.debug(f"\t{new_state} (unsat): {e.addr == addr}")
274
+ return out
@@ -0,0 +1,383 @@
1
+ import ctypes
2
+ import logging
3
+
4
+ import claripy
5
+ from angr.storage.memory_mixins.memory_mixin import MemoryMixin
6
+
7
+ from .... import hinting
8
+ from ....emulators.angr import PathTerminationSignal
9
+ from ....emulators.angr.utils import reg_name_from_offset
10
+ from ....extern.ctypes import TypedPointer
11
+ from .base import BaseMemoryMixin
12
+ from .visitor import EvalVisitor
13
+
14
+ log = logging.getLogger(__name__)
15
+ hinter = hinting.get_hinter(__name__)
16
+ visitor = EvalVisitor()
17
+
18
+
19
+ class ModelMemoryMixin(BaseMemoryMixin):
20
+ """
21
+ Mixin for detecting model violations in memory ops.
22
+ """
23
+
24
+ def __init__(self, **kwargs):
25
+ super().__init__(**kwargs)
26
+ self._setup_tui()
27
+
28
+ @MemoryMixin.memo
29
+ def copy(self, memo):
30
+ o = super().copy(memo)
31
+ o._setup_tui()
32
+ return o
33
+
34
+ def _handle_typed_value(self, typedef, default, pretty):
35
+ """
36
+ Process user decision for a typed variable without a value
37
+
38
+ Pointer types allow the following options:
39
+
40
+ - Allocate a new region on the heap, and point to it.
41
+ - Ase a reference to a new heap region
42
+
43
+ All types allow the following options:
44
+
45
+ - Use a placeholder symbol to track this value
46
+ - Use a user-provided integer as a concrete value (not recommended for multi-KB structs)
47
+ - Use zero/NULL as a concrete value
48
+ - Use whatever default angr suggests
49
+ - Print details of the current situation
50
+ - Abort this execution path
51
+ - Abort all execution
52
+ """
53
+
54
+ options = {
55
+ "placeholder": self.typed_value_placeholder,
56
+ "const": self.typed_value_const,
57
+ "null": self.typed_value_null,
58
+ "ignore": self.typed_value_ignore,
59
+ "stop": self.typed_value_stop,
60
+ "quit": self.typed_value_quit,
61
+ }
62
+
63
+ if issubclass(typedef, TypedPointer):
64
+ option = "alloc"
65
+ options.update(
66
+ {
67
+ "alloc": self.typed_value_alloc,
68
+ "reuse": self.typed_value_reuse,
69
+ }
70
+ )
71
+ else:
72
+ option = "placeholder"
73
+ return options[option](typedef=typedef, default=default, pretty=pretty)
74
+
75
+ def _handle_typed_symbol(self, typedef, symbol, supercall, strategies, condition):
76
+ # Symbols need special handling;
77
+ options = {
78
+ "default": self.typed_symbol_default,
79
+ "const": self.typed_value_const,
80
+ "null": self.typed_value_null,
81
+ "stop": self.typed_value_stop,
82
+ "quit": self.typed_value_quit,
83
+ }
84
+
85
+ if issubclass(typedef, TypedPointer):
86
+ option = "alloc"
87
+ options.update(
88
+ {
89
+ "alloc": self.typed_value_alloc,
90
+ "reuse": self.typed_value_reuse,
91
+ }
92
+ )
93
+ else:
94
+ option = "default"
95
+ return options[option](
96
+ typedef=typedef,
97
+ symbol=symbol,
98
+ supercall=supercall,
99
+ strategies=strategies,
100
+ condition=condition,
101
+ )
102
+
103
+ def _handle_untyped_register(self, reg_name, default):
104
+ options = {
105
+ "ignore": self.untyped_value_ignore,
106
+ "bind": self.untyped_addr_bind,
107
+ "stop": self.untyped_value_stop,
108
+ "quit": self.untyped_value_quit,
109
+ }
110
+ option = "ignore"
111
+ return options[option](reg_name=reg_name, default=default)
112
+
113
+ def _handle_untyped_address(self, addr, default):
114
+ options = {
115
+ "ignore": self.untyped_value_ignore,
116
+ "bind": self.untyped_addr_bind,
117
+ "stop": self.untyped_value_stop,
118
+ "quit": self.untyped_value_quit,
119
+ }
120
+ option = "ignore"
121
+ return options[option](addr=addr, default=default)
122
+
123
+ def _handle_untyped_symbol(self, sym_name, default):
124
+ options = {
125
+ "ignore": self.untyped_value_ignore,
126
+ "bind": self.untyped_sym_bind,
127
+ "stop": self.untyped_value_stop,
128
+ "quit": self.untyped_value_quit,
129
+ }
130
+ option = "ignore"
131
+ return options[option](sym_name=sym_name, default=default)
132
+
133
+ def _default_value(self, addr, size, **kwargs):
134
+ environ = self.state.typedefs
135
+ res = super()._default_value(addr, size, **kwargs)
136
+
137
+ block = self.state.block()
138
+ (insn,) = list(
139
+ filter(
140
+ lambda x: x.address == self.state._ip.concrete_value,
141
+ block.disassembly.insns,
142
+ )
143
+ )
144
+ if self.id == "reg":
145
+ # Thanks to Pcode, this becomes much more complicated.
146
+ # angr can't tell the difference between a read from a sub-register,
147
+ # and read from a register truncated as part of the opcode's sleigh definition.
148
+ # This makes it halucinate registers that don't actually exist.
149
+
150
+ reg_name = reg_name_from_offset(self.state.arch, addr, size)
151
+ reg_def = environ.get_register_binding(reg_name)
152
+ if reg_def is not None:
153
+ res = self._handle_typed_value(reg_def, res, reg_name)
154
+ hint = hinting.TypedUnderSpecifiedRegisterHint(
155
+ message="Register has type, but no value",
156
+ typedef=str(reg_def),
157
+ register=reg_name,
158
+ instruction=self.state._ip.concrete_value,
159
+ value=str(res),
160
+ )
161
+ hinter.info(hint)
162
+ else:
163
+ res = self._handle_untyped_register(reg_name, res)
164
+ hint = hinting.UntypedUnderSpecifiedRegisterHint(
165
+ message="Register has no type or value",
166
+ register=reg_name,
167
+ instruction=self.state._ip.concrete_value,
168
+ value=str(res),
169
+ )
170
+ hinter.info(hint)
171
+ if isinstance(res, int):
172
+ res = self.state.solver.BVV(res, size * 8)
173
+ else:
174
+ addr_def = environ.get_address_binding(addr)
175
+ if addr_def is not None:
176
+ res = self._handle_typed_value(addr_def, res, addr)
177
+ hint = hinting.TypedUnderSpecifiedMemoryHint(
178
+ message="Memory has type, but no value",
179
+ typedef=str(addr_def),
180
+ address=addr,
181
+ size=size,
182
+ instruction=self.state._ip.concrete_value,
183
+ value=str(res),
184
+ )
185
+ hinter.info(hint)
186
+ else:
187
+ hint = hinting.UntypedUnderSpecifiedMemoryHint(
188
+ message="Memory has no type or value",
189
+ address=addr,
190
+ size=size,
191
+ instruction=self.state._ip.concrete_value,
192
+ value=str(res),
193
+ )
194
+ hinter.info(hint)
195
+ self._handle_untyped_address(addr, res)
196
+
197
+ return res
198
+
199
+ def _concretize_bindings(self, supercall, addr, strategies, condition):
200
+ """
201
+ Concretization strategy for interrogating model
202
+
203
+ This is the same code for both reads and writes.
204
+ """
205
+ environ = self.state.typedefs
206
+ block = self.state.block()
207
+ (insn,) = list(
208
+ filter(
209
+ lambda x: x.address == self.state._ip.concrete_value,
210
+ block.disassembly.insns,
211
+ )
212
+ )
213
+
214
+ log.debug(f"\tAddr: {addr}")
215
+ bindings = dict()
216
+ complete = True
217
+ for v in filter(lambda x: x.op == "BVS", addr.leaf_asts()):
218
+ value = environ.get_symbol(v.args[0])
219
+ if value is None:
220
+ binding = environ.get_symbol_binding(v.args[0])
221
+ if binding is None:
222
+ log.warn(
223
+ f"Symbol {v} (part of address expression {addr}) has no type"
224
+ )
225
+ value = self._handle_untyped_symbol(v, None)
226
+ if value is None:
227
+ complete = False
228
+ continue
229
+ hint = hinting.TypedUnderSpecifiedAddressHint(
230
+ message="Symbol has no type",
231
+ symbol=v.args[0],
232
+ addr=str(addr),
233
+ instruction=self.state._ip.concrete_value,
234
+ value=str(value),
235
+ )
236
+ else:
237
+ log.warn(
238
+ f"Symbol {v} (part of address expression {addr}) has type {binding}, but no value"
239
+ )
240
+ while True:
241
+ value = self._handle_typed_symbol(
242
+ binding, v, supercall, strategies, condition
243
+ )
244
+ if value is not None and not self.state.solver.satisfiable(
245
+ extra_constraints=[v == value]
246
+ ):
247
+ log.warn(f"Selection {value:x} is not valid")
248
+ self._untyped_value_stop()
249
+ break
250
+ hint = hinting.TypedUnderSpecifiedAddressHint(
251
+ message="Symbol has type, but no value",
252
+ typedef=str(binding),
253
+ symbol=v.args[0],
254
+ addr=str(addr),
255
+ instruction=self.state._ip.concrete_value,
256
+ value=str(value),
257
+ )
258
+ hinter.info(hint)
259
+ environ.set_symbol(v.args[0], value)
260
+ if isinstance(value, int):
261
+ pretty_value = hex(value)
262
+ else:
263
+ log.error(f"Bad value for {v.args[0]}: {value} ({type(value)})")
264
+ raise NotImplementedError()
265
+ quit(1)
266
+ log.debug(f"\tNew Value for {v.args[0]}: {pretty_value}")
267
+ else:
268
+ log.debug(f"\tExisting Value for {v.args[0]}: {value:x}")
269
+ bindings[v.args[0]] = claripy.BVV(value, 64)
270
+ if complete:
271
+ # We have bindings for all symbols.
272
+ # These must be _concrete_ bindings.
273
+ value = visitor.visit(addr, bindings=bindings)
274
+ if not isinstance(value, int):
275
+ value = value.concrete_value
276
+ res = [value]
277
+ else:
278
+ log.warn(
279
+ f"Address expression {addr} not completely concretized; falling back"
280
+ )
281
+ res = supercall(addr, strategies=strategies, condition=condition)
282
+ log.debug("\tResults:")
283
+ for v in res:
284
+ if isinstance(v, int):
285
+ log.debug(f"\t\t{v:x}")
286
+ else:
287
+ log.debug(f"\t\t{v}")
288
+ return res
289
+
290
+ def concretize_read_addr(self, addr, strategies=None, condition=None):
291
+ log.debug("Concretizing on read:")
292
+ return self._concretize_bindings(
293
+ super().concretize_read_addr, addr, strategies, condition
294
+ )
295
+
296
+ def concretize_write_addr(self, addr, strategies=None, condition=None):
297
+ log.debug("Concretizing on write:")
298
+ return self._concretize_bindings(
299
+ super().concretize_write_addr, addr, strategies, condition
300
+ )
301
+
302
+ # TUI handler functions. Fear the boilerplate.
303
+
304
+ def typed_value_alloc(self, typedef=None, **kwargs):
305
+ # User wants to allocate a new instance
306
+ environ = self.state.typedefs
307
+ res = environ.allocate(typedef.type)
308
+ log.warn(f"Allocated {ctypes.sizeof(typedef.type)} bytes at {res:x}")
309
+ return res
310
+
311
+ def typed_value_reuse(self, typedef=None, **kwargs):
312
+ raise NotImplementedError("Reuse requires human input.")
313
+
314
+ def typed_value_placeholder(self, typedef=None, **kwargs):
315
+ # User wants to assign a placeholder symbol, not a real value.
316
+ if hasattr(typedef, "__fields__"):
317
+ log.info(f"{typedef} is struct-like")
318
+ raise NotImplementedError(f"Not handling {typedef}")
319
+ else:
320
+ res = claripy.BVS(f"{typedef.__name__}", ctypes.sizeof(typedef) * 8)
321
+ self.state.typedefs.bind_symbol(res, typedef)
322
+
323
+ log.warn(f"Assigned placeholder {res}")
324
+ return res
325
+
326
+ def typed_value_const(self, **kwargs):
327
+ # User wants to provide their own value
328
+ res = input("( hex ) > ")
329
+ res = int(res, 16)
330
+ log.warn(f"Using user-provided value {res:x}")
331
+ return res
332
+
333
+ def typed_value_null(self, **kwargs):
334
+ log.warn("Using NULL")
335
+ return 0
336
+
337
+ def typed_value_ignore(self, default=None, **kwargs):
338
+ if default is None:
339
+ log.warn("Will use default when determined.")
340
+ elif isinstance(default, int):
341
+ log.warn(f"Using default {default:x}")
342
+ else:
343
+ log.warn(f"Using default {default}")
344
+ return default
345
+
346
+ def typed_symbol_default(self, symbol, supercall, strategies, condition, **kwargs):
347
+ res = supercall(symbol, strategies=strategies, condition=condition)[0]
348
+ log.warn(f"Concretizing {symbol} to {res:x}")
349
+ return res
350
+
351
+ def typed_value_stop(self, **kwargs):
352
+ log.warn("Stopping execution path")
353
+ raise PathTerminationSignal()
354
+
355
+ def typed_value_quit(self, **kwargs):
356
+ log.warn("Aborting execution")
357
+ quit()
358
+
359
+ def untyped_value_ignore(self, default=None, **kwargs):
360
+ if default is None:
361
+ log.warn("Will use default when generated")
362
+ elif isinstance(default, int):
363
+ log.warn(f"Using default value {default:x}")
364
+ else:
365
+ log.warn(f"Using default value {default}")
366
+ return default
367
+
368
+ def untyped_reg_bind(**kwargs):
369
+ raise NotImplementedError("Type binding not implemented for registers")
370
+
371
+ def untyped_addr_bind(**kwargs):
372
+ raise NotImplementedError("Type binding not implemented for addresses")
373
+
374
+ def untyped_sym_bind(**kwargs):
375
+ raise NotImplementedError("Type binding not implemented for symbols")
376
+
377
+ def untyped_value_stop(self, **kwargs):
378
+ self.warn("Stopping self execution path")
379
+ raise PathTerminationSignal()
380
+
381
+ def untyped_value_quit(self, **kwargs):
382
+ log.warn("Aborting execution")
383
+ quit()