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,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,6 @@
1
+ from . import x86
2
+ from .mmio import MemoryMappedModel
3
+ from .model import * # noqa: F401, F403
4
+ from .model import __all__ as __model__
5
+
6
+ __all__ = __model__ + ["MemoryMappedModel", "x86"]
@@ -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)})"