Represent a PE loaded in a process (current or remote)
| 305 | ] |
| 306 | |
| 307 | class PEFile(object): |
| 308 | """Represent a PE loaded in a process (current or remote)""" |
| 309 | |
| 310 | def __init__(self, target, baseaddr, targetedbitness, transformers): |
| 311 | self.target = target |
| 312 | self.baseaddr = baseaddr |
| 313 | self.bitness = targetedbitness |
| 314 | self.transformers = transformers |
| 315 | |
| 316 | if targetedbitness == 32: |
| 317 | self.IMAGE_ORDINAL_FLAG = IMAGE_ORDINAL_FLAG32 |
| 318 | else: |
| 319 | self.IMAGE_ORDINAL_FLAG = IMAGE_ORDINAL_FLAG64 |
| 320 | |
| 321 | def get_DOS_HEADER(self): |
| 322 | return self.transformers.create_structure_at(IMAGE_DOS_HEADER, self.baseaddr) |
| 323 | |
| 324 | def get_NT_HEADER(self): |
| 325 | offset = self.get_DOS_HEADER().e_lfanew |
| 326 | if self.bitness == 32: |
| 327 | return self.transformers.create_structure_at(IMAGE_NT_HEADERS32, self.baseaddr + offset) |
| 328 | return self.transformers.create_structure_at(IMAGE_NT_HEADERS64, self.baseaddr + offset) |
| 329 | |
| 330 | |
| 331 | STANDARD_OPTIONAL_HEADER_TYPE_PER_MAGIC = { |
| 332 | IMAGE_NT_OPTIONAL_HDR32_MAGIC: IMAGE_OPTIONAL_HEADER32, |
| 333 | IMAGE_NT_OPTIONAL_HDR64_MAGIC: IMAGE_OPTIONAL_HEADER64, |
| 334 | } |
| 335 | |
| 336 | STANDARD_OPTIONAL_HEADER_SIZE_PER_MAGIC = ( |
| 337 | (IMAGE_NT_OPTIONAL_HDR32_MAGIC, ctypes.sizeof(IMAGE_OPTIONAL_HEADER32)), |
| 338 | (IMAGE_NT_OPTIONAL_HDR64_MAGIC, ctypes.sizeof(IMAGE_OPTIONAL_HEADER64)), |
| 339 | ) |
| 340 | |
| 341 | def get_OptionalHeader(self): |
| 342 | # We can have a 32bits PE with a 64 bits OptionalHeader |
| 343 | # Ex : PE32 .NET that allow to be loaded in 64b process |
| 344 | # See: https://github.com/dotnet/runtime/blob/8bbe33819464216becffb7cf8b7ea8dd3bab5836/src/coreclr/src/vm/peimagelayout.cpp#L599 |
| 345 | # In this case the OptionalHeader is transformed in 64bits & OptionalHeader.Magic is changed accordingly |
| 346 | # So we cannot just rely on get_NT_HEADER() to give us the correct OptionalHeader type. some re-check are required |
| 347 | default_opth = self.get_NT_HEADER().OptionalHeader |
| 348 | # Cannot juste compare types with type(default_opth) as it may be a remoteType |
| 349 | current_opth_infos = (default_opth.Magic, ctypes.sizeof(default_opth)) |
| 350 | if current_opth_infos in self.STANDARD_OPTIONAL_HEADER_SIZE_PER_MAGIC: |
| 351 | # The default OptionalHeader structure match what we expect based on the magic (most of the cases) |
| 352 | return default_opth |
| 353 | # Mismatch -> PE32 remapped as 64b (with OptionalHeader rewrite) |
| 354 | # Remap the correct OptionalHeader |
| 355 | opt_header_real_type = self.STANDARD_OPTIONAL_HEADER_TYPE_PER_MAGIC[default_opth.Magic] |
| 356 | opt_header_addr = default_opth._base_addr if self.target else ctypes.addressof(default_opth) |
| 357 | return self.transformers.create_structure_at(opt_header_real_type, opt_header_addr) |
| 358 | |
| 359 | def get_DataDirectory(self): |
| 360 | return self.get_OptionalHeader().DataDirectory |
| 361 | |
| 362 | |
| 363 | def get_IMPORT_DESCRIPTORS(self): |
| 364 | import_datadir = self.get_DataDirectory()[IMAGE_DIRECTORY_ENTRY_IMPORT] |