smallworld-re 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- smallworld/__init__.py +35 -0
- smallworld/analyses/__init__.py +14 -0
- smallworld/analyses/analysis.py +88 -0
- smallworld/analyses/code_coverage.py +31 -0
- smallworld/analyses/colorizer.py +682 -0
- smallworld/analyses/colorizer_summary.py +100 -0
- smallworld/analyses/field_detection/__init__.py +14 -0
- smallworld/analyses/field_detection/field_analysis.py +536 -0
- smallworld/analyses/field_detection/guards.py +26 -0
- smallworld/analyses/field_detection/hints.py +133 -0
- smallworld/analyses/field_detection/malloc.py +211 -0
- smallworld/analyses/forced_exec/__init__.py +3 -0
- smallworld/analyses/forced_exec/forced_exec.py +87 -0
- smallworld/analyses/underlays/__init__.py +4 -0
- smallworld/analyses/underlays/basic.py +13 -0
- smallworld/analyses/underlays/underlay.py +31 -0
- smallworld/analyses/unstable/__init__.py +4 -0
- smallworld/analyses/unstable/angr/__init__.py +0 -0
- smallworld/analyses/unstable/angr/base.py +12 -0
- smallworld/analyses/unstable/angr/divergence.py +274 -0
- smallworld/analyses/unstable/angr/model.py +383 -0
- smallworld/analyses/unstable/angr/nwbt.py +63 -0
- smallworld/analyses/unstable/angr/typedefs.py +170 -0
- smallworld/analyses/unstable/angr/utils.py +25 -0
- smallworld/analyses/unstable/angr/visitor.py +315 -0
- smallworld/analyses/unstable/angr_nwbt.py +106 -0
- smallworld/analyses/unstable/code_coverage.py +54 -0
- smallworld/analyses/unstable/code_reachable.py +44 -0
- smallworld/analyses/unstable/control_flow_tracer.py +71 -0
- smallworld/analyses/unstable/pointer_finder.py +90 -0
- smallworld/arch/__init__.py +0 -0
- smallworld/arch/aarch64_arch.py +286 -0
- smallworld/arch/amd64_arch.py +86 -0
- smallworld/arch/i386_arch.py +44 -0
- smallworld/emulators/__init__.py +14 -0
- smallworld/emulators/angr/__init__.py +7 -0
- smallworld/emulators/angr/angr.py +1652 -0
- smallworld/emulators/angr/default.py +15 -0
- smallworld/emulators/angr/exceptions.py +7 -0
- smallworld/emulators/angr/exploration/__init__.py +9 -0
- smallworld/emulators/angr/exploration/bounds.py +27 -0
- smallworld/emulators/angr/exploration/default.py +17 -0
- smallworld/emulators/angr/exploration/terminate.py +22 -0
- smallworld/emulators/angr/factory.py +55 -0
- smallworld/emulators/angr/machdefs/__init__.py +35 -0
- smallworld/emulators/angr/machdefs/aarch64.py +292 -0
- smallworld/emulators/angr/machdefs/amd64.py +192 -0
- smallworld/emulators/angr/machdefs/arm.py +387 -0
- smallworld/emulators/angr/machdefs/i386.py +221 -0
- smallworld/emulators/angr/machdefs/machdef.py +138 -0
- smallworld/emulators/angr/machdefs/mips.py +184 -0
- smallworld/emulators/angr/machdefs/mips64.py +189 -0
- smallworld/emulators/angr/machdefs/ppc.py +101 -0
- smallworld/emulators/angr/machdefs/riscv.py +261 -0
- smallworld/emulators/angr/machdefs/xtensa.py +255 -0
- smallworld/emulators/angr/memory/__init__.py +7 -0
- smallworld/emulators/angr/memory/default.py +10 -0
- smallworld/emulators/angr/memory/fixups.py +43 -0
- smallworld/emulators/angr/memory/memtrack.py +105 -0
- smallworld/emulators/angr/scratch.py +43 -0
- smallworld/emulators/angr/simos.py +53 -0
- smallworld/emulators/angr/utils.py +70 -0
- smallworld/emulators/emulator.py +1013 -0
- smallworld/emulators/hookable.py +252 -0
- smallworld/emulators/panda/__init__.py +5 -0
- smallworld/emulators/panda/machdefs/__init__.py +28 -0
- smallworld/emulators/panda/machdefs/aarch64.py +93 -0
- smallworld/emulators/panda/machdefs/amd64.py +71 -0
- smallworld/emulators/panda/machdefs/arm.py +89 -0
- smallworld/emulators/panda/machdefs/i386.py +36 -0
- smallworld/emulators/panda/machdefs/machdef.py +86 -0
- smallworld/emulators/panda/machdefs/mips.py +94 -0
- smallworld/emulators/panda/machdefs/mips64.py +91 -0
- smallworld/emulators/panda/machdefs/ppc.py +79 -0
- smallworld/emulators/panda/panda.py +575 -0
- smallworld/emulators/unicorn/__init__.py +13 -0
- smallworld/emulators/unicorn/machdefs/__init__.py +28 -0
- smallworld/emulators/unicorn/machdefs/aarch64.py +310 -0
- smallworld/emulators/unicorn/machdefs/amd64.py +326 -0
- smallworld/emulators/unicorn/machdefs/arm.py +321 -0
- smallworld/emulators/unicorn/machdefs/i386.py +137 -0
- smallworld/emulators/unicorn/machdefs/machdef.py +117 -0
- smallworld/emulators/unicorn/machdefs/mips.py +202 -0
- smallworld/emulators/unicorn/unicorn.py +684 -0
- smallworld/exceptions/__init__.py +5 -0
- smallworld/exceptions/exceptions.py +85 -0
- smallworld/exceptions/unstable/__init__.py +1 -0
- smallworld/exceptions/unstable/exceptions.py +25 -0
- smallworld/extern/__init__.py +4 -0
- smallworld/extern/ctypes.py +94 -0
- smallworld/extern/unstable/__init__.py +1 -0
- smallworld/extern/unstable/ghidra.py +129 -0
- smallworld/helpers.py +107 -0
- smallworld/hinting/__init__.py +8 -0
- smallworld/hinting/hinting.py +214 -0
- smallworld/hinting/hints.py +427 -0
- smallworld/hinting/unstable/__init__.py +2 -0
- smallworld/hinting/utils.py +19 -0
- smallworld/instructions/__init__.py +18 -0
- smallworld/instructions/aarch64.py +20 -0
- smallworld/instructions/arm.py +18 -0
- smallworld/instructions/bsid.py +67 -0
- smallworld/instructions/instructions.py +258 -0
- smallworld/instructions/mips.py +21 -0
- smallworld/instructions/x86.py +100 -0
- smallworld/logging.py +90 -0
- smallworld/platforms.py +95 -0
- smallworld/py.typed +0 -0
- smallworld/state/__init__.py +6 -0
- smallworld/state/cpus/__init__.py +32 -0
- smallworld/state/cpus/aarch64.py +563 -0
- smallworld/state/cpus/amd64.py +676 -0
- smallworld/state/cpus/arm.py +630 -0
- smallworld/state/cpus/cpu.py +71 -0
- smallworld/state/cpus/i386.py +239 -0
- smallworld/state/cpus/mips.py +374 -0
- smallworld/state/cpus/mips64.py +372 -0
- smallworld/state/cpus/powerpc.py +229 -0
- smallworld/state/cpus/riscv.py +357 -0
- smallworld/state/cpus/xtensa.py +80 -0
- smallworld/state/memory/__init__.py +7 -0
- smallworld/state/memory/code.py +70 -0
- smallworld/state/memory/elf/__init__.py +3 -0
- smallworld/state/memory/elf/elf.py +564 -0
- smallworld/state/memory/elf/rela/__init__.py +32 -0
- smallworld/state/memory/elf/rela/aarch64.py +27 -0
- smallworld/state/memory/elf/rela/amd64.py +32 -0
- smallworld/state/memory/elf/rela/arm.py +51 -0
- smallworld/state/memory/elf/rela/i386.py +32 -0
- smallworld/state/memory/elf/rela/mips.py +45 -0
- smallworld/state/memory/elf/rela/ppc.py +45 -0
- smallworld/state/memory/elf/rela/rela.py +63 -0
- smallworld/state/memory/elf/rela/riscv64.py +27 -0
- smallworld/state/memory/elf/rela/xtensa.py +15 -0
- smallworld/state/memory/elf/structs.py +55 -0
- smallworld/state/memory/heap.py +85 -0
- smallworld/state/memory/memory.py +181 -0
- smallworld/state/memory/stack/__init__.py +31 -0
- smallworld/state/memory/stack/aarch64.py +22 -0
- smallworld/state/memory/stack/amd64.py +42 -0
- smallworld/state/memory/stack/arm.py +66 -0
- smallworld/state/memory/stack/i386.py +22 -0
- smallworld/state/memory/stack/mips.py +34 -0
- smallworld/state/memory/stack/mips64.py +34 -0
- smallworld/state/memory/stack/ppc.py +34 -0
- smallworld/state/memory/stack/riscv.py +22 -0
- smallworld/state/memory/stack/stack.py +127 -0
- smallworld/state/memory/stack/xtensa.py +34 -0
- smallworld/state/models/__init__.py +6 -0
- smallworld/state/models/mmio.py +186 -0
- smallworld/state/models/model.py +163 -0
- smallworld/state/models/posix.py +455 -0
- smallworld/state/models/x86/__init__.py +2 -0
- smallworld/state/models/x86/microsoftcdecl.py +35 -0
- smallworld/state/models/x86/systemv.py +240 -0
- smallworld/state/state.py +962 -0
- smallworld/state/unstable/__init__.py +0 -0
- smallworld/state/unstable/elf.py +393 -0
- smallworld/state/x86_registers.py +30 -0
- smallworld/utils.py +935 -0
- smallworld_re-1.0.0.dist-info/LICENSE.txt +21 -0
- smallworld_re-1.0.0.dist-info/METADATA +189 -0
- smallworld_re-1.0.0.dist-info/RECORD +166 -0
- smallworld_re-1.0.0.dist-info/WHEEL +5 -0
- smallworld_re-1.0.0.dist-info/entry_points.txt +2 -0
- smallworld_re-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,252 @@
|
|
1
|
+
import typing
|
2
|
+
|
3
|
+
from .emulator import (
|
4
|
+
Emulator,
|
5
|
+
FunctionHookable,
|
6
|
+
InstructionHookable,
|
7
|
+
InterruptHookable,
|
8
|
+
MemoryReadHookable,
|
9
|
+
MemoryWriteHookable,
|
10
|
+
)
|
11
|
+
|
12
|
+
|
13
|
+
def range_intersect(r1, r2):
|
14
|
+
return range(max(r1.start, r2.start), min(r1.stop, r2.stop)) or None
|
15
|
+
|
16
|
+
|
17
|
+
def range_to_hex_str(r):
|
18
|
+
return f"[{r.start:x}..{r.stop:x}]"
|
19
|
+
|
20
|
+
|
21
|
+
class QInstructionHookable(InstructionHookable):
|
22
|
+
"""Implementation of instruction hook data structure mgmt to be used by qemu-based emulators."""
|
23
|
+
|
24
|
+
def __init__(self: typing.Any) -> None:
|
25
|
+
super().__init__()
|
26
|
+
self.instruction_hooks: typing.Dict[int, typing.Callable[[Emulator], None]] = {}
|
27
|
+
self.all_instructions_hook: typing.Optional[
|
28
|
+
typing.Callable[[Emulator], None]
|
29
|
+
] = None
|
30
|
+
|
31
|
+
def hook_instructions(self, function: typing.Callable[[Emulator], None]) -> None:
|
32
|
+
self.all_instructions_hook = function
|
33
|
+
|
34
|
+
def unhook_instructions(self):
|
35
|
+
self.all_instructions_hook = None
|
36
|
+
|
37
|
+
def hook_instruction(
|
38
|
+
self, address: int, function: typing.Callable[[Emulator], None]
|
39
|
+
) -> None:
|
40
|
+
if address in self.instruction_hooks:
|
41
|
+
raise ValueError(
|
42
|
+
f"can't hook instruction at {address:x} since already hooked"
|
43
|
+
)
|
44
|
+
self.instruction_hooks[address] = function
|
45
|
+
|
46
|
+
def unhook_instruction(self, address: int) -> None:
|
47
|
+
if address not in self.instruction_hooks:
|
48
|
+
raise ValueError(
|
49
|
+
f"can't unhook instruction at {address:x} since its not already hooked"
|
50
|
+
)
|
51
|
+
self.instruction_hooks.pop(address, None)
|
52
|
+
|
53
|
+
def is_instruction_hooked(
|
54
|
+
self, address: int
|
55
|
+
) -> typing.Optional[typing.Callable[[Emulator], None]]:
|
56
|
+
if address in self.instruction_hooks:
|
57
|
+
return self.instruction_hooks[address]
|
58
|
+
else:
|
59
|
+
return None
|
60
|
+
|
61
|
+
|
62
|
+
class QFunctionHookable(FunctionHookable):
|
63
|
+
"""Implementation of function hook data structure mgmt to be used by qemu-based emulators."""
|
64
|
+
|
65
|
+
def __init__(self: typing.Any) -> None:
|
66
|
+
super().__init__()
|
67
|
+
self.function_hooks: typing.Dict[int, typing.Callable[[Emulator], None]] = {}
|
68
|
+
|
69
|
+
def hook_function(
|
70
|
+
self, address: int, function: typing.Callable[[Emulator], None]
|
71
|
+
) -> None:
|
72
|
+
if address in self.function_hooks:
|
73
|
+
raise ValueError(f"can't hook function at {address:x} since already hooked")
|
74
|
+
self.function_hooks[address] = function
|
75
|
+
|
76
|
+
def unhook_function(self, address: int) -> None:
|
77
|
+
if address not in self.function_hooks:
|
78
|
+
raise ValueError(
|
79
|
+
f"can't unhook function at {address:x} since its not already hooked"
|
80
|
+
)
|
81
|
+
self.function_hooks.pop(address, None)
|
82
|
+
|
83
|
+
def is_function_hooked(
|
84
|
+
self, address: int
|
85
|
+
) -> typing.Optional[typing.Callable[[Emulator], None]]:
|
86
|
+
if address in self.function_hooks:
|
87
|
+
return self.function_hooks[address]
|
88
|
+
else:
|
89
|
+
return None
|
90
|
+
|
91
|
+
|
92
|
+
class QMemoryReadHookable(MemoryReadHookable):
|
93
|
+
"""Implementation of memory read hook data structure mgmt to be used by qemu-based emulators."""
|
94
|
+
|
95
|
+
def __init__(self: typing.Any) -> None:
|
96
|
+
super().__init__()
|
97
|
+
self.memory_read_hooks: typing.Dict[
|
98
|
+
range, typing.Callable[[Emulator, int, int, bytes], typing.Optional[bytes]]
|
99
|
+
] = {}
|
100
|
+
self.all_reads_hook: typing.Optional[
|
101
|
+
typing.Callable[[Emulator, int, int, bytes], typing.Optional[bytes]]
|
102
|
+
] = None
|
103
|
+
|
104
|
+
def hook_memory_reads(
|
105
|
+
self,
|
106
|
+
function: typing.Callable[[Emulator, int, int, bytes], typing.Optional[bytes]],
|
107
|
+
) -> None:
|
108
|
+
self.all_reads_hook = function
|
109
|
+
|
110
|
+
def unhook_memory_reads(self):
|
111
|
+
self.all_reads_hook = None
|
112
|
+
|
113
|
+
def hook_memory_read(
|
114
|
+
self,
|
115
|
+
start: int,
|
116
|
+
end: int,
|
117
|
+
function: typing.Callable[[Emulator, int, int, bytes], typing.Optional[bytes]],
|
118
|
+
) -> None:
|
119
|
+
new_range = range(start, end)
|
120
|
+
for r in self.memory_read_hooks:
|
121
|
+
if range_intersect(r, new_range):
|
122
|
+
raise ValueError(
|
123
|
+
f"can't hook memory read range {range_to_hex_str(new_range)} since that overlaps already hooked range {range_to_hex_str(r)}"
|
124
|
+
)
|
125
|
+
self.memory_read_hooks[new_range] = function
|
126
|
+
|
127
|
+
def unhook_memory_read(self, start: int, end: int) -> None:
|
128
|
+
unh_r = range(start, end)
|
129
|
+
for r in self.memory_read_hooks:
|
130
|
+
if unh_r == r:
|
131
|
+
self.memory_read_hooks.pop(r, None)
|
132
|
+
return
|
133
|
+
raise ValueError(
|
134
|
+
f"can't unhook memory read range {range_to_hex_str(unh_r)} since its not already hooked"
|
135
|
+
)
|
136
|
+
|
137
|
+
# def unhook_memory_read(address: int) -> None:
|
138
|
+
# if address not in self.memory_read_hooks:
|
139
|
+
# raise ValueError(
|
140
|
+
# f"can't unhook memory read range {range_to_hex_str(address)} since its not already hooked"
|
141
|
+
# )
|
142
|
+
# self.memory_read_hooks.pop(address, None)
|
143
|
+
|
144
|
+
def is_memory_read_hooked(
|
145
|
+
self, address: int
|
146
|
+
) -> typing.Optional[
|
147
|
+
typing.Callable[[Emulator, int, int, bytes], typing.Optional[bytes]]
|
148
|
+
]:
|
149
|
+
for rng in self.memory_read_hooks:
|
150
|
+
if address in rng:
|
151
|
+
return self.memory_read_hooks[rng]
|
152
|
+
return None
|
153
|
+
|
154
|
+
|
155
|
+
class QMemoryWriteHookable(MemoryWriteHookable):
|
156
|
+
"""Implementation of memory write hook data structure mgmt to be used by qemu-based emulators."""
|
157
|
+
|
158
|
+
def __init__(self: typing.Any) -> None:
|
159
|
+
super().__init__()
|
160
|
+
self.memory_write_hooks: typing.Dict[
|
161
|
+
range, typing.Callable[[Emulator, int, int, bytes], None]
|
162
|
+
] = {}
|
163
|
+
self.all_writes_hook: typing.Optional[
|
164
|
+
typing.Callable[[Emulator, int, int, bytes], None]
|
165
|
+
] = None
|
166
|
+
|
167
|
+
def hook_memory_writes(
|
168
|
+
self, function: typing.Callable[[Emulator, int, int, bytes], None]
|
169
|
+
) -> None:
|
170
|
+
self.all_writes_hook = function
|
171
|
+
|
172
|
+
def unhook_memory_writes(self):
|
173
|
+
self.all_writes_hook = None
|
174
|
+
|
175
|
+
def hook_memory_write(
|
176
|
+
self,
|
177
|
+
start: int,
|
178
|
+
end: int,
|
179
|
+
function: typing.Callable[[Emulator, int, int, bytes], None],
|
180
|
+
) -> None:
|
181
|
+
new_range = range(start, end)
|
182
|
+
for r in self.memory_write_hooks:
|
183
|
+
if range_intersect(r, new_range):
|
184
|
+
raise ValueError(
|
185
|
+
f"can't hook memory write range {range_to_hex_str(new_range)} since that overlaps already hooked range {range_to_hex_str(r)}"
|
186
|
+
)
|
187
|
+
self.memory_write_hooks[new_range] = function
|
188
|
+
|
189
|
+
def unhook_memory_write(self, start: int, end: int) -> None:
|
190
|
+
unh_r = range(start, end)
|
191
|
+
for r in self.memory_write_hooks:
|
192
|
+
if unh_r == r:
|
193
|
+
self.memory_write_hooks.pop(r, None)
|
194
|
+
return
|
195
|
+
raise ValueError(
|
196
|
+
f"can't unhook memory write range {range_to_hex_str(unh_r)} since its not already hooked"
|
197
|
+
)
|
198
|
+
|
199
|
+
# def unhook_memory_write(self, address: int) -> None:
|
200
|
+
# if address not in self.memory_write_hooks:
|
201
|
+
# raise ValueError(
|
202
|
+
# f"can't unhook memory write range {range_to_hex_str(address)} since its not already hooked"
|
203
|
+
# )
|
204
|
+
# self.memory_write_hooks.pop(address, None)
|
205
|
+
def is_memory_write_hooked(
|
206
|
+
self, address: int
|
207
|
+
) -> typing.Optional[typing.Callable[[Emulator, int, int, bytes], None]]:
|
208
|
+
for rng in self.memory_write_hooks:
|
209
|
+
if address in rng:
|
210
|
+
return self.memory_write_hooks[rng]
|
211
|
+
return None
|
212
|
+
|
213
|
+
|
214
|
+
class QInterruptHookable(InterruptHookable):
|
215
|
+
"""Implementation of interrupt hook data structure mgmt to be used by qemu-based emulators."""
|
216
|
+
|
217
|
+
def __init__(self: typing.Any) -> None:
|
218
|
+
super().__init__()
|
219
|
+
self.all_interrupts_hook: typing.Optional[
|
220
|
+
typing.Callable[[Emulator, int], None]
|
221
|
+
] = None
|
222
|
+
self.interrupt_hooks: typing.Dict[int, typing.Callable[[Emulator], None]] = {}
|
223
|
+
|
224
|
+
def hook_interrupts(self, function: typing.Callable[[Emulator, int], None]) -> None:
|
225
|
+
self.all_interrupts_hook = function
|
226
|
+
|
227
|
+
def unhook_interrupts(self):
|
228
|
+
self.all_interrupts_hook = None
|
229
|
+
|
230
|
+
def hook_interrupt(
|
231
|
+
self, intno: int, function: typing.Callable[[Emulator], None]
|
232
|
+
) -> None:
|
233
|
+
if intno in self.interrupt_hooks:
|
234
|
+
raise ValueError(
|
235
|
+
f"can't hook interrupt number {intno} since its already hooked"
|
236
|
+
)
|
237
|
+
self.interrupt_hooks[intno] = function
|
238
|
+
|
239
|
+
def unhook_interrupt(self, intno: int) -> None:
|
240
|
+
if intno not in self.interrupt_hooks:
|
241
|
+
raise ValueError(
|
242
|
+
f"asked to unhook interrupt {intno} which was not previously hooked"
|
243
|
+
)
|
244
|
+
self.interrupt_hooks.pop(intno, None)
|
245
|
+
|
246
|
+
def is_interrupt_hooked(
|
247
|
+
self, intno: int
|
248
|
+
) -> typing.Optional[typing.Callable[[Emulator], None]]:
|
249
|
+
if intno in self.interrupt_hooks:
|
250
|
+
return self.interrupt_hooks[intno]
|
251
|
+
else:
|
252
|
+
return None
|
@@ -0,0 +1,28 @@
|
|
1
|
+
from .aarch64 import AArch64MachineDef
|
2
|
+
from .amd64 import AMD64MachineDef
|
3
|
+
from .arm import ( # ARMv6MMachineDef,; ARMv6MThumbMachineDef,
|
4
|
+
ARMv5TMachineDef,
|
5
|
+
ARMv7MMachineDef,
|
6
|
+
)
|
7
|
+
from .i386 import i386MachineDef
|
8
|
+
from .machdef import PandaMachineDef
|
9
|
+
from .mips import MIPSBEMachineDef, MIPSELMachineDef
|
10
|
+
from .mips64 import MIPS64BEMachineDef # , MIPS64ELMachineDef
|
11
|
+
from .ppc import PowerPC32MachineDef # , PowerPC64MachineDef
|
12
|
+
|
13
|
+
__all__ = [
|
14
|
+
"AArch64MachineDef",
|
15
|
+
"AMD64MachineDef",
|
16
|
+
"PandaMachineDef",
|
17
|
+
"ARMv5TMachineDef",
|
18
|
+
# "ARMv6MMachineDef",
|
19
|
+
# "ARMv6MThumbMachineDef",
|
20
|
+
"ARMv7MMachineDef",
|
21
|
+
"i386MachineDef",
|
22
|
+
"MIPSBEMachineDef",
|
23
|
+
"MIPSELMachineDef",
|
24
|
+
"MIPS64BEMachineDef",
|
25
|
+
# "MIPS64ELMachineDef",
|
26
|
+
"PowerPC32MachineDef",
|
27
|
+
# "PowerPC64MachineDef",
|
28
|
+
]
|
@@ -0,0 +1,93 @@
|
|
1
|
+
import capstone
|
2
|
+
|
3
|
+
from ....platforms import Architecture, Byteorder
|
4
|
+
from .machdef import PandaMachineDef
|
5
|
+
|
6
|
+
|
7
|
+
class AArch64MachineDef(PandaMachineDef):
|
8
|
+
arch = Architecture.AARCH64
|
9
|
+
byteorder = Byteorder.LITTLE
|
10
|
+
|
11
|
+
cs_arch = capstone.CS_ARCH_ARM64
|
12
|
+
cs_mode = capstone.CS_MODE_ARM | capstone.CS_MODE_LITTLE_ENDIAN
|
13
|
+
|
14
|
+
panda_arch = "aarch64"
|
15
|
+
|
16
|
+
# I'm going to define all the ones we are making possible as of now
|
17
|
+
# I need to submit a PR to change to X86 32 bit and to includ eflags
|
18
|
+
def __init__(self):
|
19
|
+
self._registers = {
|
20
|
+
"x0": "x0",
|
21
|
+
"w0": "x0",
|
22
|
+
"x1": "x1",
|
23
|
+
"w1": "x1",
|
24
|
+
"x2": "x2",
|
25
|
+
"w2": "x2",
|
26
|
+
"x3": "x3",
|
27
|
+
"w3": "x3",
|
28
|
+
"x4": "x4",
|
29
|
+
"w4": "x4",
|
30
|
+
"x5": "x5",
|
31
|
+
"w5": "x5",
|
32
|
+
"x6": "x6",
|
33
|
+
"w6": "x6",
|
34
|
+
"x7": "x7",
|
35
|
+
"w7": "x7",
|
36
|
+
"x8": "xr",
|
37
|
+
"w8": "xr",
|
38
|
+
"xr": "xr",
|
39
|
+
"x9": "x9",
|
40
|
+
"w9": "x9",
|
41
|
+
"x10": "x10",
|
42
|
+
"w10": "x10",
|
43
|
+
"x11": "x11",
|
44
|
+
"w11": "x11",
|
45
|
+
"x12": "x12",
|
46
|
+
"w12": "x12",
|
47
|
+
"x13": "x13",
|
48
|
+
"w13": "x13",
|
49
|
+
"x14": "x14",
|
50
|
+
"w14": "x14",
|
51
|
+
"x15": "x15",
|
52
|
+
"w15": "x15",
|
53
|
+
"x16": "ip0",
|
54
|
+
"w16": "ip0",
|
55
|
+
"ip0": "ip0",
|
56
|
+
"x17": "ip1",
|
57
|
+
"w17": "ip1",
|
58
|
+
"ip1": "ip1",
|
59
|
+
"x18": "pr",
|
60
|
+
"w18": "pr",
|
61
|
+
"pr": "pr",
|
62
|
+
"x19": "x19",
|
63
|
+
"w19": "x19",
|
64
|
+
"x20": "x20",
|
65
|
+
"w20": "x20",
|
66
|
+
"x21": "x21",
|
67
|
+
"w21": "x21",
|
68
|
+
"x22": "x22",
|
69
|
+
"w22": "x22",
|
70
|
+
"x23": "x23",
|
71
|
+
"w23": "x23",
|
72
|
+
"x24": "x24",
|
73
|
+
"w24": "x24",
|
74
|
+
"x25": "x25",
|
75
|
+
"w25": "x25",
|
76
|
+
"x26": "x26",
|
77
|
+
"w26": "x26",
|
78
|
+
"x27": "x27",
|
79
|
+
"w27": "x27",
|
80
|
+
"x28": "x28",
|
81
|
+
"w28": "x28",
|
82
|
+
"x29": "fp",
|
83
|
+
"w29": "fp",
|
84
|
+
"fp": "fp",
|
85
|
+
"x30": "lr",
|
86
|
+
"w30": "lr",
|
87
|
+
"lr": "lr",
|
88
|
+
"pc": "pc",
|
89
|
+
"sp": "sp",
|
90
|
+
"wsp": "sp",
|
91
|
+
}
|
92
|
+
|
93
|
+
self._registers = {i: j for i, j in self._registers.items()}
|
@@ -0,0 +1,71 @@
|
|
1
|
+
import capstone
|
2
|
+
|
3
|
+
from ....platforms import Architecture, Byteorder
|
4
|
+
from .machdef import PandaMachineDef
|
5
|
+
|
6
|
+
|
7
|
+
class AMD64MachineDef(PandaMachineDef):
|
8
|
+
arch = Architecture.X86_64
|
9
|
+
byteorder = Byteorder.LITTLE
|
10
|
+
|
11
|
+
panda_arch = "x86_64"
|
12
|
+
|
13
|
+
cs_arch = capstone.CS_ARCH_X86
|
14
|
+
cs_mode = capstone.CS_MODE_64
|
15
|
+
|
16
|
+
# I'm going to define all the ones we are making possible as of now
|
17
|
+
# I need to submit a PR to change to X86 32 bit and to includ eflags
|
18
|
+
_registers_64 = {
|
19
|
+
"rax",
|
20
|
+
"rbx",
|
21
|
+
"rcx",
|
22
|
+
"rdx",
|
23
|
+
"rsi",
|
24
|
+
"rdi",
|
25
|
+
"rsp",
|
26
|
+
"rbp",
|
27
|
+
"rip",
|
28
|
+
"r8",
|
29
|
+
"r9",
|
30
|
+
"r10",
|
31
|
+
"r11",
|
32
|
+
"r12",
|
33
|
+
"r13",
|
34
|
+
"r14",
|
35
|
+
"r15",
|
36
|
+
}
|
37
|
+
_registers_general = {"eax", "ebx", "ecx", "edx", "esi", "edi", "esp", "ebp", "eip"}
|
38
|
+
_registers_short = {"ax", "bx", "cx", "dx", "si", "di", "sp", "bp"}
|
39
|
+
_registers_byte = {"al", "bl", "cl", "dl", "ah", "bh", "ch", "dh"}
|
40
|
+
_registers_seg = {"es", "cs", "ss", "ds", "fs", "gs"}
|
41
|
+
_registers_control = {"cr0", "cr1", "cr2", "cr3", "cr4"}
|
42
|
+
_registers_mmr = {"gdtr": "gdt", "idtr": "idt", "tr": "tr", "ldtr": "ldt"}
|
43
|
+
_registers_xmm = {
|
44
|
+
"xmm0",
|
45
|
+
"xmm1",
|
46
|
+
"xmm2",
|
47
|
+
"xmm3",
|
48
|
+
"xmm4",
|
49
|
+
"xmm5",
|
50
|
+
"xmm6",
|
51
|
+
"xmm7",
|
52
|
+
"xmm8",
|
53
|
+
"xmm9",
|
54
|
+
"xmm10",
|
55
|
+
"xmm11",
|
56
|
+
"xmm12",
|
57
|
+
"xmm13",
|
58
|
+
"xmm14",
|
59
|
+
"xmm15",
|
60
|
+
}
|
61
|
+
_register_pc = {"pc": "rip"}
|
62
|
+
|
63
|
+
_registers = {}
|
64
|
+
_registers = _registers | {i: i for i in _registers_64}
|
65
|
+
_registers = _registers | {i: i for i in _registers_general}
|
66
|
+
_registers = _registers | {i: i for i in _registers_byte}
|
67
|
+
_registers = _registers | {i: i for i in _registers_seg}
|
68
|
+
_registers = _registers | {i: i for i in _registers_control}
|
69
|
+
_registers = _registers | {i: j for i, j in _registers_mmr.items()}
|
70
|
+
_registers = _registers | {i: i for i in _registers_xmm}
|
71
|
+
_registers = _registers | {i: j for i, j in _register_pc.items()}
|
@@ -0,0 +1,89 @@
|
|
1
|
+
import capstone
|
2
|
+
|
3
|
+
from ....platforms import Architecture, Byteorder
|
4
|
+
from .machdef import PandaMachineDef
|
5
|
+
|
6
|
+
|
7
|
+
class ARMMachineDef(PandaMachineDef):
|
8
|
+
cs_arch = capstone.CS_ARCH_ARM
|
9
|
+
cs_mode = capstone.CS_MODE_ARM | capstone.CS_MODE_LITTLE_ENDIAN
|
10
|
+
|
11
|
+
panda_arch = "arm"
|
12
|
+
|
13
|
+
# I'm going to define all the ones we are making possible as of now
|
14
|
+
# I need to submit a PR to change to X86 32 bit and to includ eflags
|
15
|
+
def __init__(self):
|
16
|
+
self._registers = {
|
17
|
+
"r0",
|
18
|
+
"r1",
|
19
|
+
"r2",
|
20
|
+
"r3",
|
21
|
+
"r4",
|
22
|
+
"r5",
|
23
|
+
"r6",
|
24
|
+
"r7",
|
25
|
+
"r8",
|
26
|
+
"r9",
|
27
|
+
"r10",
|
28
|
+
"r11",
|
29
|
+
"r12",
|
30
|
+
"sp",
|
31
|
+
"lr",
|
32
|
+
"ip",
|
33
|
+
}
|
34
|
+
|
35
|
+
self._registers = {i: i for i in self._registers}
|
36
|
+
self._registers = self._registers | {"pc": "ip"}
|
37
|
+
|
38
|
+
|
39
|
+
class ARMMachineMixinM:
|
40
|
+
"""Mixin for ARM M-series machine models"""
|
41
|
+
|
42
|
+
def __init__(self):
|
43
|
+
super().__init__()
|
44
|
+
self._registers_m = {
|
45
|
+
# NOTE: None of the expected privileged registers exist
|
46
|
+
# "psr",
|
47
|
+
# "primask",
|
48
|
+
# "basepri",
|
49
|
+
# "faultmask",
|
50
|
+
# "control",
|
51
|
+
# "msp",
|
52
|
+
# "psp",
|
53
|
+
}
|
54
|
+
self._registers = self._registers | {i: i for i in self._registers_m}
|
55
|
+
|
56
|
+
|
57
|
+
class ARMMachineMixinA:
|
58
|
+
"""Mixin for ARM A-series machine models"""
|
59
|
+
|
60
|
+
def __init__(self):
|
61
|
+
super().__init__()
|
62
|
+
# TODO: QEMU doesn't quite support what I expect.
|
63
|
+
# I expected to see cpsr and spsr.
|
64
|
+
# I either got the CPU model wrong, or something else is weird.
|
65
|
+
self._registers_a = {
|
66
|
+
"psr",
|
67
|
+
}
|
68
|
+
self._registers = self._registers | {i: i for i in self._registers_a}
|
69
|
+
|
70
|
+
|
71
|
+
class ARMv5TMachineDef(ARMMachineDef):
|
72
|
+
arch = Architecture.ARM_V5T
|
73
|
+
byteorder = Byteorder.LITTLE
|
74
|
+
cpu = "pxa255"
|
75
|
+
|
76
|
+
|
77
|
+
# TODO: Something's very weird with Panda's Arm 7 models.
|
78
|
+
# cortex-a9 should be an A-series, but it looks more like an M-series.
|
79
|
+
# cortex-m4 looks like an M-series, but aborts; I suspect we're missing configuration.
|
80
|
+
class ARMv7AMachineDef(ARMMachineMixinA, ARMMachineDef):
|
81
|
+
arch = Architecture.ARM_V7A
|
82
|
+
byteorder = Byteorder.LITTLE
|
83
|
+
cpu = "cortex-a9"
|
84
|
+
|
85
|
+
|
86
|
+
class ARMv7MMachineDef(ARMMachineMixinM, ARMMachineDef):
|
87
|
+
arch = Architecture.ARM_V7M
|
88
|
+
byteorder = Byteorder.LITTLE
|
89
|
+
cpu = "cortex-m4"
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import capstone
|
2
|
+
|
3
|
+
from ....platforms import Architecture, Byteorder
|
4
|
+
from .machdef import PandaMachineDef
|
5
|
+
|
6
|
+
|
7
|
+
class i386MachineDef(PandaMachineDef):
|
8
|
+
arch = Architecture.X86_32
|
9
|
+
byteorder = Byteorder.LITTLE
|
10
|
+
|
11
|
+
panda_arch = "i386"
|
12
|
+
|
13
|
+
cs_arch = capstone.CS_ARCH_X86
|
14
|
+
cs_mode = capstone.CS_MODE_32
|
15
|
+
|
16
|
+
# I'm going to define all the ones we are making possible as of now
|
17
|
+
# I need to submit a PR to change to X86 32 bit and to includ eflags
|
18
|
+
_registers_general = {"eax", "ebx", "ecx", "edx", "esi", "edi", "esp", "ebp", "eip"}
|
19
|
+
_registers_short = {"ax", "bx", "cx", "dx", "si", "di", "sp", "bp"}
|
20
|
+
_registers_byte = {"al", "bl", "cl", "dl", "ah", "bh", "ch", "dh"}
|
21
|
+
_registers_seg = {"es", "cs", "ss", "ds", "fs", "gs"}
|
22
|
+
_registers_control = {"cr0", "cr1", "cr2", "cr3", "cr4"}
|
23
|
+
_registers_mmr = {"gdtr": "gdt", "idtr": "idt", "tr": "tr", "ldtr": "ldt"}
|
24
|
+
_register_pc = {"pc": "eip"}
|
25
|
+
|
26
|
+
_registers = {}
|
27
|
+
_registers = _registers | {i: i for i in _registers_general}
|
28
|
+
_registers = _registers | {i: i for i in _registers_byte}
|
29
|
+
_registers = _registers | {i: i for i in _registers_seg}
|
30
|
+
_registers = _registers | {i: i for i in _registers_control}
|
31
|
+
_registers = _registers | {i: j for i, j in _registers_mmr.items()}
|
32
|
+
_registers = _registers | {i: j for i, j in _register_pc.items()}
|
33
|
+
# _registers = (
|
34
|
+
# _registers_general | _registers_byte | _registers_seg | _registers_control
|
35
|
+
# )
|
36
|
+
# _registers = {**_registers_general, **_register_short, **_registers_seg, **_registers_control}
|
@@ -0,0 +1,86 @@
|
|
1
|
+
import abc
|
2
|
+
import typing
|
3
|
+
|
4
|
+
from .... import platforms, utils
|
5
|
+
|
6
|
+
|
7
|
+
class PandaMachineDef(metaclass=abc.ABCMeta):
|
8
|
+
"""Container class for Unicorn architecture-specific definitions"""
|
9
|
+
|
10
|
+
@property
|
11
|
+
@abc.abstractmethod
|
12
|
+
def arch(self) -> platforms.Architecture:
|
13
|
+
"""The architecture ID"""
|
14
|
+
raise NotImplementedError("This is an abstract method.")
|
15
|
+
|
16
|
+
@property
|
17
|
+
@abc.abstractmethod
|
18
|
+
def byteorder(self) -> platforms.Byteorder:
|
19
|
+
"""The byte order"""
|
20
|
+
raise NotImplementedError("This is an abstract method.")
|
21
|
+
|
22
|
+
@property
|
23
|
+
@abc.abstractmethod
|
24
|
+
def panda_arch(self) -> str:
|
25
|
+
"""The panda architecture to use"""
|
26
|
+
raise NotImplementedError("This is an abstract method.")
|
27
|
+
|
28
|
+
@property
|
29
|
+
@abc.abstractmethod
|
30
|
+
def cs_arch(self) -> int:
|
31
|
+
"""The capstone architecture to use"""
|
32
|
+
raise NotImplementedError("This is an abstract method.")
|
33
|
+
|
34
|
+
@property
|
35
|
+
@abc.abstractmethod
|
36
|
+
def cs_mode(self) -> int:
|
37
|
+
"""The capstone mode to use"""
|
38
|
+
raise NotImplementedError("This is an abstract method.")
|
39
|
+
|
40
|
+
_registers: typing.Dict[str, str] = {}
|
41
|
+
|
42
|
+
def panda_reg(self, name: str) -> str:
|
43
|
+
if name in self._registers:
|
44
|
+
return self._registers[name]
|
45
|
+
else:
|
46
|
+
raise ValueError(
|
47
|
+
f"Unknown register for {self.arch}:{self.byteorder}: {name}"
|
48
|
+
)
|
49
|
+
|
50
|
+
def check_panda_reg(self, name: str) -> bool:
|
51
|
+
"""Convert a register name to panda cpu field, index, mask
|
52
|
+
|
53
|
+
This must cover all names defined in the CPU state model
|
54
|
+
for this arch/mode/byteorder, or return 0,
|
55
|
+
which always indicates an invalid register
|
56
|
+
"""
|
57
|
+
if name in self._registers:
|
58
|
+
return True
|
59
|
+
else:
|
60
|
+
return False
|
61
|
+
|
62
|
+
@classmethod
|
63
|
+
def for_platform(cls, platform: platforms.Platform):
|
64
|
+
"""Find the appropriate MachineDef for your architecture
|
65
|
+
|
66
|
+
Arguments:
|
67
|
+
arch: The architecture ID you want
|
68
|
+
mode: The mode ID you want
|
69
|
+
byteorder: The byteorderness you want
|
70
|
+
|
71
|
+
Returns:
|
72
|
+
An instance of the appropriate MachineDef
|
73
|
+
|
74
|
+
Raises:
|
75
|
+
ValueError: If no MachineDef subclass matches your request
|
76
|
+
"""
|
77
|
+
try:
|
78
|
+
return utils.find_subclass(
|
79
|
+
cls,
|
80
|
+
lambda x: x.arch == platform.architecture
|
81
|
+
and x.byteorder == platform.byteorder,
|
82
|
+
)
|
83
|
+
except:
|
84
|
+
raise ValueError(
|
85
|
+
f"No machine model for {platform.architecture}:{platform.byteorder}"
|
86
|
+
)
|