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,133 @@
1
+ import dataclasses
2
+ import typing
3
+
4
+ from ... import hinting
5
+
6
+
7
+ class ClaripySerializable(hinting.Serializable):
8
+ """Serializable wrapper that allows serializing claripy expressions in hints."""
9
+
10
+ @classmethod
11
+ def claripy_to_dict(cls, expr):
12
+ if (
13
+ expr is None
14
+ or isinstance(expr, int)
15
+ or isinstance(expr, str)
16
+ or isinstance(expr, bool)
17
+ ):
18
+ return expr
19
+ else:
20
+ return {"op": expr.op, "args": list(map(cls.claripy_to_dict, expr.args))}
21
+
22
+ def __init__(self, expr):
23
+ self.expr = expr
24
+
25
+ def to_dict(self):
26
+ return self.claripy_to_dict(self.expr)
27
+
28
+ @classmethod
29
+ def from_dict(cls, dict):
30
+ raise NotImplementedError(
31
+ "Rebuilding clairpy is a lot harder than tearing it apart"
32
+ )
33
+
34
+
35
+ @dataclasses.dataclass(frozen=True)
36
+ class FieldHint(hinting.Hint):
37
+ address: int = 0
38
+ size: int = 0
39
+
40
+ def pp(self, out):
41
+ out(self.message)
42
+ out(f" address: {hex(self.address)}")
43
+ out(f" size: {self.size}")
44
+
45
+
46
+ @dataclasses.dataclass(frozen=True)
47
+ class TrackedFieldHint(FieldHint):
48
+ label: str = ""
49
+
50
+ def pp(self, out):
51
+ super().pp(out)
52
+ out(f" label: {self.label}")
53
+
54
+
55
+ @dataclasses.dataclass(frozen=True)
56
+ class FieldEventHint(FieldHint):
57
+ """Hint representing a detected, unhandled field"""
58
+
59
+ pc: int = 0
60
+ guards: typing.List[typing.Tuple[int, ClaripySerializable]] = dataclasses.field(
61
+ default_factory=list
62
+ )
63
+ access: str = ""
64
+
65
+ def pp(self, out):
66
+ super().pp(out)
67
+ out(f" pc: {hex(self.pc)}")
68
+ out(f" access: {self.access}")
69
+ out(" guards:")
70
+ for pc, guard in self.guards:
71
+ out(
72
+ f" {hex(pc)}: {guard.expr.shallow_repr()} [{list(filter(lambda x: x.op != 'BVV', guard.expr.leaf_asts()))}]"
73
+ )
74
+
75
+
76
+ @dataclasses.dataclass(frozen=True)
77
+ class UnknownFieldHint(FieldEventHint):
78
+ """Hint representing an access of an unknown field.
79
+
80
+ The expression loaded from memory is not
81
+ a simple slice of any known label.
82
+ """
83
+
84
+ message: str = "Accessed unknown field" # Don't need to replace
85
+ expr: str = ""
86
+
87
+ def pp(self, out):
88
+ super().pp(out)
89
+ out(f" expr: {self.expr}")
90
+
91
+
92
+ @dataclasses.dataclass(frozen=True)
93
+ class PartialByteFieldAccessHint(FieldEventHint):
94
+ """Hint representing an access to part of a known field."""
95
+
96
+ message: str = "Partial access to known field" # Don't need to replace
97
+ label: str = ""
98
+ start: int = 0
99
+ end: int = 0
100
+
101
+ def pp(self, out):
102
+ super().pp(out)
103
+ out(f" field: {self.label}[{self.start}:{self.end}]")
104
+
105
+
106
+ @dataclasses.dataclass(frozen=True)
107
+ class PartialByteFieldWriteHint(PartialByteFieldAccessHint):
108
+ """Hint representing a write to part of a known field.
109
+
110
+ Also includes the data I'm trying to write
111
+ """
112
+
113
+ message: str = "Partial write to known field" # Don't need to replace
114
+ access: str = "write" # Don't need to replace
115
+ expr: str = ""
116
+
117
+ def pp(self, out):
118
+ super().pp(out)
119
+ out(f" expr: {self.expr}")
120
+
121
+
122
+ @dataclasses.dataclass(frozen=True)
123
+ class PartialBitFieldAccessHint(FieldEventHint):
124
+ """Hint representing an access to a bit field within a known field."""
125
+
126
+ message: str = "Bit field access in known field" # Don't need to replace
127
+ label: str = ""
128
+ start: int = 0
129
+ end: int = 0
130
+
131
+ def pp(self, out):
132
+ super().pp(out)
133
+ out(f" field: {self.label}[{self.start}:{self.end}]")
@@ -0,0 +1,211 @@
1
+ import logging
2
+ import typing
3
+
4
+ import claripy
5
+
6
+ from ... import emulators, exceptions, platforms, state
7
+ from ...emulators.angr.exceptions import PathTerminationSignal
8
+
9
+ log = logging.getLogger(__name__)
10
+
11
+
12
+ class MallocModel(state.models.Model):
13
+ name = "malloc"
14
+ platform = platforms.Platform(
15
+ platforms.Architecture.X86_64, platforms.Byteorder.LITTLE
16
+ )
17
+ abi = platforms.ABI.SYSTEMV
18
+
19
+ _arg1_for_arch = {
20
+ platforms.Architecture.AARCH64: "x0",
21
+ platforms.Architecture.ARM_V5T: "r0",
22
+ platforms.Architecture.ARM_V7A: "r0",
23
+ platforms.Architecture.MIPS32: "a0",
24
+ platforms.Architecture.MIPS64: "a0",
25
+ platforms.Architecture.POWERPC32: "r3",
26
+ platforms.Architecture.X86_64: "rdi",
27
+ }
28
+
29
+ _ret_for_arch = {
30
+ platforms.Architecture.AARCH64: "x0",
31
+ platforms.Architecture.ARM_V5T: "r0",
32
+ platforms.Architecture.ARM_V7A: "r0",
33
+ platforms.Architecture.MIPS32: "v0",
34
+ platforms.Architecture.MIPS64: "v0",
35
+ platforms.Architecture.POWERPC32: "r3",
36
+ platforms.Architecture.X86_64: "rax",
37
+ }
38
+
39
+ def __init__(
40
+ self,
41
+ address: int,
42
+ heap: state.memory.heap.Heap,
43
+ platform: platforms.Platform,
44
+ read_callback,
45
+ write_callback,
46
+ ):
47
+ super().__init__(address)
48
+
49
+ self.arg1_reg = self._arg1_for_arch[platform.architecture]
50
+ self.ret_reg = self._ret_for_arch[platform.architecture]
51
+
52
+ if len(heap) > 0:
53
+ raise exceptions.ConfigurationError("This only works with a blank heap")
54
+ end = state.IntegerValue(heap.address + heap.get_capacity(), 8, None)
55
+ ptr = state.IntegerValue(heap.address + 16, 8, None)
56
+
57
+ heap.allocate(end)
58
+ heap.allocate(ptr)
59
+
60
+ self.heap_addr = heap.address
61
+ self.read_callback = read_callback
62
+ self.write_callback = write_callback
63
+
64
+ self.struct_lengths: typing.Dict[str, int] = dict()
65
+ self.struct_prefixes: typing.Dict[str, str] = dict()
66
+ self.struct_fields: typing.Dict[
67
+ str, typing.List[typing.Tuple[int, str]]
68
+ ] = dict()
69
+
70
+ def bind_length_to_struct(
71
+ self, field: str, prefix: str, labels: typing.List[typing.Tuple[int, str]]
72
+ ):
73
+ self.struct_lengths[field] = 0
74
+ self.struct_prefixes[field] = prefix
75
+ for size, label in labels:
76
+ self.struct_lengths[field] += size
77
+ self.struct_fields[field] = labels
78
+
79
+ def model(self, emulator: emulators.Emulator):
80
+ if not isinstance(emulator, emulators.AngrEmulator):
81
+ raise exceptions.ConfigurationError("Model only works with angr")
82
+ # Read the capacity.
83
+ # Bypass the smallworld API; I want to know if it's symbolic
84
+ fda = emulator.get_extension("fda")
85
+ capacity = emulator.read_register_symbolic(self.arg1_reg)
86
+ length = 0
87
+
88
+ if capacity.symbolic:
89
+ # Capacity is a symbolic expression.
90
+ # Check if it's collapsible
91
+ good = True
92
+ try:
93
+ vals = emulator.eval_atmost(capacity, 1)
94
+ except exceptions.UnsatError:
95
+ log.error("Capacity is unsat")
96
+ good = False
97
+ except exceptions.SymbolicValueError:
98
+ log.error("Capacity did not collapse to one value")
99
+ good = False
100
+
101
+ if not good or len(vals) > 1:
102
+ log.error("The following fields are lengths:")
103
+ for var in capacity.variables:
104
+ log.error(f" {var}")
105
+ log.error("Concretize them to continue analysis")
106
+ raise PathTerminationSignal()
107
+
108
+ length = vals[0]
109
+ else:
110
+ length = capacity.concrete_value
111
+
112
+ heap_end = int.from_bytes(
113
+ emulator.read_memory_content(self.heap_addr, 8), "little"
114
+ )
115
+ heap_ptr = int.from_bytes(
116
+ emulator.read_memory_content(self.heap_addr + 8, 8), "little"
117
+ )
118
+
119
+ if heap_end - heap_ptr < length:
120
+ # OOM; Return NULL
121
+ log.warning(
122
+ f"malloc: OOM! Need {length}, only have {hex(heap_end)} - {hex(heap_ptr)} = {heap_end - heap_ptr}"
123
+ )
124
+ res = 0
125
+ else:
126
+ # Return the pointer to the new region.
127
+ log.warning(f"malloc: Alloc'd {length} bytes at {hex(heap_ptr)}")
128
+ res = heap_ptr
129
+ heap_ptr += length
130
+ emulator.write_memory_content(
131
+ self.heap_addr + 8, heap_ptr.to_bytes(8, "little")
132
+ )
133
+
134
+ # Check if this is something we want to track.
135
+ fields = list(map(lambda x: x.split("_")[0], capacity.variables))
136
+
137
+ if len(fields) != 1:
138
+ # Don't track; too complex
139
+ log.warn(" Length has multiple variables; not solving")
140
+ elif fields[0] not in self.struct_lengths:
141
+ # Don't track; not something we asked to track
142
+ log.warn(f" Length field {fields[0]} not known")
143
+ else:
144
+ struct_length = self.struct_lengths[fields[0]]
145
+ struct_prefix = self.struct_prefixes[fields[0]]
146
+ struct_labels = self.struct_fields[fields[0]]
147
+
148
+ sym = list(filter(lambda x: x.op == "BVS", capacity.leaf_asts()))[0]
149
+ if not isinstance(sym, claripy.ast.bv.BV):
150
+ raise TypeError("BVS isn't a bitvector: {sym}")
151
+ n = emulator.eval_atmost(sym, 1)[0]
152
+
153
+ if length // n != struct_length:
154
+ # Don't track; not an obvious "n * sizeof(struct foo)"
155
+ log.warn(f" {length} // {n} != {struct_length}")
156
+ elif length % struct_length != 0:
157
+ # Don't track; not an obvious "n * sizeof(struct foo)"
158
+ log.warn(f" {length} not evenly divisible by {n}")
159
+ else:
160
+ # Track!
161
+ log.warn(f" Alloc of {n} items")
162
+ addr = res
163
+ for i in range(0, n):
164
+ struct_fields = list()
165
+ off = 0
166
+ for flen, fname in struct_labels:
167
+ # Build a symbol for this field of this item
168
+ flabel = struct_prefix + "." + str(i) + "." + fname
169
+ expr = claripy.BVS(flabel, flen * 8, explicit_name=True)
170
+ struct_fields.append(expr)
171
+
172
+ # Track the new field
173
+ r = range(addr + off, addr + off + flen)
174
+ fda.fda_labels.add(flabel)
175
+ fda.fda_addr_to_label[r] = flabel
176
+ fda.fda_label_to_addr[flabel] = r
177
+ fda.fda_bindings[flabel] = expr
178
+
179
+ off += flen
180
+
181
+ # Insert the whole struct into memory
182
+ expr = claripy.Concat(*struct_fields)
183
+ emulator.write_memory(addr, expr)
184
+
185
+ addr += struct_length
186
+
187
+ # Hook the entire array
188
+ fda.fda_mem_ranges.add((res, res + length))
189
+ emulator.hook_memory_read_symbolic(
190
+ res, res + length, self.read_callback
191
+ )
192
+ emulator.hook_memory_write_symbolic(
193
+ res, res + length, self.write_callback
194
+ )
195
+
196
+ emulator.write_register_content(self.ret_reg, res)
197
+
198
+
199
+ class FreeModel(state.models.Model):
200
+ name = "free"
201
+ platform = platforms.Platform(
202
+ platforms.Architecture.X86_64, platforms.Byteorder.LITTLE
203
+ )
204
+ abi = platforms.ABI.SYSTEMV
205
+
206
+ def __init__(self, address: int):
207
+ super().__init__(address)
208
+
209
+ def model(self, emulator: emulators.Emulator):
210
+ # Just free it.
211
+ return
@@ -0,0 +1,3 @@
1
+ from .forced_exec import ForcedExecution, ForcedExecutionUnderlay
2
+
3
+ __all__ = ["ForcedExecution", "ForcedExecutionUnderlay"]
@@ -0,0 +1,87 @@
1
+ import logging
2
+ import typing
3
+
4
+ from ...emulators import AngrEmulator
5
+ from ...exceptions import EmulationStop
6
+ from ...platforms import Platform
7
+ from ...state import Machine
8
+ from ..underlays import AnalysisUnderlay
9
+
10
+ log = logging.getLogger(__name__)
11
+
12
+
13
+ class ForcedExecutionUnderlay(AnalysisUnderlay):
14
+ """Forced execution analysis underlay
15
+
16
+ This allows you to emulate arbitrary program slices
17
+ by forcing the emulator to visit specific instructions,
18
+ ignoring the normal program control flow.
19
+
20
+ This isn't a complete analysis;
21
+ instead, it's a dummy base class that makes it easy
22
+ to support forced execution mode by implementing
23
+ the complex logic as an overlay,
24
+ and building the actual analysis as a combination
25
+ of overlay and underlay.
26
+ See field detection to see what I mean.
27
+
28
+ NOTE: This is not compatible with all architectures.
29
+ The architecture needs to support single-stepping;
30
+ delay slot architectures such as MIPS can't
31
+ be single-stepped by angr.
32
+
33
+ Arguments:
34
+ trace: The list of program counter addresses you want to visit
35
+
36
+ """
37
+
38
+ def __init__(self, trace: typing.List[typing.Dict[str, int]]):
39
+ self.trace: typing.List[typing.Dict[str, int]] = trace
40
+
41
+ def execute(self):
42
+ try:
43
+ for regs in self.trace:
44
+ for reg, val in regs.items():
45
+ self.emulator.write_register_content(reg, val)
46
+ self.emulator.step()
47
+ except EmulationStop:
48
+ pass
49
+
50
+
51
+ class ForcedExecution(ForcedExecutionUnderlay):
52
+ """Forced execution using angr
53
+
54
+ This allows you to emulate arbitrary program slices
55
+ by forcing the emulator to visit specific instructions,
56
+ ignoring the normal program control flow.
57
+
58
+ NOTE: This is not compatible with all architectures.
59
+ The architecture needs to support single-stepping;
60
+ delay slot architectures such as MIPS can't
61
+ be single-stepped by angr.
62
+
63
+ Arguments:
64
+ platform: The platform you want to emulate
65
+ trace: The list of program counter addresses you want to visit
66
+ """
67
+
68
+ name = "forced-execution"
69
+ description = "Forced execution using angr"
70
+ version = "0.0.1"
71
+
72
+ def __init__(self, platform: Platform, trace: typing.List[typing.Dict[str, int]]):
73
+ super().__init__(trace)
74
+ self.platform: Platform = platform
75
+ self.emulator = AngrEmulator(platform)
76
+ self.emulator.enable_linear()
77
+
78
+ def run(self, machine: Machine):
79
+ emulator = self.emulator
80
+ if not isinstance(emulator, AngrEmulator):
81
+ raise TypeError("Impossible!")
82
+ machine.apply(emulator)
83
+ emulator.initialize()
84
+ self.execute()
85
+ for s in emulator.mgr.active:
86
+ log.info(s.solver.constraints)
87
+ s.registers.pp(log.info)
@@ -0,0 +1,4 @@
1
+ from .basic import BasicAnalysisUnderlay
2
+ from .underlay import AnalysisUnderlay
3
+
4
+ __all__ = ["AnalysisUnderlay", "BasicAnalysisUnderlay"]
@@ -0,0 +1,13 @@
1
+ from ...exceptions import EmulationStop
2
+ from .underlay import AnalysisUnderlay
3
+
4
+
5
+ class BasicAnalysisUnderlay(AnalysisUnderlay):
6
+ """Basic analysis underlay that steps until done"""
7
+
8
+ def execute(self):
9
+ try:
10
+ while True:
11
+ self.emulator.step()
12
+ except EmulationStop:
13
+ pass
@@ -0,0 +1,31 @@
1
+ import abc
2
+
3
+ from ...emulators import Emulator
4
+ from ..analysis import Analysis
5
+
6
+
7
+ class AnalysisUnderlay(Analysis):
8
+ """Base class for execution underlays
9
+
10
+ Some analyses are orthogonal to
11
+ exactly how their program gets actuated.
12
+ In those cases, the author can write the
13
+ bulk of the analysis in an overlay,
14
+ and pair that overlay with different underlays.
15
+ """
16
+
17
+ @property
18
+ def emulator(self) -> Emulator:
19
+ """The emulator to run
20
+ Underlays need the overlay to define the emulator.
21
+ """
22
+ return self._emulator
23
+
24
+ @emulator.setter
25
+ def emulator(self, emu: Emulator):
26
+ self._emulator = emu
27
+
28
+ @abc.abstractmethod
29
+ def execute(self) -> None:
30
+ """Exercise the emulator"""
31
+ raise NotImplementedError()
@@ -0,0 +1,4 @@
1
+ # from .colorizer import Colorizer
2
+ # from .colorizer_summary import ColorizerSummary
3
+
4
+ # __all__ = ["Colorizer", "ColorizerSummary"]
File without changes
@@ -0,0 +1,12 @@
1
+ from angr.storage.memory_mixins.memory_mixin import MemoryMixin
2
+
3
+
4
+ class BaseMemoryMixin(MemoryMixin): # type: ignore[misc]
5
+ """Base class for memory mixins.
6
+
7
+ I wanted to add the _setup_tui() method,
8
+ and needed a base class to make multiple inheritance happen cleanly.
9
+ """
10
+
11
+ def _setup_tui(self):
12
+ pass