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,258 @@
|
|
1
|
+
import abc
|
2
|
+
import logging
|
3
|
+
import typing
|
4
|
+
|
5
|
+
import capstone
|
6
|
+
|
7
|
+
from .. import emulators, utils
|
8
|
+
|
9
|
+
logger = logging.getLogger(__name__)
|
10
|
+
|
11
|
+
|
12
|
+
class Operand(metaclass=abc.ABCMeta):
|
13
|
+
"""An operand from an instruction."""
|
14
|
+
|
15
|
+
@abc.abstractmethod
|
16
|
+
def key(self, emulator: emulators.Emulator):
|
17
|
+
"""Provide a unique key for this reference.
|
18
|
+
|
19
|
+
Arguments:
|
20
|
+
emulator: An emulator from which to fetch a value.
|
21
|
+
|
22
|
+
Returns:
|
23
|
+
A key value used to reference this operand.
|
24
|
+
"""
|
25
|
+
|
26
|
+
pass
|
27
|
+
|
28
|
+
@abc.abstractmethod
|
29
|
+
def concretize(
|
30
|
+
self, emulator: emulators.Emulator
|
31
|
+
) -> typing.Optional[typing.Union[int, bytes]]:
|
32
|
+
"""Compute a concrete value for this operand, using an emulator.
|
33
|
+
|
34
|
+
Arguments:
|
35
|
+
emulator: An emulator from which to fetch a value.
|
36
|
+
|
37
|
+
Returns:
|
38
|
+
The concrete value of this operand.
|
39
|
+
"""
|
40
|
+
|
41
|
+
pass
|
42
|
+
|
43
|
+
|
44
|
+
class RegisterOperand(Operand):
|
45
|
+
"""An operand from an instruction that is simply a register."""
|
46
|
+
|
47
|
+
def __init__(self, name: str):
|
48
|
+
self.name = name
|
49
|
+
|
50
|
+
def key(self, emulator: emulators.Emulator):
|
51
|
+
return self.name
|
52
|
+
|
53
|
+
def __eq__(self, other) -> bool:
|
54
|
+
return hash(self) == hash(other)
|
55
|
+
|
56
|
+
def __hash__(self) -> int:
|
57
|
+
return hash(self.__repr__())
|
58
|
+
|
59
|
+
def concretize(self, emulator: emulators.Emulator) -> int:
|
60
|
+
return emulator.read_register(self.name)
|
61
|
+
|
62
|
+
def __repr__(self) -> str:
|
63
|
+
return f"{self.__class__.__name__}({self.name})"
|
64
|
+
|
65
|
+
|
66
|
+
class MemoryReferenceOperand(Operand):
|
67
|
+
"""An operand from an instruction which reads or writes memory."""
|
68
|
+
|
69
|
+
def __init__(self, size: int = 4):
|
70
|
+
self.size = size
|
71
|
+
|
72
|
+
@abc.abstractmethod
|
73
|
+
def address(self, emulator: emulators.Emulator) -> int:
|
74
|
+
"""Compute a concrete value for this operand.
|
75
|
+
|
76
|
+
Arguments:
|
77
|
+
emulator: An emulator from which to fetch a value.
|
78
|
+
|
79
|
+
Returns:
|
80
|
+
The concrete value of this operand.
|
81
|
+
"""
|
82
|
+
|
83
|
+
def key(self, emulator: emulators.Emulator) -> int:
|
84
|
+
return self.address(emulator)
|
85
|
+
|
86
|
+
def __eq__(self, other):
|
87
|
+
return self.__repr__() == other.__repr__()
|
88
|
+
|
89
|
+
def __hash__(self):
|
90
|
+
return hash(self.__repr__())
|
91
|
+
|
92
|
+
def concretize(self, emulator: emulators.Emulator) -> typing.Optional[bytes]:
|
93
|
+
return emulator.read_memory(self.address(emulator), self.size)
|
94
|
+
|
95
|
+
|
96
|
+
class Instruction(metaclass=abc.ABCMeta):
|
97
|
+
"""An instruction storage and semantic metadata class."""
|
98
|
+
|
99
|
+
def __init__(
|
100
|
+
self,
|
101
|
+
instruction: bytes,
|
102
|
+
address: int,
|
103
|
+
_instruction: typing.Optional[capstone.CsInsn] = None,
|
104
|
+
):
|
105
|
+
self.instruction = instruction
|
106
|
+
self.address = address
|
107
|
+
|
108
|
+
if _instruction is None:
|
109
|
+
md = capstone.Cs(self.cs_arch, self.cs_mode)
|
110
|
+
md.detail = True
|
111
|
+
|
112
|
+
_instruction = md.disasm(instruction, address).__next__()
|
113
|
+
|
114
|
+
self._instruction = _instruction
|
115
|
+
self.disasm = f"{self._instruction.address:x} {self._instruction.mnemonic} {self._instruction.op_str}"
|
116
|
+
|
117
|
+
@property
|
118
|
+
@abc.abstractmethod
|
119
|
+
def angr_arch(self) -> str:
|
120
|
+
"""angr architecture ID"""
|
121
|
+
return ""
|
122
|
+
|
123
|
+
@property
|
124
|
+
@abc.abstractmethod
|
125
|
+
def cs_arch(self) -> int:
|
126
|
+
"""Capstone architecture ID"""
|
127
|
+
return 0
|
128
|
+
|
129
|
+
@property
|
130
|
+
@abc.abstractmethod
|
131
|
+
def cs_mode(self) -> int:
|
132
|
+
"""Capstone mode ID"""
|
133
|
+
return 0
|
134
|
+
|
135
|
+
@classmethod
|
136
|
+
def from_capstone(cls, instruction: capstone.CsInsn):
|
137
|
+
"""Construct from an existing Capstone instruction.
|
138
|
+
|
139
|
+
Arguments:
|
140
|
+
instruction: An existing Capstone instruction.
|
141
|
+
"""
|
142
|
+
try:
|
143
|
+
return utils.find_subclass(
|
144
|
+
cls,
|
145
|
+
check=lambda x: x.cs_arch == instruction._cs.arch
|
146
|
+
and x.cs_mode == instruction._cs.mode,
|
147
|
+
instruction=instruction.bytes,
|
148
|
+
address=instruction.address,
|
149
|
+
_instruction=instruction,
|
150
|
+
)
|
151
|
+
except ValueError:
|
152
|
+
raise ValueError(
|
153
|
+
f"No instruction format for {instruction._cs.arch}:{instruction._cs.mode}"
|
154
|
+
)
|
155
|
+
|
156
|
+
@classmethod
|
157
|
+
def from_angr(cls, instruction, block, arch: str):
|
158
|
+
"""Construct from an angr disassembler instruction.
|
159
|
+
|
160
|
+
Arguments:
|
161
|
+
instruction: An existing angr disassembler instruction
|
162
|
+
arch: angr architecture string
|
163
|
+
"""
|
164
|
+
# angr's instructions don't include raw bytes.
|
165
|
+
off = instruction.address - block.addr
|
166
|
+
raw = block.bytes[off : off + instruction.size]
|
167
|
+
try:
|
168
|
+
return utils.find_subclass(
|
169
|
+
cls,
|
170
|
+
check=lambda x: x.angr_arch == arch,
|
171
|
+
instruction=raw,
|
172
|
+
address=instruction.address,
|
173
|
+
)
|
174
|
+
except ValueError:
|
175
|
+
raise ValueError(f"No instruction format for {arch}")
|
176
|
+
|
177
|
+
@classmethod
|
178
|
+
def from_bytes(cls, raw: bytes, address: int, arch: str, mode: str):
|
179
|
+
"""Construct from a byte string."""
|
180
|
+
try:
|
181
|
+
return utils.find_subclass(
|
182
|
+
cls,
|
183
|
+
check=lambda x: x.arch == arch and x.mode == mode,
|
184
|
+
instruction=raw,
|
185
|
+
address=address,
|
186
|
+
)
|
187
|
+
except ValueError:
|
188
|
+
raise ValueError(f"No instruction format for {arch}:{mode}")
|
189
|
+
|
190
|
+
@abc.abstractmethod
|
191
|
+
def _memory_reference(self, operand) -> MemoryReferenceOperand:
|
192
|
+
pass
|
193
|
+
|
194
|
+
@property
|
195
|
+
def reads(self) -> typing.Set[Operand]:
|
196
|
+
"""Registers and memory references read by this instruction.
|
197
|
+
|
198
|
+
This is a list of string register names and dictionary memory reference
|
199
|
+
specifications (i.e., in the form `base + scale * index + offset`).
|
200
|
+
"""
|
201
|
+
|
202
|
+
read: typing.Set[Operand] = set()
|
203
|
+
|
204
|
+
for operand in self._instruction.operands:
|
205
|
+
if operand.type == capstone.CS_OP_MEM and (
|
206
|
+
not hasattr(operand, "access") or operand.access & capstone.CS_AC_READ
|
207
|
+
):
|
208
|
+
read.add(self._memory_reference(operand))
|
209
|
+
elif operand.type == capstone.CS_OP_REG and (
|
210
|
+
not hasattr(operand, "access") or operand.access & capstone.CS_AC_READ
|
211
|
+
):
|
212
|
+
read.add(RegisterOperand(self._instruction.reg_name(operand.reg)))
|
213
|
+
|
214
|
+
return read
|
215
|
+
|
216
|
+
@property
|
217
|
+
def writes(self) -> typing.Set[Operand]:
|
218
|
+
"""Registers and memory references written by this instruction.
|
219
|
+
|
220
|
+
Same format as `reads`.
|
221
|
+
"""
|
222
|
+
|
223
|
+
write: typing.Set[Operand] = set()
|
224
|
+
|
225
|
+
for operand in self._instruction.operands:
|
226
|
+
if operand.type == capstone.CS_OP_MEM and (
|
227
|
+
not hasattr(operand, "access") or operand.access & capstone.CS_AC_WRITE
|
228
|
+
):
|
229
|
+
write.add(self._memory_reference(operand))
|
230
|
+
elif operand.type == capstone.CS_OP_REG and (
|
231
|
+
not hasattr(operand, "access") or operand.access & capstone.CS_AC_WRITE
|
232
|
+
):
|
233
|
+
write.add(RegisterOperand(self._instruction.reg_name(operand.reg)))
|
234
|
+
|
235
|
+
return write
|
236
|
+
|
237
|
+
# def to_json(self) -> dict:
|
238
|
+
# return {
|
239
|
+
# "instruction": base64.b64encode(self.instruction).decode(),
|
240
|
+
# "disasm": self.disasm,
|
241
|
+
# "address": self.address,
|
242
|
+
# "arch": self.arch,
|
243
|
+
# "mode": self.mode,
|
244
|
+
# }
|
245
|
+
|
246
|
+
# @classmethod
|
247
|
+
# def from_json(cls, dict):
|
248
|
+
# if "instruction" not in dict:
|
249
|
+
# raise ValueError(f"malformed {cls.__name__}: {dict!r}")
|
250
|
+
|
251
|
+
# dict["instruction"] = base64.b64decode(dict["instruction"])
|
252
|
+
|
253
|
+
# return cls(**dict)
|
254
|
+
|
255
|
+
def __repr__(self) -> str:
|
256
|
+
string = f"{self._instruction.mnemonic} {self._instruction.op_str}".strip()
|
257
|
+
|
258
|
+
return f"{self.__class__.__name__}(0x{self.address:x}: {string})"
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import capstone
|
2
|
+
|
3
|
+
from .bsid import BSIDMemoryReferenceOperand
|
4
|
+
from .instructions import Instruction, MemoryReferenceOperand
|
5
|
+
|
6
|
+
|
7
|
+
class MIPSInstruction(Instruction):
|
8
|
+
angr_arch = "MIPS"
|
9
|
+
cs_arch = capstone.CS_ARCH_MIPS
|
10
|
+
cs_mode = capstone.CS_MODE_MIPS32 | capstone.CS_MODE_BIG_ENDIAN
|
11
|
+
|
12
|
+
def _memory_reference(self, operand) -> MemoryReferenceOperand:
|
13
|
+
return BSIDMemoryReferenceOperand(
|
14
|
+
base=self._instruction.reg_name(operand.value.mem.base),
|
15
|
+
offset=operand.value.mem.disp,
|
16
|
+
size=4,
|
17
|
+
)
|
18
|
+
|
19
|
+
|
20
|
+
class MIPSELInstruction(MIPSInstruction):
|
21
|
+
cs_mode = capstone.CS_MODE_MIPS32
|
@@ -0,0 +1,100 @@
|
|
1
|
+
import typing
|
2
|
+
|
3
|
+
import capstone
|
4
|
+
|
5
|
+
from .bsid import BSIDMemoryReferenceOperand
|
6
|
+
from .instructions import Instruction, MemoryReferenceOperand, Operand, RegisterOperand
|
7
|
+
|
8
|
+
|
9
|
+
class x86Instruction(Instruction):
|
10
|
+
word_size = 4
|
11
|
+
angr_arch = "X86"
|
12
|
+
cs_arch = capstone.CS_ARCH_X86
|
13
|
+
cs_mode = capstone.CS_MODE_32
|
14
|
+
sp = "esp"
|
15
|
+
|
16
|
+
def _memory_reference(self, base, index, scale, offset, size):
|
17
|
+
return BSIDMemoryReferenceOperand(
|
18
|
+
base=base, index=index, scale=scale, offset=offset, size=size
|
19
|
+
)
|
20
|
+
|
21
|
+
# operand is a capstone operand
|
22
|
+
def _memory_reference_operand(self, operand) -> MemoryReferenceOperand:
|
23
|
+
return self._memory_reference(
|
24
|
+
self._instruction.reg_name(operand.value.mem.base),
|
25
|
+
self._instruction.reg_name(operand.value.mem.index),
|
26
|
+
operand.value.mem.scale,
|
27
|
+
operand.value.mem.disp,
|
28
|
+
operand.size,
|
29
|
+
)
|
30
|
+
|
31
|
+
@property
|
32
|
+
def reads(self) -> typing.Set[Operand]:
|
33
|
+
"""Registers and memory references read by this instruction.
|
34
|
+
|
35
|
+
This is a list of string register names and dictionary memory reference
|
36
|
+
specifications (i.e., in the form `base + scale * index + offset`).
|
37
|
+
"""
|
38
|
+
|
39
|
+
reg_reads, _ = self._instruction.regs_access()
|
40
|
+
the_reads: typing.Set[Operand] = set(
|
41
|
+
[RegisterOperand(self._instruction.reg_name(r)) for r in reg_reads]
|
42
|
+
)
|
43
|
+
|
44
|
+
for operand in self._instruction.operands:
|
45
|
+
if operand.access & capstone.CS_AC_READ:
|
46
|
+
if operand.type == capstone.x86.X86_OP_MEM:
|
47
|
+
if not self._instruction.mnemonic == "lea":
|
48
|
+
# add the actual memory read
|
49
|
+
the_reads.add(self._memory_reference_operand(operand))
|
50
|
+
# add reads for parts of the operand
|
51
|
+
base_name = self._instruction.reg_name(operand.mem.base)
|
52
|
+
index_name = self._instruction.reg_name(operand.mem.index)
|
53
|
+
if base_name:
|
54
|
+
the_reads.add(RegisterOperand(base_name))
|
55
|
+
if index_name:
|
56
|
+
the_reads.add(RegisterOperand(index_name))
|
57
|
+
elif operand.type == capstone.x86.X86_OP_REG:
|
58
|
+
# these are already in the list bc of regs_access above
|
59
|
+
pass
|
60
|
+
else:
|
61
|
+
# shouldn't happen
|
62
|
+
assert 1 == 0
|
63
|
+
if self._instruction.mnemonic == "pop":
|
64
|
+
the_reads.add(self._memory_reference(self.sp, None, 1, 0, self.word_size))
|
65
|
+
|
66
|
+
return the_reads
|
67
|
+
|
68
|
+
@property
|
69
|
+
def writes(self) -> typing.Set[Operand]:
|
70
|
+
"""Registers and memory references written by this instruction.
|
71
|
+
|
72
|
+
Same format as `reads`.
|
73
|
+
"""
|
74
|
+
_, reg_writes = self._instruction.regs_access()
|
75
|
+
the_writes: typing.Set[Operand] = set(
|
76
|
+
[RegisterOperand(self._instruction.reg_name(r)) for r in reg_writes]
|
77
|
+
)
|
78
|
+
for operand in self._instruction.operands:
|
79
|
+
if operand.access & capstone.CS_AC_WRITE:
|
80
|
+
# please dont change this to CS_OP_MEM bc that doesnt work?
|
81
|
+
if operand.type == capstone.x86.X86_OP_MEM:
|
82
|
+
assert not (self._instruction.mnemonic == "lea")
|
83
|
+
the_writes.add(self._memory_reference_operand(operand))
|
84
|
+
elif operand.type == capstone.x86.X86_OP_REG:
|
85
|
+
# operands doesn't contain implicit registers.
|
86
|
+
# we get all registers from regs_write
|
87
|
+
pass
|
88
|
+
else:
|
89
|
+
assert 1 == 0
|
90
|
+
if self._instruction.mnemonic == "push":
|
91
|
+
the_writes.add(self._memory_reference(self.sp, None, 1, 0, self.word_size))
|
92
|
+
|
93
|
+
return the_writes
|
94
|
+
|
95
|
+
|
96
|
+
class AMD64Instruction(x86Instruction):
|
97
|
+
angr_arch = "AMD64"
|
98
|
+
cs_mode = capstone.CS_MODE_64
|
99
|
+
sp = "rsp"
|
100
|
+
word_size = 8
|
smallworld/logging.py
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
import logging
|
2
|
+
import sys
|
3
|
+
|
4
|
+
|
5
|
+
class CharacterLevelFilter(logging.Filter):
|
6
|
+
"""Adds logging level as a single character for formatting."""
|
7
|
+
|
8
|
+
CHARACTERS = {
|
9
|
+
logging.DEBUG: "-",
|
10
|
+
logging.INFO: "+",
|
11
|
+
logging.WARNING: "!",
|
12
|
+
logging.ERROR: "*",
|
13
|
+
logging.CRITICAL: "#",
|
14
|
+
}
|
15
|
+
|
16
|
+
def filter(self, record):
|
17
|
+
record.levelchar = self.CHARACTERS.get(record.levelno, " ")
|
18
|
+
return True
|
19
|
+
|
20
|
+
|
21
|
+
class ColorLevelFilter(logging.Filter):
|
22
|
+
"""Adds logging level as a color for formatting."""
|
23
|
+
|
24
|
+
WHITE_DIM = "\x1b[37;2m"
|
25
|
+
WHITE = "\x1b[37m"
|
26
|
+
YELLOW = "\x1b[33m"
|
27
|
+
RED = "\x1b[31m"
|
28
|
+
RED_BOLD = "\x1b[31;1m"
|
29
|
+
END = "\x1b[0m"
|
30
|
+
NULL = END
|
31
|
+
|
32
|
+
COLORS = {
|
33
|
+
logging.DEBUG: WHITE_DIM,
|
34
|
+
logging.INFO: WHITE,
|
35
|
+
logging.WARNING: YELLOW,
|
36
|
+
logging.ERROR: RED,
|
37
|
+
logging.CRITICAL: RED_BOLD,
|
38
|
+
}
|
39
|
+
|
40
|
+
def filter(self, record):
|
41
|
+
record.levelcolor = self.COLORS.get(record.levelno, self.NULL)
|
42
|
+
return True
|
43
|
+
|
44
|
+
|
45
|
+
def setup_logging(
|
46
|
+
level: int = logging.INFO,
|
47
|
+
verbose: bool = False,
|
48
|
+
colors: bool = True,
|
49
|
+
clear: bool = True,
|
50
|
+
) -> None:
|
51
|
+
"""Setup log handling.
|
52
|
+
|
53
|
+
Note: this should only be called once.
|
54
|
+
|
55
|
+
Arguments:
|
56
|
+
level: Logging level (from `logging` module).
|
57
|
+
verbose: Enable verbose logging mode.
|
58
|
+
colors: Enable logging colors (if supported).
|
59
|
+
clear: Remove all other handlers from the root logger.
|
60
|
+
"""
|
61
|
+
|
62
|
+
if verbose:
|
63
|
+
format = "[%(asctime)s %(levelname)-7s|%(name)s]: %(message)s"
|
64
|
+
else:
|
65
|
+
format = "[%(levelchar)s] %(message)s"
|
66
|
+
|
67
|
+
if colors and sys.stderr.isatty():
|
68
|
+
format = f"%(levelcolor)s{format}{ColorLevelFilter.END}"
|
69
|
+
|
70
|
+
root = logging.getLogger()
|
71
|
+
root.setLevel(level)
|
72
|
+
|
73
|
+
if clear:
|
74
|
+
handlers = list(root.handlers)
|
75
|
+
for handler in handlers:
|
76
|
+
root.removeHandler(handler)
|
77
|
+
|
78
|
+
formatter = logging.Formatter(format)
|
79
|
+
|
80
|
+
handler = logging.StreamHandler()
|
81
|
+
handler.setLevel(level)
|
82
|
+
handler.addFilter(CharacterLevelFilter())
|
83
|
+
handler.addFilter(ColorLevelFilter())
|
84
|
+
|
85
|
+
handler.setFormatter(formatter)
|
86
|
+
|
87
|
+
root.addHandler(handler)
|
88
|
+
|
89
|
+
|
90
|
+
__all__ = ["setup_logging"]
|
smallworld/platforms.py
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
import enum
|
2
|
+
from dataclasses import dataclass
|
3
|
+
|
4
|
+
|
5
|
+
class Architecture(enum.Enum):
|
6
|
+
"""Architecture and mode.
|
7
|
+
|
8
|
+
Names take the form ``{ARCH}_{MODE}`` where ``{ARCH}`` and ``{MODE}``
|
9
|
+
match the regex ``[A-Z0-9]+``.
|
10
|
+
|
11
|
+
Values are lowercase, kebab-case.
|
12
|
+
"""
|
13
|
+
|
14
|
+
X86_32 = "x86-32"
|
15
|
+
"""32-bit x86 supporting SSE extensions."""
|
16
|
+
|
17
|
+
X86_64 = "x86-64"
|
18
|
+
"""64-bit x86 supporting AVX2 extensions."""
|
19
|
+
|
20
|
+
X86_64_AVX512 = "x86-64-avx512"
|
21
|
+
"""64-bit x86 supporting AVX512 extensions."""
|
22
|
+
|
23
|
+
AARCH64 = "aarch64"
|
24
|
+
|
25
|
+
MIPS32 = "mips32"
|
26
|
+
|
27
|
+
MIPS64 = "mips64"
|
28
|
+
|
29
|
+
POWERPC64 = "powerpc64"
|
30
|
+
POWERPC32 = "powerpc32"
|
31
|
+
|
32
|
+
ARM_V5T = "arm-v5t"
|
33
|
+
ARM_V6M = "arm-v6m"
|
34
|
+
ARM_V6M_THUMB = "arm-v6m-thumb"
|
35
|
+
ARM_V7M = "arm-v7m"
|
36
|
+
ARM_V7R = "arm-v7r"
|
37
|
+
ARM_V7A = "arm-v7a"
|
38
|
+
|
39
|
+
RISCV64 = "riscv-64"
|
40
|
+
|
41
|
+
XTENSA = "xtensa"
|
42
|
+
|
43
|
+
|
44
|
+
class Byteorder(enum.Enum):
|
45
|
+
"""Endianness."""
|
46
|
+
|
47
|
+
BIG = "big"
|
48
|
+
"""Big endian - most significant bit first."""
|
49
|
+
|
50
|
+
LITTLE = "little"
|
51
|
+
"""Little endian - least significant bit first."""
|
52
|
+
|
53
|
+
MIDDLE = "middle"
|
54
|
+
"""Middle endian - also known as PDP-endian."""
|
55
|
+
|
56
|
+
|
57
|
+
class ABI(enum.Enum):
|
58
|
+
"""Application binary interface.
|
59
|
+
|
60
|
+
Names match the regex ``[A-Z]+``.
|
61
|
+
|
62
|
+
Values are lowercase, kebab-case.
|
63
|
+
"""
|
64
|
+
|
65
|
+
SYSTEMV = "system-v"
|
66
|
+
"""System V."""
|
67
|
+
|
68
|
+
CDECL = "cdecl"
|
69
|
+
"""Microsoft cdecl."""
|
70
|
+
|
71
|
+
VECTORCALL = "vectorcall"
|
72
|
+
"""Microsoft vectorcall."""
|
73
|
+
|
74
|
+
FASTCALL = "fastcall"
|
75
|
+
"""Microsoft fastcall."""
|
76
|
+
|
77
|
+
NONE = "none"
|
78
|
+
"""No ABI"""
|
79
|
+
|
80
|
+
|
81
|
+
@dataclass(frozen=True)
|
82
|
+
class Platform:
|
83
|
+
"""Platform metadata/configuration storage class."""
|
84
|
+
|
85
|
+
architecture: Architecture
|
86
|
+
"""Architecture and mode."""
|
87
|
+
|
88
|
+
byteorder: Byteorder
|
89
|
+
"""Endianness."""
|
90
|
+
|
91
|
+
def __repr__(self) -> str:
|
92
|
+
return f"{self.architecture}:{self.byteorder}"
|
93
|
+
|
94
|
+
|
95
|
+
__all__ = ["Platform", "Architecture", "Byteorder", "ABI"]
|
smallworld/py.typed
ADDED
File without changes
|
@@ -0,0 +1,32 @@
|
|
1
|
+
from .aarch64 import AArch64
|
2
|
+
from .amd64 import AMD64
|
3
|
+
from .arm import ARMv5T, ARMv6M, ARMv6MThumb, ARMv7A, ARMv7M, ARMv7R
|
4
|
+
from .cpu import * # noqa: F401, F403
|
5
|
+
from .cpu import __all__ as __cpu__
|
6
|
+
from .i386 import I386
|
7
|
+
from .mips import MIPSBE, MIPSEL
|
8
|
+
from .mips64 import MIPS64BE, MIPS64EL
|
9
|
+
from .powerpc import PowerPC32, PowerPC64
|
10
|
+
from .riscv import RISCV64
|
11
|
+
from .xtensa import XTensaBE, XTensaEL
|
12
|
+
|
13
|
+
__all__ = __cpu__ + [
|
14
|
+
"AArch64",
|
15
|
+
"AMD64",
|
16
|
+
"ARMv5T",
|
17
|
+
"ARMv6M",
|
18
|
+
"ARMv6MThumb",
|
19
|
+
"ARMv7M",
|
20
|
+
"ARMv7R",
|
21
|
+
"ARMv7A",
|
22
|
+
"I386",
|
23
|
+
"MIPS64EL",
|
24
|
+
"MIPS64BE",
|
25
|
+
"MIPSEL",
|
26
|
+
"MIPSBE",
|
27
|
+
"PowerPC32",
|
28
|
+
"PowerPC64",
|
29
|
+
"RISCV64",
|
30
|
+
"XTensaBE",
|
31
|
+
"XTensaEL",
|
32
|
+
]
|