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
File without changes
@@ -0,0 +1,393 @@
1
+ import logging
2
+ import typing
3
+
4
+ import lief
5
+
6
+ from ..emulators import Emulator
7
+ from ..exceptions import ConfigurationError
8
+ from ..hinting import Hint, get_hinter
9
+ from .state import Code, Memory
10
+
11
+ log = logging.getLogger(__name__)
12
+ hinter = get_hinter(__name__)
13
+
14
+ # Prorgam header types
15
+ PT_NULL = 0 # Empty/unused program header
16
+ PT_LOAD = 1 # Describes loadable program segment
17
+ PT_DYNAMIC = 2 # Points to dynamic linking metadata
18
+ PT_INTERP = 3 # Points to program interpreter
19
+ PT_NOTE = 4 # Points to auxiliary information
20
+ PT_SHLIB = 5 # Reserved value; I think it's unused
21
+ PT_PHDR = 6 # Points to program header table
22
+ PT_TLS = 7 # Indicates need for thread-local storage
23
+ PT_LOOS = 0x60000000 # Start of OS-specific types
24
+ PT_GNU_EH_FRAME = 0x6474E550 # GNU-specific: Points to exception handler segment
25
+ PT_GNU_STACK = 0x6474E551 # GNU-specific: Describes stack permissions
26
+ PT_GNU_RELRO = 0x6474E552 # GNU-specific: Describes read-only after relocation segment
27
+ PT_GNU_PROPERTY = 0x6474E553 # GNU-specific: Points to GNU property
28
+ PT_HIOS = 0x6FFFFFFF # End of OS-specific types
29
+ PT_LOPROC = 0x70000000 # Start of processor-specific types
30
+ PT_HIPROC = 0x7FFFFFFF # End of processor-specific types
31
+
32
+ # Program header flags
33
+ PF_X = 0x1 # Segment is executable
34
+ PF_W = 0x2 # Segment is writable
35
+ PF_R = 0x4 # Segment is readable
36
+
37
+
38
+ class ELFImage(Code):
39
+ default_base = 0x400000
40
+ page_size = 0x1000
41
+
42
+ def __init__(
43
+ self,
44
+ image: bytes,
45
+ format: typing.Optional[str] = None,
46
+ arch: typing.Optional[str] = None,
47
+ mode: typing.Optional[str] = None,
48
+ base: typing.Optional[int] = None,
49
+ entry: typing.Optional[int] = None,
50
+ bounds: typing.Optional[typing.Iterable[range]] = None,
51
+ ):
52
+ super().__init__(
53
+ image,
54
+ base=0,
55
+ format=format,
56
+ arch=arch,
57
+ mode=mode,
58
+ entry=None,
59
+ bounds=bounds,
60
+ )
61
+ self.user_base: typing.Optional[int] = base
62
+ self.file_base: int = 0
63
+ self.user_entry: typing.Optional[int] = entry
64
+ self.file_entry: int = 0
65
+
66
+ self.code_segments: typing.List[Code] = list()
67
+ self.data_segments: typing.List[Memory] = list()
68
+
69
+ self.load_elf()
70
+
71
+ def determine_base(self):
72
+ """Determine base address to load ELF
73
+
74
+ There are two possible sources for a base address.
75
+ ELF files can specify a base address by setting the address
76
+ of their first loaded segment to non-zero.
77
+ Otherwise, a user can request a specific base address.
78
+
79
+ If both the user and the file specify an address, it's an error.
80
+ If only one specifies a base address, use it.
81
+ If neither specify one, halucinate a value.
82
+
83
+ Raises:
84
+ ConfigurationError: If file_base is non-zero, and user_base is not None
85
+ """
86
+ if self.user_base is None:
87
+ # No base address requested
88
+ if self.file_base == 0:
89
+ # Progam file does not need a specific base address
90
+ # Use a default
91
+ # FIXME: Using a fixed value will not be valid if we load multiple files
92
+ hint = Hint(
93
+ message=f"No base address requested, and ELF is PIC. Using {hex(self.default_base)}"
94
+ )
95
+ hinter.info(hint)
96
+ self.base = self.default_base
97
+ else:
98
+ # Program file needs a specific base address
99
+ # Use the specified address
100
+ self.base = self.file_base
101
+ else:
102
+ # Base address requested
103
+ if self.file_base == 0:
104
+ # Program file does not need a specific base address
105
+ # Use the requested address
106
+ self.user_base
107
+ elif self.file_base == self.user_base:
108
+ # User and file request the same base address.
109
+ # We are okay with this.
110
+ self.user_base
111
+ else:
112
+ # Program file needs a specific base address
113
+ # Not possible to rebase
114
+ hint = Hint(
115
+ message=f"Requested base address {hex(self.user_base)}, but program needs {hex(self.file_base)}"
116
+ )
117
+ hinter.error(hint)
118
+ raise ConfigurationError("Contradictory base addresses.")
119
+
120
+ def determine_entry(self):
121
+ """Determine entrypoint address to use
122
+
123
+ This performs two jobs.
124
+ One is to determine which entrypoint to use;
125
+ it can be specified by the ELF header, or by the user.
126
+
127
+ The second job is to rebase that address
128
+ according to the base address.
129
+ An entrypoint from the file is relative to the file's base address.
130
+ An entrypoint from the user is assumed relative to the user's base address.
131
+ If the user does not specify a base address, their entrypoint
132
+ should be relative to the start of the file.
133
+
134
+ Raises:
135
+ ConfigurationError: If neither user nor file specify an entrypoint
136
+
137
+ """
138
+ if self.user_entry is None:
139
+ # No entrypoint requested.
140
+ # Get entry from the file
141
+ if self.file_entry == 0:
142
+ # No one specified an entrypoint.
143
+ # No entrypoint will be set for this file.
144
+ self.entry = None
145
+ # file_entry is relative to file_base; rebase relative to base
146
+ self.entry = self.file_entry - self.file_base + self.base
147
+ else:
148
+ # Entrypoint requested.
149
+ if self.user_base is None:
150
+ user_base = 0
151
+ else:
152
+ user_base = self.user_base
153
+ # user_entry is relative to user_base, or zero if none requested
154
+ # rebase relative to base
155
+ self.entry = self.user_entry - user_base + self.base
156
+
157
+ def rebase_user(self, addr: int):
158
+ """Helper function for rebasing user-relative addresses"""
159
+ if self.user_base is None:
160
+ old_base = 0
161
+ else:
162
+ old_base = self.user_base
163
+ if self.base is None:
164
+ base = 0
165
+ else:
166
+ base = self.base
167
+ return addr - old_base + base
168
+
169
+ def rebase_file(self, addr: int):
170
+ """Helper function for rebasing file-relative addresses"""
171
+ if self.base is None:
172
+ base = 0
173
+ else:
174
+ base = self.base
175
+ return addr - self.file_base + base
176
+
177
+ def page_align(self, x: int, up: bool = True):
178
+ """Align an address to a page boundary
179
+
180
+ Arguments:
181
+ x (int): Address to align
182
+ up (bool): If true, round up. If false, round down
183
+
184
+ Return:
185
+ (int): Aligned version of the address
186
+ """
187
+ if up:
188
+ x += self.page_size - 1
189
+ return (x // self.page_size) * self.page_size
190
+
191
+ def load_elf(self):
192
+ """Load an ELF file into a SmallWorld machine state object.
193
+
194
+ This parses the ELF header and the program headers,
195
+ does minimal validation, and then maps the loadable segments into memory.
196
+ It also reports RE-relevant features of the binary as hints.
197
+
198
+ This function assumes that the program should be loaded
199
+ using the architecture and mode from the CPU object.
200
+
201
+ The user can specify a base address and entrypoint.
202
+ If not specified, this function defaults to the addresses specified in the ELF.
203
+
204
+ If both user and ELF specify a base address,
205
+ this function will raise an exception.
206
+
207
+ If netither user nor ELF specify a base address,
208
+ a default will be used.
209
+
210
+ If both user and ELF specify an entrypoint,
211
+ the user's entrypoint takes precedence.
212
+
213
+ If neither user nor elf specify an entrypoint,
214
+ no entrypoint will be set for this file.
215
+
216
+ Raises:
217
+ ConfigurationError: If the ELF is invalid, or user-provided data conflicts with ELF.
218
+ """
219
+ # Use lief to check if this is an ELF
220
+ # NOTE: for some reason, this takes list[int], not bytes
221
+ if not lief.is_elf(list(self.image)):
222
+ hint = Hint(message="File is not an elf.")
223
+ hinter.error(hint)
224
+ raise ConfigurationError("Input is not an elf")
225
+
226
+ # Use lief to parse the ELF
227
+ # NOTE: for some reason, this takes list[int], not bytes
228
+ elf = lief.ELF.parse(list(self.image))
229
+ if elf is None:
230
+ raise ConfigurationError("Failed parsing input")
231
+
232
+ ehdr = elf.header
233
+ if ehdr is None:
234
+ raise ConfigurationError("Failed extracting Elf header")
235
+
236
+ # TODO: Check machine compatibility?
237
+ # - ei_class
238
+ # - ei_data
239
+ # - ei_osabi (some ABIs)
240
+ # - e_machine
241
+ # - e_flags (some ABIs)
242
+
243
+ # Figure out if this file is loadable.
244
+ # Easiest way to tell is if there are program headers
245
+ if ehdr.program_header_offset == 0:
246
+ # NULL phoff means no program headers.
247
+ # This file is not loadable; time to use another ELF loader.
248
+ hint = Hint(message="No program headers; file is not loadable")
249
+ hinter.error(hint)
250
+ raise ConfigurationError("File not loadable")
251
+ if ehdr.program_header_offset >= len(self.image):
252
+ hint = Hint(
253
+ message=f"Invalid program header offset: {hex(ehdr.program_header_offset)}"
254
+ )
255
+ hinter.error(hint)
256
+ raise ConfigurationError("Invalid program header offset")
257
+
258
+ # Determine the file base address,
259
+ # entrypoint, and exit points
260
+ self.file_base = elf.imagebase
261
+ self.file_entry = elf.entrypoint
262
+ self.determine_base()
263
+ self.determine_entry()
264
+ self.exits = list(map(lambda x: self.rebase_user(x), self.exits))
265
+
266
+ for phdr in elf.segments:
267
+ log.debug(f"{phdr}")
268
+ if phdr.type == PT_LOAD:
269
+ # Loadable segment
270
+ # Map its data into memory
271
+ self.map_segment(phdr)
272
+ elif phdr.type == PT_DYNAMIC:
273
+ # Dynamic linking metadata.
274
+ # This ELF needs dynamic linking
275
+ hint = Hint(message="Program includes dynamic linking metadata")
276
+ hinter.info(hint)
277
+ elif phdr.type == PT_INTERP:
278
+ # Program interpreter
279
+ # This completely changes how program loading works.
280
+ # Whether you care is a different matter.
281
+ interp = self.image[
282
+ phdr.file_offset : phdr.file_offset + phdr.physical_size
283
+ ]
284
+ hint = Hint(message=f"Program specifies interpreter {interp!r}")
285
+ hinter.info(hint)
286
+ elif phdr.type == PT_NOTE:
287
+ # Auxiliary information
288
+ # Possibly useful for comparing machine/OS type.
289
+ pass
290
+ elif phdr.type == PT_PHDR:
291
+ # Program header self-reference
292
+ # Useful for the dynamic linker, but not for us
293
+ pass
294
+ elif phdr.type == PT_TLS:
295
+ # TLS Segment
296
+ # Your analysis is about to get nasty :(
297
+ hint = Hint(message="Program includes thread-local storage")
298
+ hinter.info(hint)
299
+ elif phdr.type == PT_GNU_EH_FRAME:
300
+ # Exception handler frame.
301
+ # GCC puts one of these in everything. Do we care?
302
+ pass
303
+ elif phdr.type == PT_GNU_STACK:
304
+ # Stack executability
305
+ # If this is missing, assume executable stack
306
+ hint = Hint(message="Program specifies stack permissions")
307
+ hinter.info(hint)
308
+ elif phdr.type == PT_GNU_RELRO:
309
+ # Read-only after relocation
310
+ # Only the dynamic linker should write this data.
311
+ hint = Hint(message="Program specifies RELRO data")
312
+ hinter.info(hint)
313
+ elif phdr.type == PT_GNU_PROPERTY:
314
+ # GNU property segment
315
+ # Contains extra metadata which I'm not sure anything uses
316
+ pass
317
+ elif phdr.type >= PT_LOOS and phdr.type <= PT_HIOS:
318
+ # Unknown OS-specific program header
319
+ # Either this is a weird ISA that extends the generic GNU ABI,
320
+ # or this isn't a Linux ELF.
321
+ hint = Hint(f"Unknown OS-specific program header: {phdr.type:08x}")
322
+ hinter.warn(hint)
323
+ elif phdr.type >= PT_LOPROC and phdr.type <= PT_HIPROC:
324
+ # Unknown machine-specific program header
325
+ # This is probably a non-Intel ISA.
326
+ # Most of these are harmless, serving to tell the RTLD
327
+ # where to find machine-specific metadata
328
+ hint = Hint(f"Unknown machine-specific program header: {phdr.type:08x}")
329
+ hinter.warn(hint)
330
+ else:
331
+ # Unknown program header outside the allowed custom ranges
332
+ hint = Hint(f"Invalid program header: {phdr.type:08x}")
333
+ hinter.warn(hint)
334
+
335
+ def map_segment(self, phdr):
336
+ """Map a segment into a SmallWorld machine state object
337
+
338
+ This computes the actual mapping boundaries from a LOAD segment,
339
+ and then maps it into Smallworld.
340
+
341
+ Executable segments are mapped as Code objects.
342
+ Other segments are mapped as Memory.
343
+
344
+ Arguments:
345
+ phdr: Program header object to load
346
+ """
347
+
348
+ # Compute segment boundaries
349
+ seg_start = self.page_align(phdr.file_offset, up=False)
350
+ seg_end = self.page_align(phdr.file_offset + phdr.physical_size)
351
+ seg_addr = self.page_align(self.rebase_file(phdr.virtual_address), up=False)
352
+ seg_size = self.page_align(phdr.virtual_size + (phdr.file_offset - seg_start))
353
+
354
+ log.debug(f"{phdr.physical_size:012x}")
355
+
356
+ log.debug("Mapping: ")
357
+ log.debug(f" f: [ {seg_start:012x} -> {seg_end:012x} ]")
358
+ log.debug(f" m: [ {seg_addr:012x} -> {seg_addr + seg_size:012x} ]")
359
+
360
+ # Extract segment data, and zero-fill out to seg_size
361
+ seg_data = self.image[seg_start:seg_end]
362
+ if len(seg_data) < seg_size:
363
+ seg_data += b"\x00" * (seg_size - len(seg_data))
364
+ elif len(seg_data) != seg_size:
365
+ # Virtual size should always be greater or equal to file size.
366
+ # If not, something's wrong.
367
+ raise ConfigurationError(
368
+ f"Expected segment of size {seg_size}, but got {len(seg_data)}"
369
+ )
370
+
371
+ if (phdr.flags & PF_X) != 0:
372
+ # If this is an executable segment, treat it as code
373
+ code = Code(
374
+ image=seg_data,
375
+ format="blob",
376
+ arch=self.arch,
377
+ mode=self.mode,
378
+ base=seg_addr,
379
+ entry=self.entry,
380
+ exits=self.exits,
381
+ )
382
+ self.code_segments.append(code)
383
+ else:
384
+ # Otherwise, treat it as Memory
385
+ data = Memory(seg_addr, seg_size)
386
+ data.set(seg_data)
387
+ self.data_segments.append(data)
388
+
389
+ def apply(self, emulator: Emulator, override: bool = True):
390
+ for code in self.code_segments:
391
+ code.apply(emulator)
392
+ for data in self.data_segments:
393
+ data.apply(emulator)
@@ -0,0 +1,30 @@
1
+ import typing
2
+
3
+ from .state import Register
4
+
5
+
6
+ class X86MMRRegister(Register):
7
+ """x86 Memory Management Register
8
+
9
+ These things have a special internal format,
10
+ represented by the 4-tuple (selector, base, limit, flags).
11
+
12
+ Unicorn takes these as a 4-tuple.
13
+
14
+ angr doesn't take an actual value;
15
+ it takes a pointer to a host-allocated table. I think.
16
+ """
17
+
18
+ def set_content(self, content: typing.Optional[typing.Any]):
19
+ self._content = content
20
+
21
+ def __str__(self):
22
+ s = f"Reg({self.name},{self.size})="
23
+ x = self.get_content()
24
+ if x is None:
25
+ s = s + "=None"
26
+ elif isinstance(x, tuple):
27
+ s = s + ", ".join(map(lambda v: hex(v), x))
28
+ else:
29
+ s = s + "External ref {hex(x)}"
30
+ return s