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,42 @@
|
|
1
|
+
import typing
|
2
|
+
|
3
|
+
from .... import platforms
|
4
|
+
from ... import state
|
5
|
+
from . import stack
|
6
|
+
|
7
|
+
|
8
|
+
class AMD64Stack(stack.DescendingStack):
|
9
|
+
"""A stack for an AMD 64-bit CPU"""
|
10
|
+
|
11
|
+
platform = platforms.Platform(
|
12
|
+
platforms.Architecture.X86_64, platforms.Byteorder.LITTLE
|
13
|
+
)
|
14
|
+
|
15
|
+
def get_pointer(self) -> int:
|
16
|
+
return (self.address + self.size) - self.get_used()
|
17
|
+
|
18
|
+
def get_alignment(self) -> int:
|
19
|
+
return 16
|
20
|
+
|
21
|
+
def push(self, value: state.Value) -> int:
|
22
|
+
return super().push(value)
|
23
|
+
|
24
|
+
@classmethod
|
25
|
+
def initialize_stack(cls, argv: typing.List[bytes], *args, **kwargs):
|
26
|
+
s = cls(*args, **kwargs)
|
27
|
+
argv_address = []
|
28
|
+
total_strings_bytes = 0
|
29
|
+
for i, arg in enumerate(argv):
|
30
|
+
arg_size = len(arg)
|
31
|
+
total_strings_bytes += arg_size
|
32
|
+
argv_address.append((i, s.push_bytes(arg, label=f"argv[{i}]")))
|
33
|
+
|
34
|
+
argc = len(argv)
|
35
|
+
total_space = (8 * (argc + 2)) + total_strings_bytes
|
36
|
+
padding = 16 - (total_space % 16)
|
37
|
+
s.push_bytes(bytes(padding), label="stack alignment padding bytes")
|
38
|
+
s.push_integer(0, size=8, label="null terminator of argv array")
|
39
|
+
for i, addr in reversed(argv_address):
|
40
|
+
s.push_integer(addr, size=8, label=f"pointer to argv[{i}]")
|
41
|
+
s.push_integer(argc, size=8, label="argc")
|
42
|
+
return s
|
@@ -0,0 +1,66 @@
|
|
1
|
+
import typing
|
2
|
+
|
3
|
+
from .... import platforms
|
4
|
+
from . import stack
|
5
|
+
|
6
|
+
|
7
|
+
class ARM32Stack(stack.DescendingStack):
|
8
|
+
"""A stack for an ARM 32-bit CPU"""
|
9
|
+
|
10
|
+
def get_pointer(self) -> int:
|
11
|
+
return (self.address + self.size) - self.get_used()
|
12
|
+
|
13
|
+
def get_alignment(self) -> int:
|
14
|
+
return 8
|
15
|
+
|
16
|
+
@classmethod
|
17
|
+
def initialize_stack(cls, argv: typing.List[bytes], *args, **kwargs):
|
18
|
+
raise NotImplementedError("Stack initialization not implemented for ARM32")
|
19
|
+
|
20
|
+
|
21
|
+
class ARMv5tStack(ARM32Stack):
|
22
|
+
"""A stack for an ARMv5t 32-bit CPU"""
|
23
|
+
|
24
|
+
platform = platforms.Platform(
|
25
|
+
platforms.Architecture.ARM_V5T, platforms.Byteorder.LITTLE
|
26
|
+
)
|
27
|
+
|
28
|
+
|
29
|
+
class ARMv6mStack(ARM32Stack):
|
30
|
+
"""A stack for an ARMv6m 32-bit CPU"""
|
31
|
+
|
32
|
+
platform = platforms.Platform(
|
33
|
+
platforms.Architecture.ARM_V6M, platforms.Byteorder.LITTLE
|
34
|
+
)
|
35
|
+
|
36
|
+
|
37
|
+
class ARMv6mThumbStack(ARM32Stack):
|
38
|
+
"""A stack for an ARMv6mThumb 32-bit CPU"""
|
39
|
+
|
40
|
+
platform = platforms.Platform(
|
41
|
+
platforms.Architecture.ARM_V6M_THUMB, platforms.Byteorder.LITTLE
|
42
|
+
)
|
43
|
+
|
44
|
+
|
45
|
+
class ARMv7mStack(ARM32Stack):
|
46
|
+
"""A stack for an ARMv7m 32-bit CPU"""
|
47
|
+
|
48
|
+
platform = platforms.Platform(
|
49
|
+
platforms.Architecture.ARM_V7M, platforms.Byteorder.LITTLE
|
50
|
+
)
|
51
|
+
|
52
|
+
|
53
|
+
class ARMv7rStack(ARM32Stack):
|
54
|
+
"""A stack for an ARMv7r 32-bit CPU"""
|
55
|
+
|
56
|
+
platform = platforms.Platform(
|
57
|
+
platforms.Architecture.ARM_V7R, platforms.Byteorder.LITTLE
|
58
|
+
)
|
59
|
+
|
60
|
+
|
61
|
+
class ARMv7aStack(ARM32Stack):
|
62
|
+
"""A stack for an ARMv7a 32-bit CPU"""
|
63
|
+
|
64
|
+
platform = platforms.Platform(
|
65
|
+
platforms.Architecture.ARM_V7A, platforms.Byteorder.LITTLE
|
66
|
+
)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import typing
|
2
|
+
|
3
|
+
from .... import platforms
|
4
|
+
from . import stack
|
5
|
+
|
6
|
+
|
7
|
+
class X86Stack(stack.DescendingStack):
|
8
|
+
"""A stack for an Intel 32-bit CPU"""
|
9
|
+
|
10
|
+
platform = platforms.Platform(
|
11
|
+
platforms.Architecture.X86_32, platforms.Byteorder.LITTLE
|
12
|
+
)
|
13
|
+
|
14
|
+
def get_pointer(self) -> int:
|
15
|
+
return (self.address + self.size) - self.get_used()
|
16
|
+
|
17
|
+
def get_alignment(self) -> int:
|
18
|
+
return 4
|
19
|
+
|
20
|
+
@classmethod
|
21
|
+
def initialize_stack(cls, argv: typing.List[bytes], *args, **kwargs):
|
22
|
+
raise NotImplementedError("Stack initialization not implemented for i386")
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import typing
|
2
|
+
|
3
|
+
from .... import platforms
|
4
|
+
from . import stack
|
5
|
+
|
6
|
+
|
7
|
+
class MIPSStack(stack.DescendingStack):
|
8
|
+
"""A stack for a MIPS 32-bit CPU"""
|
9
|
+
|
10
|
+
def get_pointer(self) -> int:
|
11
|
+
return (self.address + self.size) - self.get_used()
|
12
|
+
|
13
|
+
def get_alignment(self) -> int:
|
14
|
+
return 4
|
15
|
+
|
16
|
+
@classmethod
|
17
|
+
def initialize_stack(cls, argv: typing.List[bytes], *args, **kwargs):
|
18
|
+
raise NotImplementedError("Stack initialization not implemented for MIPS32")
|
19
|
+
|
20
|
+
|
21
|
+
class MIPSBEStack(MIPSStack):
|
22
|
+
"""A stack for a big-endian MIPS 32-bit CPU"""
|
23
|
+
|
24
|
+
platform = platforms.Platform(
|
25
|
+
platforms.Architecture.MIPS32, platforms.Byteorder.BIG
|
26
|
+
)
|
27
|
+
|
28
|
+
|
29
|
+
class MIPSELStack(MIPSStack):
|
30
|
+
"""A stack for a little-endian MIPS 32-bit CPU"""
|
31
|
+
|
32
|
+
platform = platforms.Platform(
|
33
|
+
platforms.Architecture.MIPS32, platforms.Byteorder.LITTLE
|
34
|
+
)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import typing
|
2
|
+
|
3
|
+
from .... import platforms
|
4
|
+
from . import stack
|
5
|
+
|
6
|
+
|
7
|
+
class MIPS64Stack(stack.DescendingStack):
|
8
|
+
"""A stack for a MIPS 64-bit CPU"""
|
9
|
+
|
10
|
+
def get_pointer(self) -> int:
|
11
|
+
return (self.address + self.size) - self.get_used()
|
12
|
+
|
13
|
+
def get_alignment(self) -> int:
|
14
|
+
return 4
|
15
|
+
|
16
|
+
@classmethod
|
17
|
+
def initialize_stack(cls, argv: typing.List[bytes], *args, **kwargs):
|
18
|
+
raise NotImplementedError("Stack initialization not implemented for MIPS64")
|
19
|
+
|
20
|
+
|
21
|
+
class MIPS64BEStack(MIPS64Stack):
|
22
|
+
"""A stack for a big-endian MIPS 64-bit CPU"""
|
23
|
+
|
24
|
+
platform = platforms.Platform(
|
25
|
+
platforms.Architecture.MIPS64, platforms.Byteorder.BIG
|
26
|
+
)
|
27
|
+
|
28
|
+
|
29
|
+
class MIPS64ELStack(MIPS64Stack):
|
30
|
+
"""A stack for a little-endian MIPS 64-bit CPU"""
|
31
|
+
|
32
|
+
platform = platforms.Platform(
|
33
|
+
platforms.Architecture.MIPS64, platforms.Byteorder.LITTLE
|
34
|
+
)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import typing
|
2
|
+
|
3
|
+
from .... import platforms
|
4
|
+
from . import stack
|
5
|
+
|
6
|
+
|
7
|
+
class PowerPCStack(stack.DescendingStack):
|
8
|
+
"""A stack for a PPC 32-bit CPU"""
|
9
|
+
|
10
|
+
def get_pointer(self) -> int:
|
11
|
+
return (self.address + self.size) - self.get_used()
|
12
|
+
|
13
|
+
def get_alignment(self) -> int:
|
14
|
+
return 4
|
15
|
+
|
16
|
+
@classmethod
|
17
|
+
def initialize_stack(cls, argv: typing.List[bytes], *args, **kwargs):
|
18
|
+
raise NotImplementedError("Stack initialization not implemented for PowerPC")
|
19
|
+
|
20
|
+
|
21
|
+
class PowerPC32Stack(PowerPCStack):
|
22
|
+
"""A stack for a PPC 32-bit CPU"""
|
23
|
+
|
24
|
+
platform = platforms.Platform(
|
25
|
+
platforms.Architecture.POWERPC32, platforms.Byteorder.BIG
|
26
|
+
)
|
27
|
+
|
28
|
+
|
29
|
+
class PowerPC64Stack(PowerPCStack):
|
30
|
+
"""A stack for a PPC 64-bit CPU"""
|
31
|
+
|
32
|
+
platform = platforms.Platform(
|
33
|
+
platforms.Architecture.POWERPC64, platforms.Byteorder.BIG
|
34
|
+
)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import typing
|
2
|
+
|
3
|
+
from .... import platforms
|
4
|
+
from . import stack
|
5
|
+
|
6
|
+
|
7
|
+
class RISCV64Stack(stack.DescendingStack):
|
8
|
+
"""A stack for a RISCV 64-bit CPU"""
|
9
|
+
|
10
|
+
platform = platforms.Platform(
|
11
|
+
platforms.Architecture.RISCV64, platforms.Byteorder.LITTLE
|
12
|
+
)
|
13
|
+
|
14
|
+
def get_pointer(self) -> int:
|
15
|
+
return (self.address + self.size) - self.get_used()
|
16
|
+
|
17
|
+
def get_alignment(self) -> int:
|
18
|
+
return 16
|
19
|
+
|
20
|
+
@classmethod
|
21
|
+
def initialize_stack(cls, argv: typing.List[bytes], *args, **kwargs):
|
22
|
+
raise NotImplementedError("Stack initialization not implemented for AArch64")
|
@@ -0,0 +1,127 @@
|
|
1
|
+
import abc
|
2
|
+
import typing
|
3
|
+
|
4
|
+
from .... import platforms, utils
|
5
|
+
from ... import state
|
6
|
+
from .. import memory
|
7
|
+
|
8
|
+
|
9
|
+
class Stack(memory.Memory):
|
10
|
+
"""A stack-like region of memory with convenient operations like push and pop."""
|
11
|
+
|
12
|
+
@property
|
13
|
+
@abc.abstractmethod
|
14
|
+
def platform(self) -> platforms.Platform:
|
15
|
+
"""The platform for which this stack is intended."""
|
16
|
+
pass
|
17
|
+
|
18
|
+
@classmethod
|
19
|
+
def get_platform(cls) -> platforms.Platform:
|
20
|
+
"""Retrieve the platform for this stack."""
|
21
|
+
if not isinstance(cls.platform, platforms.Platform):
|
22
|
+
raise TypeError(f"{cls.__name__}.platform is not a Platform object")
|
23
|
+
return cls.platform
|
24
|
+
|
25
|
+
@abc.abstractmethod
|
26
|
+
def get_pointer(self) -> int:
|
27
|
+
"""Get the current stack pointer.
|
28
|
+
|
29
|
+
Returns:
|
30
|
+
The current value of the stack pointer.
|
31
|
+
"""
|
32
|
+
pass
|
33
|
+
|
34
|
+
@abc.abstractmethod
|
35
|
+
def get_alignment(self) -> int:
|
36
|
+
"""Get the alignment for this stack.
|
37
|
+
|
38
|
+
Returns:
|
39
|
+
The alignment for this stack.
|
40
|
+
"""
|
41
|
+
pass
|
42
|
+
|
43
|
+
@abc.abstractmethod
|
44
|
+
def push(self, value: state.Value) -> int:
|
45
|
+
"""Push a value to the stack.
|
46
|
+
|
47
|
+
Arguments:
|
48
|
+
value: The value to be pushed.
|
49
|
+
Returns:
|
50
|
+
The stack pointer after the push.
|
51
|
+
"""
|
52
|
+
pass
|
53
|
+
|
54
|
+
def push_integer(self, integer: int, size: int, label: str) -> int:
|
55
|
+
"""Push an integer to the stack.
|
56
|
+
|
57
|
+
Arguments:
|
58
|
+
integer: The integer value to be pushed.
|
59
|
+
size: The size in bytes for the integer on the stack.
|
60
|
+
label: The label for the integer.
|
61
|
+
Returns:
|
62
|
+
The stack pointer after the push.
|
63
|
+
"""
|
64
|
+
|
65
|
+
value = state.IntegerValue(integer, size, label)
|
66
|
+
return self.push(value)
|
67
|
+
|
68
|
+
def push_bytes(self, content: typing.Union[bytes, bytearray], label: str) -> int:
|
69
|
+
"""Push some bytes to the stack.
|
70
|
+
|
71
|
+
Arguments:
|
72
|
+
content: The bytes to push.
|
73
|
+
label: The label for the bytes.
|
74
|
+
|
75
|
+
Returns:
|
76
|
+
The stack pointer after the push.
|
77
|
+
"""
|
78
|
+
value = state.BytesValue(content, label)
|
79
|
+
return self.push(value)
|
80
|
+
|
81
|
+
def push_ctype(self, content: typing.Any, label: str) -> int:
|
82
|
+
"""Push some structured bytes to the stack.
|
83
|
+
|
84
|
+
Arguments:
|
85
|
+
content: The ctypes structured bytes.
|
86
|
+
label: The label for the bytes.
|
87
|
+
Returns:
|
88
|
+
The stack pointer after the push.
|
89
|
+
"""
|
90
|
+
value = state.Value.from_ctypes(content, label)
|
91
|
+
return self.push(value)
|
92
|
+
|
93
|
+
@classmethod
|
94
|
+
def for_platform(cls, platform: platforms.Platform, address: int, size: int):
|
95
|
+
"""Create a stack for this platform.
|
96
|
+
|
97
|
+
Arguments:
|
98
|
+
platform: The platform for which this stack is intended.
|
99
|
+
address: Start address for this stack.
|
100
|
+
size: Size of requested stack, in bytes.
|
101
|
+
"""
|
102
|
+
|
103
|
+
def check(x):
|
104
|
+
if x.get_platform():
|
105
|
+
return (
|
106
|
+
x.get_platform().architecture == platform.architecture
|
107
|
+
and x.get_platform().byteorder == platform.byteorder
|
108
|
+
)
|
109
|
+
return False
|
110
|
+
|
111
|
+
try:
|
112
|
+
return utils.find_subclass(cls, check, address, size)
|
113
|
+
except ValueError:
|
114
|
+
raise ValueError(f"No stack for {platform}")
|
115
|
+
|
116
|
+
|
117
|
+
class DescendingStack(Stack):
|
118
|
+
"""A stack that grows down, i.e., a push will decrease the stack pointer."""
|
119
|
+
|
120
|
+
def push(self, value: state.Value) -> int:
|
121
|
+
self._is_safe(value)
|
122
|
+
offset = (self.get_capacity()) - self.get_used() - value.get_size()
|
123
|
+
self[offset] = value
|
124
|
+
return offset
|
125
|
+
|
126
|
+
|
127
|
+
__all__ = ["Stack"]
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import typing
|
2
|
+
|
3
|
+
from .... import platforms
|
4
|
+
from . import stack
|
5
|
+
|
6
|
+
|
7
|
+
class XTensaStack(stack.DescendingStack):
|
8
|
+
"""A stack for an XTensa CPU"""
|
9
|
+
|
10
|
+
def get_pointer(self) -> int:
|
11
|
+
return (self.address + self.size) - self.get_used()
|
12
|
+
|
13
|
+
def get_alignment(self) -> int:
|
14
|
+
return 4
|
15
|
+
|
16
|
+
@classmethod
|
17
|
+
def initialize_stack(cls, argv: typing.List[bytes], *args, **kwargs):
|
18
|
+
raise NotImplementedError("Stack initialization not implemented for XTensa")
|
19
|
+
|
20
|
+
|
21
|
+
class XTensaBEStack(XTensaStack):
|
22
|
+
"""A stack for a big-endian XTensa CPU"""
|
23
|
+
|
24
|
+
platform = platforms.Platform(
|
25
|
+
platforms.Architecture.XTENSA, platforms.Byteorder.BIG
|
26
|
+
)
|
27
|
+
|
28
|
+
|
29
|
+
class XTensaELStack(XTensaStack):
|
30
|
+
"""A stack for a little-endian XTensa CPU"""
|
31
|
+
|
32
|
+
platform = platforms.Platform(
|
33
|
+
platforms.Architecture.XTENSA, platforms.Byteorder.LITTLE
|
34
|
+
)
|
@@ -0,0 +1,186 @@
|
|
1
|
+
import abc
|
2
|
+
import logging
|
3
|
+
import typing
|
4
|
+
|
5
|
+
import claripy
|
6
|
+
|
7
|
+
from ... import emulators
|
8
|
+
from .. import state
|
9
|
+
|
10
|
+
logger = logging.getLogger(__name__)
|
11
|
+
|
12
|
+
|
13
|
+
class MemoryMappedModel(state.Stateful):
|
14
|
+
"""A model of a memory-mapped IO device dealing with concrete values
|
15
|
+
|
16
|
+
This lets you specify alternate handler routines
|
17
|
+
for reads and writes within a range of memory addressess,
|
18
|
+
bypassing the emulator's normal memory model.
|
19
|
+
As the name suggests, this is useful for modeling
|
20
|
+
MMIO devices, where accessing a particular address
|
21
|
+
actually accesses a register of a peripheral device.
|
22
|
+
|
23
|
+
The callback routines on_read() and on_write()
|
24
|
+
will trigger on any access within the specified range;
|
25
|
+
one MemoryMappedModel can handle multiple registers,
|
26
|
+
allowing you to model an entire device, or even a set of adjacent devices
|
27
|
+
in one object.
|
28
|
+
|
29
|
+
Arguments:
|
30
|
+
address: Starting address of the MMIO region
|
31
|
+
size: Size of the MMIO region in bytes
|
32
|
+
"""
|
33
|
+
|
34
|
+
def __init__(self, address: int, size: int):
|
35
|
+
self.address = address
|
36
|
+
self.size = size
|
37
|
+
|
38
|
+
@abc.abstractmethod
|
39
|
+
def on_read(
|
40
|
+
self, emu: emulators.Emulator, addr: int, size: int, unused: bytes
|
41
|
+
) -> typing.Optional[bytes]:
|
42
|
+
"""Callback handling reads from an MMIO register
|
43
|
+
|
44
|
+
NOTE: Results must be encoded in the emulator's byte order.
|
45
|
+
|
46
|
+
NOTE: Attempting to access memory in this MMIO range
|
47
|
+
inside this handler will produce undefined behavior.
|
48
|
+
|
49
|
+
Arguments:
|
50
|
+
emu: The emulator object mediating this operation
|
51
|
+
addr: The start address of the read operation
|
52
|
+
size: The number of bytes read
|
53
|
+
|
54
|
+
Returns:
|
55
|
+
`size` bytes containing the result of the modeled read
|
56
|
+
"""
|
57
|
+
raise NotImplementedError("Abstract method")
|
58
|
+
|
59
|
+
@abc.abstractmethod
|
60
|
+
def on_write(
|
61
|
+
self, emu: emulators.Emulator, addr: int, size: int, value: bytes
|
62
|
+
) -> None:
|
63
|
+
"""Callback handling writes to an MMIO register
|
64
|
+
|
65
|
+
NOTE: `value` will be encoded in the emulator's byte order.
|
66
|
+
|
67
|
+
NOTE: Attempting to access memory in this MMIO range
|
68
|
+
inside this handler will produce undefined behavior.
|
69
|
+
|
70
|
+
Arguments:
|
71
|
+
emu: The emulator object mediating this operation
|
72
|
+
addr: The start address of the write operation
|
73
|
+
size: The number of bytes written
|
74
|
+
value: The bytes written
|
75
|
+
"""
|
76
|
+
raise NotImplementedError("Abstract method")
|
77
|
+
|
78
|
+
def extract(self, emulator: emulators.Emulator) -> None:
|
79
|
+
logger.debug(f"Skipping extract for {self} (mmio)")
|
80
|
+
|
81
|
+
def apply(self, emulator: emulators.Emulator) -> None:
|
82
|
+
logger.debug(f"Hooking MMIO {self} {self.address:x}")
|
83
|
+
emulator.map_memory(self.address, self.size)
|
84
|
+
if self.on_read is not None:
|
85
|
+
if not isinstance(emulator, emulators.MemoryReadHookable):
|
86
|
+
raise NotImplementedError("Emulator does not support read hooking")
|
87
|
+
emulator.hook_memory_read(
|
88
|
+
self.address, self.address + self.size, self.on_read
|
89
|
+
)
|
90
|
+
if self.on_write is not None:
|
91
|
+
if not isinstance(emulator, emulators.MemoryWriteHookable):
|
92
|
+
raise NotImplementedError("Emulator does not support write hooking")
|
93
|
+
emulator.hook_memory_write(
|
94
|
+
self.address, self.address + self.size, self.on_write
|
95
|
+
)
|
96
|
+
|
97
|
+
def __repr__(self) -> str:
|
98
|
+
return f"{self.__class__.__name__}({hex(self.address)})"
|
99
|
+
|
100
|
+
|
101
|
+
class SymbolicMemoryMappedModel(state.Stateful):
|
102
|
+
"""A model of a memory-mapped IO device dealing with symbolic values
|
103
|
+
|
104
|
+
This lets you specify alternate handler routines
|
105
|
+
for reads and writes within a range of memory addressess,
|
106
|
+
bypassing the emulator's normal memory model.
|
107
|
+
As the name suggests, this is useful for modeling
|
108
|
+
MMIO devices, where accessing a particular address
|
109
|
+
actually accesses a register of a peripheral device.
|
110
|
+
|
111
|
+
The callback routines on_read() and on_write()
|
112
|
+
will trigger on any access within the specified range;
|
113
|
+
one MemoryMappedModel can handle multiple registers,
|
114
|
+
allowing you to model an entire device, or even a set of adjacent devices
|
115
|
+
in one object.
|
116
|
+
|
117
|
+
Arguments:
|
118
|
+
address: Starting address of the MMIO region
|
119
|
+
size: Size of the MMIO region in bytes
|
120
|
+
"""
|
121
|
+
|
122
|
+
def __init__(self, address: int, size: int):
|
123
|
+
self.address = address
|
124
|
+
self.size = size
|
125
|
+
|
126
|
+
@abc.abstractmethod
|
127
|
+
def on_read(
|
128
|
+
self, emu: emulators.Emulator, addr: int, size: int, unused: claripy.ast.bv.BV
|
129
|
+
) -> typing.Optional[claripy.ast.bv.BV]:
|
130
|
+
"""Callback handling reads from an MMIO register
|
131
|
+
|
132
|
+
NOTE: Results must be encoded in the emulator's byte order.
|
133
|
+
|
134
|
+
NOTE: Attempting to access memory in this MMIO range
|
135
|
+
inside this handler will produce undefined behavior.
|
136
|
+
|
137
|
+
Arguments:
|
138
|
+
emu: The emulator object mediating this operation
|
139
|
+
addr: The start address of the read operation
|
140
|
+
size: The number of bytes read
|
141
|
+
|
142
|
+
Returns:
|
143
|
+
`size` bytes containing the result of the modeled read
|
144
|
+
"""
|
145
|
+
raise NotImplementedError("Abstract method")
|
146
|
+
|
147
|
+
@abc.abstractmethod
|
148
|
+
def on_write(
|
149
|
+
self, emu: emulators.Emulator, addr: int, size: int, value: claripy.ast.bv.BV
|
150
|
+
) -> None:
|
151
|
+
"""Callback handling writes to an MMIO register
|
152
|
+
|
153
|
+
NOTE: `value` will be encoded in the emulator's byte order.
|
154
|
+
|
155
|
+
NOTE: Attempting to access memory in this MMIO range
|
156
|
+
inside this handler will produce undefined behavior.
|
157
|
+
|
158
|
+
Arguments:
|
159
|
+
emu: The emulator object mediating this operation
|
160
|
+
addr: The start address of the write operation
|
161
|
+
size: The number of bytes written
|
162
|
+
value: The bytes written
|
163
|
+
"""
|
164
|
+
raise NotImplementedError("Abstract method")
|
165
|
+
|
166
|
+
def extract(self, emulator: emulators.Emulator) -> None:
|
167
|
+
logger.debug(f"Skipping extract for {self} (mmio)")
|
168
|
+
|
169
|
+
def apply(self, emulator: emulators.Emulator) -> None:
|
170
|
+
logger.debug(f"Hooking MMIO {self} {self.address:x}")
|
171
|
+
emulator.map_memory(self.address, self.size)
|
172
|
+
if self.on_read is not None:
|
173
|
+
if not isinstance(emulator, emulators.MemoryReadHookable):
|
174
|
+
raise NotImplementedError("Emulator does not support read hooking")
|
175
|
+
emulator.hook_memory_read_symbolic(
|
176
|
+
self.address, self.address + self.size, self.on_read
|
177
|
+
)
|
178
|
+
if self.on_write is not None:
|
179
|
+
if not isinstance(emulator, emulators.MemoryWriteHookable):
|
180
|
+
raise NotImplementedError("Emulator does not support write hooking")
|
181
|
+
emulator.hook_memory_write_symbolic(
|
182
|
+
self.address, self.address + self.size, self.on_write
|
183
|
+
)
|
184
|
+
|
185
|
+
def __repr__(self) -> str:
|
186
|
+
return f"{self.__class__.__name__}({hex(self.address)})"
|