diff --git a/minidump/__main__.py b/minidump/__main__.py index e0ab944..81be45b 100644 --- a/minidump/__main__.py +++ b/minidump/__main__.py @@ -27,6 +27,7 @@ def run(): parser.add_argument('--exception', action='store_true', help='Show exception records') parser.add_argument('--handles', action='store_true', help='List handles') parser.add_argument('--misc', action='store_true', help='Show misc info') + parser.add_argument('--peb', action='store_true', help='Show PEB info') parser.add_argument('--all', action='store_true', help='Show all info') parser.add_argument('-r', '--read-addr', type=lambda x: int(x,0), help='Dump a memory region from the process\'s addres space') parser.add_argument('-s', '--read-size', type=lambda x: int(x,0), default = 0x20, help='Dump a memory region from the process\'s addres space') @@ -89,6 +90,10 @@ def run(): print(str(mf.misc_info)) if args.all or args.header: print(str(mf.header)) + + if args.all or args.peb: + if mf.peb is not None: + print(str(mf.peb)) if args.read_addr: buff_reader = reader.get_buffered_reader() diff --git a/minidump/_version.py b/minidump/_version.py index 28189d4..6a2cb48 100644 --- a/minidump/_version.py +++ b/minidump/_version.py @@ -1,5 +1,5 @@ -__version__ = "0.0.23" +__version__ = "0.0.24" __banner__ = \ """ # minidump %s diff --git a/minidump/constants.py b/minidump/constants.py index 4a9b947..4366841 100644 --- a/minidump/constants.py +++ b/minidump/constants.py @@ -66,50 +66,3 @@ class MINIDUMP_TYPE(enum.IntFlag): MiniDumpFilterTriage = 0x00100000 MiniDumpValidTypeFlags = 0x001fffff - -OFFSETS = [ - { # x86 offsets - # _TEB offsets - "peb": 0x30, - # _PEB offsets - "being_debugged": 0x2, - "image_base_address": 0x8, - "process_parameters": 0x10, - # _RTL_USER_PROCESS_PARAMETERS offsets - "image_path": 0x38, - "command_line": 0x40, - "window_title": 0x70, - "dll_path": 0x30, - "current_directory": 0x24, - "standard_input": 0x18, - "standard_output": 0x1C, - "standard_error": 0x20, - "environment_variables": 0x48, - # _UNICODE_STRING offsets - "buffer": 0x4, - }, - { # x64 offsets - # _TEB offsets - "peb": 0x60, - # _PEB offsets - "being_debugged": 0x2, - "image_base_address": 0x10, - "process_parameters": 0x20, - # _RTL_USER_PROCESS_PARAMETERS offsets - "image_path": 0x60, - "command_line": 0x70, - "window_title": 0xB0, - "dll_path": 0x50, - "current_directory": 0x38, - "standard_input": 0x20, - "standard_output": 0x28, - "standard_error": 0x30, - "environment_variables": 0x80, - # _UNICODE_STRING offsets - "buffer": 0x8, - }, -] - - -POINTER_SIZE = [4, 8] # x86 (32 bit size pointer) # x64 (64 bit size pointer) - diff --git a/minidump/directory.py b/minidump/directory.py index 75993a9..f476eff 100644 --- a/minidump/directory.py +++ b/minidump/directory.py @@ -4,8 +4,8 @@ class MINIDUMP_DIRECTORY: def __init__(self): - self.StreamType = None - self.Location = None + self.StreamType:MINIDUMP_STREAM_TYPE = None + self.Location:MINIDUMP_LOCATION_DESCRIPTOR = None def to_bytes(self): t = self.StreamType.value.to_bytes(4, byteorder = 'little', signed = False) diff --git a/minidump/header.py b/minidump/header.py index fc1f6c7..032e089 100644 --- a/minidump/header.py +++ b/minidump/header.py @@ -5,15 +5,15 @@ # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680378(v=vs.85).aspx class MinidumpHeader: def __init__(self): - self.Signature = 'PMDM' - self.Version = None - self.ImplementationVersion = None - self.NumberOfStreams = None - self.StreamDirectoryRva = None - self.CheckSum = 0 - self.Reserved = 0 - self.TimeDateStamp = 0 - self.Flags = None + self.Signature:str = 'PMDM' + self.Version:int = None + self.ImplementationVersion:int = None + self.NumberOfStreams:int = None + self.StreamDirectoryRva:int = None + self.CheckSum:int = 0 + self.Reserved:int = 0 + self.TimeDateStamp:int = 0 + self.Flags:MINIDUMP_TYPE = None def to_bytes(self): t = self.Signature.encode('ascii') diff --git a/minidump/minidumpfile.py b/minidump/minidumpfile.py index 2dc52d1..1c066a0 100644 --- a/minidump/minidumpfile.py +++ b/minidump/minidumpfile.py @@ -9,37 +9,41 @@ import enum import struct import logging +from typing import List from minidump.header import MinidumpHeader from minidump.minidumpreader import MinidumpFileReader from minidump.streams import * from minidump.common_structs import * -from minidump.constants import MINIDUMP_STREAM_TYPE, OFFSETS, POINTER_SIZE +from minidump.constants import MINIDUMP_STREAM_TYPE from minidump.directory import MINIDUMP_DIRECTORY from minidump.streams.SystemInfoStream import PROCESSOR_ARCHITECTURE +from minidump.structures.peb import PEB class MinidumpFile: def __init__(self): - self.filename = None + self.filename:str = None self.file_handle = None - self.header = None - self.directories = [] - - self.threads_ex = None - self.threads = None - self.modules = None - self.memory_segments = None - self.memory_segments_64 = None - self.sysinfo = None - self.comment_a = None - self.comment_w = None - self.exception = None - self.handles = None - self.unloaded_modules = None - self.misc_info = None - self.memory_info = None - self.thread_info = None + self.header:MinidumpHeader = None + self.directories: List[MINIDUMP_DIRECTORY] = [] + + self.threads_ex:MinidumpThreadExList = None + self.threads:MinidumpThreadList = None + self.modules:MinidumpModuleList = None + self.memory_segments:MinidumpMemoryList = None + self.memory_segments_64:MinidumpMemory64List = None + self.sysinfo:MinidumpSystemInfo = None + self.comment_a:CommentStreamA = None + self.comment_w:CommentStreamW = None + self.exception:ExceptionList = None + self.handles:MinidumpHandleDataStream = None + self.unloaded_modules:MinidumpUnloadedModuleList = None + self.misc_info:MinidumpMiscInfo = None + self.memory_info:MinidumpMemoryInfoList = None + self.thread_info:MinidumpThreadInfoList = None + + self.peb:PEB = None @staticmethod def parse(filename): @@ -78,82 +82,10 @@ def get_reader(self): def _parse(self): self.__parse_header() self.__parse_directories() - self.__parse_peb() - - def __read_unicode_string_property(self, buff_reader, addr, x64): - buff_reader.move(addr) - string_length = int.from_bytes(buff_reader.read(2), "little") - if not string_length: - return "" - buff_reader.move(addr + OFFSETS[x64]["buffer"]) - buff_va = int.from_bytes(buff_reader.read(POINTER_SIZE[x64]), "little") - buff_reader.move(buff_va) - return buff_reader.read(string_length).decode("utf-16") - - def __parse_peb(self): - self.x64 = (self.memory_segments_64 is not None) or (self.memory_segments and any(mem.start_virtual_address > 0xFFFFFFFF for mem in self.memory_segments)) - offset_index = self.x64 - - reader = self.get_reader() - buff_reader = reader.get_buffered_reader() - - buff_reader.move(self.threads.threads[0].Teb + OFFSETS[offset_index]["peb"]) - - self.peb_address = int.from_bytes(buff_reader.read(POINTER_SIZE[self.x64]), "little") - - buff_reader.move(self.peb_address + OFFSETS[offset_index]["being_debugged"]) - self.being_debugged = int.from_bytes(buff_reader.read(1), "little") - - buff_reader.move(self.peb_address + OFFSETS[offset_index]["image_base_address"]) - self.image_base_address = int.from_bytes(buff_reader.read(POINTER_SIZE[self.x64]), "little") - - buff_reader.move(self.peb_address + OFFSETS[offset_index]["process_parameters"]) - process_parameters = int.from_bytes(buff_reader.read(POINTER_SIZE[self.x64]), "little") - - self.image_path = self.__read_unicode_string_property( - buff_reader, process_parameters + OFFSETS[offset_index]["image_path"], self.x64 - ) - - self.command_line = self.__read_unicode_string_property( - buff_reader, process_parameters + OFFSETS[offset_index]["command_line"], self.x64 - ) - - self.window_title = self.__read_unicode_string_property( - buff_reader, process_parameters + OFFSETS[offset_index]["window_title"], self.x64 - ) - - self.dll_path = self.__read_unicode_string_property(buff_reader, process_parameters + OFFSETS[offset_index]["dll_path"], - self.x64) - - self.current_directory = self.__read_unicode_string_property( - buff_reader, process_parameters + OFFSETS[offset_index]["current_directory"], self.x64 - ) - - buff_reader.move(process_parameters + OFFSETS[offset_index]["standard_input"]) - self.standard_input = int.from_bytes(buff_reader.read(POINTER_SIZE[self.x64]), "little") - - buff_reader.move(process_parameters + OFFSETS[offset_index]["standard_output"]) - self.standard_output = int.from_bytes(buff_reader.read(POINTER_SIZE[self.x64]), "little") - - buff_reader.move(process_parameters + OFFSETS[offset_index]["standard_error"]) - self.standard_error = int.from_bytes(buff_reader.read(POINTER_SIZE[self.x64]), "little") - - # Parse Environment Variables from PEB - self.environment_variables = [] - buff_reader.move(process_parameters + OFFSETS[offset_index]["environment_variables"]) - environment_va = int.from_bytes(buff_reader.read(POINTER_SIZE[self.x64]), "little") - buff_reader.move(environment_va) - - env_buffer = buff_reader.read(buff_reader.current_segment.end_address - buff_reader.current_position) - while (env_len := env_buffer.find(b"\x00\x00")) and (env_len != -1): - decoded_env = (env_buffer[:env_len] + b"\x00").decode("utf-16") - name = decoded_env.split("=")[0] - value = decoded_env.split("=")[1] - self.environment_variables.append({"name": name, "value": value}) - environment_va += (len(decoded_env) + 1) * 2 - buff_reader.move(environment_va) - env_buffer = buff_reader.read(buff_reader.current_segment.end_address - buff_reader.current_position) - + try: + self.__parse_peb() + except Exception as e: + logging.exception('PEB parsing error!') def __parse_header(self): self.header = MinidumpHeader.parse(self.file_handle) @@ -296,6 +228,13 @@ def __parse_thread_context(self): elif self.sysinfo.ProcessorArchitecture == PROCESSOR_ARCHITECTURE.INTEL: thread.ContextObject = WOW64_CONTEXT.parse(self.file_handle) + def __parse_peb(self): + if not self.sysinfo or not self.threads: + return + + self.peb = PEB.from_minidump(self) + + def __str__(self): t = '== Minidump File ==\n' diff --git a/minidump/minidumpreader.py b/minidump/minidumpreader.py index 98b0048..05689f9 100644 --- a/minidump/minidumpreader.py +++ b/minidump/minidumpreader.py @@ -272,9 +272,6 @@ def find_in_module(self, module_name, pattern, find_first = False, reverse_order t = self.reader.search_module(module_name, pattern, find_first = find_first, reverse_order = reverse_order, chunksize = self.segment_chunk_size) return t - - - class MinidumpFileReader: def __init__(self, minidumpfile): self.modules = minidumpfile.modules.modules @@ -358,4 +355,3 @@ def read(self, virt_addr, size): if segment.inrange(virt_addr): return segment.read(virt_addr, size, self.file_handle) raise Exception('Address not in memory range! %s' % hex(virt_addr)) - diff --git a/minidump/minidumpshell.py b/minidump/minidumpshell.py index cc70598..5fa1435 100644 --- a/minidump/minidumpshell.py +++ b/minidump/minidumpshell.py @@ -28,6 +28,11 @@ def do_open(self, filename): """Opens minidump file""" self.mini = MinidumpFile.parse(filename) self.reader = self.mini.get_reader().get_buffered_reader() + + def do_peb(self, args): + """Shows PEB information (if available)""" + if self.mini.peb is not None: + print(str(self.mini.peb)) def do_threads(self, args): """Lists all thread information (if available)""" diff --git a/minidump/streams/CommentStreamA.py b/minidump/streams/CommentStreamA.py index 55b7d16..0aa5c29 100644 --- a/minidump/streams/CommentStreamA.py +++ b/minidump/streams/CommentStreamA.py @@ -5,7 +5,7 @@ # class CommentStreamA: def __init__(self): - self.data = None + self.data:str = None def to_bytes(self): return self.data.encode('ascii') diff --git a/minidump/streams/CommentStreamW.py b/minidump/streams/CommentStreamW.py index b3fce15..9992af8 100644 --- a/minidump/streams/CommentStreamW.py +++ b/minidump/streams/CommentStreamW.py @@ -5,7 +5,7 @@ # class CommentStreamW: def __init__(self): - self.data = None + self.data:str = None def to_bytes(self): return self.data.encode('utf-16-le') diff --git a/minidump/streams/ExceptionStream.py b/minidump/streams/ExceptionStream.py index 81d915c..a87889d 100644 --- a/minidump/streams/ExceptionStream.py +++ b/minidump/streams/ExceptionStream.py @@ -7,15 +7,16 @@ import io import enum +from typing import List from minidump.common_structs import * # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680368(v=vs.85).aspx class MINIDUMP_EXCEPTION_STREAM: def __init__(self): - self.ThreadId = None - self.alignment = None - self.ExceptionRecord = None - self.ThreadContext = None + self.ThreadId:int = None + self.alignment:int = None + self.ExceptionRecord:MINIDUMP_EXCEPTION = None + self.ThreadContext:MINIDUMP_LOCATION_DESCRIPTOR = None @staticmethod def parse(buff): @@ -176,7 +177,7 @@ def to_row(self): class ExceptionList: def __init__(self): - self.exception_records = [] + self.exception_records:List[MINIDUMP_EXCEPTION_STREAM] = [] @staticmethod def parse(dir, buff): diff --git a/minidump/streams/FunctionTableStream.py b/minidump/streams/FunctionTableStream.py index a247091..4ed77d8 100644 --- a/minidump/streams/FunctionTableStream.py +++ b/minidump/streams/FunctionTableStream.py @@ -5,12 +5,12 @@ # class MINIDUMP_FUNCTION_TABLE_STREAM: def __init__(self): - self.SizeOfHeader = None - self.SizeOfDescriptor = None - self.SizeOfNativeDescriptor = None - self.SizeOfFunctionEntry = None - self.NumberOfDescriptors = None - self.SizeOfAlignPad = None + self.SizeOfHeader:int = None + self.SizeOfDescriptor:int = None + self.SizeOfNativeDescriptor:int = None + self.SizeOfFunctionEntry:int = None + self.NumberOfDescriptors:int = None + self.SizeOfAlignPad:int = None @staticmethod def parse(dir, buff): diff --git a/minidump/streams/HandleDataStream.py b/minidump/streams/HandleDataStream.py index 7899b26..db8de29 100644 --- a/minidump/streams/HandleDataStream.py +++ b/minidump/streams/HandleDataStream.py @@ -6,14 +6,15 @@ import io import enum from minidump.common_structs import * +from typing import List # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680372(v=vs.85).aspx class MINIDUMP_HANDLE_DATA_STREAM: def __init__(self): - self.SizeOfHeader = None - self.SizeOfDescriptor = None - self.NumberOfDescriptors = None - self.Reserved = None + self.SizeOfHeader:int = None + self.SizeOfDescriptor:int = None + self.NumberOfDescriptors:int = None + self.Reserved:int = None @staticmethod def parse(buff): @@ -29,13 +30,13 @@ def parse(buff): class MINIDUMP_HANDLE_DESCRIPTOR: size = 32 def __init__(self): - self.Handle = None - self.TypeNameRva = None - self.ObjectNameRva = None - self.Attributes = None - self.GrantedAccess = None - self.HandleCount = None - self.PointerCount = None + self.Handle:int = None + self.TypeNameRva:int = None + self.ObjectNameRva:int = None + self.Attributes:int = None + self.GrantedAccess:int = None + self.HandleCount:int = None + self.PointerCount:int = None @staticmethod def parse(buff): @@ -53,15 +54,15 @@ def parse(buff): # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680373(v=vs.85).aspx class MINIDUMP_HANDLE_DESCRIPTOR_2: def __init__(self): - self.Handle = None - self.TypeNameRva = None - self.ObjectNameRva = None - self.Attributes = None - self.GrantedAccess = None - self.HandleCount = None - self.PointerCount = None - self.ObjectInfoRva = None - self.Reserved0 = None + self.Handle:int = None + self.TypeNameRva:int = None + self.ObjectNameRva:int = None + self.Attributes:int = None + self.GrantedAccess:int = None + self.HandleCount:int = None + self.PointerCount:int = None + self.ObjectInfoRva:int = None + self.Reserved0:int = None @staticmethod def parse(buff): @@ -89,12 +90,12 @@ class MINIDUMP_HANDLE_OBJECT_INFORMATION_TYPE(enum.Enum): class MINIDUMP_HANDLE_OBJECT_INFORMATION: def __init__(self): - self.NextInfoRva = None - self.InfoType = None - self.SizeOfInfo = None + self.NextInfoRva:int = None + self.InfoType:int = None + self.SizeOfInfo:int = None #high-level, delete this when documentation becomes available! - self.info_bytes = None + self.info_bytes:bytes = None @staticmethod def parse(buff): @@ -120,9 +121,9 @@ async def aparse(buff): class MinidumpHandleObjectInformation: def __init__(self): self.NextInfo = None - self.InfoType = None - self.SizeOfInfo = None - self.info_bytes = None + self.InfoType:int = None + self.SizeOfInfo:int = None + self.info_bytes:bytes = None @staticmethod def parse(mhoi): @@ -139,14 +140,14 @@ def __str__(self): class MinidumpHandleDescriptor: def __init__(self): - self.Handle = None - self.TypeName = None - self.ObjectName = None - self.Attributes = None - self.GrantedAccess = None - self.HandleCount = None - self.PointerCount = None - self.ObjectInfos = [] + self.Handle:int = None + self.TypeName:str = None + self.ObjectName:str = None + self.Attributes:int = None + self.GrantedAccess:int = None + self.HandleCount:int = None + self.PointerCount:int = None + self.ObjectInfos:List[MinidumpHandleObjectInformation] = [] @staticmethod def parse(t, buff): @@ -216,8 +217,8 @@ def __str__(self): class MinidumpHandleDataStream: def __init__(self): - self.header = None - self.handles = [] + self.header:MINIDUMP_HANDLE_DATA_STREAM = None + self.handles:List[MinidumpHandleDescriptor] = [] @staticmethod def parse(dir, buff): diff --git a/minidump/streams/HandleOperationListStream.py b/minidump/streams/HandleOperationListStream.py index 47a30fb..b515d86 100644 --- a/minidump/streams/HandleOperationListStream.py +++ b/minidump/streams/HandleOperationListStream.py @@ -5,10 +5,10 @@ # class MINIDUMP_HANDLE_OPERATION_LIST: def __init__(self): - self.SizeOfHeader = None - self.SizeOfEntry = None - self.NumberOfEntries = None - self.Reserved = None + self.SizeOfHeader:int = None + self.SizeOfEntry:int = None + self.NumberOfEntries:int = None + self.Reserved:int = None @staticmethod def parse(dir, buff): diff --git a/minidump/streams/LastReservedStream.py b/minidump/streams/LastReservedStream.py index 55ffed9..b934f2c 100644 --- a/minidump/streams/LastReservedStream.py +++ b/minidump/streams/LastReservedStream.py @@ -5,8 +5,8 @@ # class MINIDUMP_USER_STREAM: def __init__(self): - self.Type = None - self.BufferSize = None + self.Type:int = None + self.BufferSize:int = None self.Buffer = None @staticmethod diff --git a/minidump/streams/Memory64ListStream.py b/minidump/streams/Memory64ListStream.py index 57d4466..fc929e3 100644 --- a/minidump/streams/Memory64ListStream.py +++ b/minidump/streams/Memory64ListStream.py @@ -5,13 +5,14 @@ # import io from minidump.common_structs import * +from typing import List # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680387(v=vs.85).aspx class MINIDUMP_MEMORY64_LIST: def __init__(self): - self.NumberOfMemoryRanges = None - self.BaseRva = None - self.MemoryRanges = [] + self.NumberOfMemoryRanges:int = None + self.BaseRva:int = None + self.MemoryRanges:List[MINIDUMP_MEMORY_DESCRIPTOR64] = [] def get_size(self): return 8 + 8 + len(self.MemoryRanges) * MINIDUMP_MEMORY_DESCRIPTOR64().get_size() @@ -52,8 +53,8 @@ def __str__(self): # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680384(v=vs.85).aspx class MINIDUMP_MEMORY_DESCRIPTOR64: def __init__(self): - self.StartOfMemoryRange = None - self.DataSize = None + self.StartOfMemoryRange:int = None + self.DataSize:int = None def get_size(self): return 16 @@ -77,7 +78,7 @@ def __str__(self): class MinidumpMemory64List: def __init__(self): - self.memory_segments = [] + self.memory_segments:List[MinidumpMemorySegment] = [] @staticmethod def parse(dir, buff): diff --git a/minidump/streams/MemoryInfoListStream.py b/minidump/streams/MemoryInfoListStream.py index 557620a..0f71d2e 100644 --- a/minidump/streams/MemoryInfoListStream.py +++ b/minidump/streams/MemoryInfoListStream.py @@ -65,9 +65,9 @@ class MemoryState(enum.Enum): # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680385(v=vs.85).aspx class MINIDUMP_MEMORY_INFO_LIST: def __init__(self): - self.SizeOfHeader = 16 - self.SizeOfEntry = 48 - self.NumberOfEntries = None + self.SizeOfHeader:int = 16 + self.SizeOfEntry:int = 48 + self.NumberOfEntries:int = None self.entries = [] def get_size(self): diff --git a/minidump/structures/__init__.py b/minidump/structures/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/minidump/structures/peb.py b/minidump/structures/peb.py new file mode 100644 index 0000000..84b4975 --- /dev/null +++ b/minidump/structures/peb.py @@ -0,0 +1,166 @@ +from minidump.streams.SystemInfoStream import PROCESSOR_ARCHITECTURE + + +PEB_OFFSETS = [ + { # x86 offsets + # _TEB offsets + "peb": 0x30, + # _PEB offsets + "being_debugged": 0x2, + "image_base_address": 0x8, + "process_parameters": 0x10, + # _RTL_USER_PROCESS_PARAMETERS offsets + "image_path": 0x38, + "command_line": 0x40, + "window_title": 0x70, + "dll_path": 0x30, + "current_directory": 0x24, + "standard_input": 0x18, + "standard_output": 0x1C, + "standard_error": 0x20, + "environment_variables": 0x48, + # _UNICODE_STRING offsets + "buffer": 0x4, + }, + { # x64 offsets + # _TEB offsets + "peb": 0x60, + # _PEB offsets + "being_debugged": 0x2, + "image_base_address": 0x10, + "process_parameters": 0x20, + # _RTL_USER_PROCESS_PARAMETERS offsets + "image_path": 0x60, + "command_line": 0x70, + "window_title": 0xB0, + "dll_path": 0x50, + "current_directory": 0x38, + "standard_input": 0x20, + "standard_output": 0x28, + "standard_error": 0x30, + "environment_variables": 0x80, + # _UNICODE_STRING offsets + "buffer": 0x8, + }, +] + +class PEB: + def __init__(self): + self.address = None + self.is_x64 = None + self.ptr_size = None + self.being_debugged = None + self.image_base_address = None + self.process_parameters = None + self.image_path = None + self.command_line = None + self.window_title = None + self.dll_path = None + self.current_directory = None + self.standard_input = None + self.standard_output = None + self.standard_error = None + self.environment_variables = [] + + def read_unicode_string_property(self, reader, addr): + reader.move(addr) + string_length = int.from_bytes(reader.read(2), "little") + if not string_length: + return "" + reader.move(addr + PEB_OFFSETS[self.is_x64]["buffer"]) + buff_va = int.from_bytes(reader.read(self.ptr_size), "little") + reader.move(buff_va) + return reader.read(string_length).decode("utf-16") + + @staticmethod + def from_minidump(minidumpfile): + reader = minidumpfile.get_reader() + buff_reader = reader.get_buffered_reader() + + peb = PEB() + peb.is_x64 = not(reader.sysinfo.ProcessorArchitecture == PROCESSOR_ARCHITECTURE.INTEL) #dunno if this is the best way... + peb.ptr_size = 8 if peb.is_x64 else 4 + offset_index = int(peb.is_x64) + + buff_reader.move(minidumpfile.threads.threads[0].Teb + PEB_OFFSETS[offset_index]["peb"]) + + peb.address = int.from_bytes(buff_reader.read(peb.ptr_size), "little") + + buff_reader.move(peb.address + PEB_OFFSETS[offset_index]["being_debugged"]) + peb.being_debugged = int.from_bytes(buff_reader.read(1), "little") + + buff_reader.move(peb.address + PEB_OFFSETS[offset_index]["image_base_address"]) + peb.image_base_address = int.from_bytes(buff_reader.read(peb.ptr_size), "little") + + buff_reader.move(peb.address + PEB_OFFSETS[offset_index]["process_parameters"]) + process_parameters = int.from_bytes(buff_reader.read(peb.ptr_size), "little") + + peb.image_path = peb.read_unicode_string_property( + buff_reader, process_parameters + PEB_OFFSETS[offset_index]["image_path"] + ) + + peb.command_line = peb.read_unicode_string_property( + buff_reader, process_parameters + PEB_OFFSETS[offset_index]["command_line"] + ) + + peb.window_title = peb.read_unicode_string_property( + buff_reader, process_parameters + PEB_OFFSETS[offset_index]["window_title"] + ) + + peb.dll_path = peb.read_unicode_string_property(buff_reader, process_parameters + PEB_OFFSETS[offset_index]["dll_path"]) + + peb.current_directory = peb.read_unicode_string_property( + buff_reader, process_parameters + PEB_OFFSETS[offset_index]["current_directory"] + ) + + buff_reader.move(process_parameters + PEB_OFFSETS[offset_index]["standard_input"]) + peb.standard_input = int.from_bytes(buff_reader.read(peb.ptr_size), "little") + + buff_reader.move(process_parameters + PEB_OFFSETS[offset_index]["standard_output"]) + peb.standard_output = int.from_bytes(buff_reader.read(peb.ptr_size), "little") + + buff_reader.move(process_parameters + PEB_OFFSETS[offset_index]["standard_error"]) + peb.standard_error = int.from_bytes(buff_reader.read(peb.ptr_size), "little") + + # Parse Environment Variables from PEB + buff_reader.move(process_parameters + PEB_OFFSETS[offset_index]["environment_variables"]) + environment_va = int.from_bytes(buff_reader.read(peb.ptr_size), "little") + buff_reader.move(environment_va) + + env_buffer = buff_reader.read(buff_reader.current_segment.end_address - buff_reader.current_position) + while (env_len := env_buffer.find(b"\x00\x00")) and (env_len != -1): + decoded_env = (env_buffer[:env_len] + b"\x00").decode("utf-16") + name = decoded_env + value = "" + if decoded_env.find("=") != -1: + name, value = decoded_env.split("=", 1) + peb.environment_variables.append({"name": name, "value": value}) + environment_va += (len(decoded_env) + 1) * 2 + buff_reader.move(environment_va) + env_buffer = buff_reader.read(buff_reader.current_segment.end_address - buff_reader.current_position) + + return peb + + def __str__(self): + envs = "\n\t".join([f"{env['name']}={env['value']}" for env in self.environment_variables]) + return f""" +PEB ADDR: {hex(self.address)} +BeingDebugged: {self.being_debugged} +ImageBaseAddress: {hex(self.image_base_address)} +ProcessParameters: {self.process_parameters} +ImagePath: {self.image_path} +CommandLine: {self.command_line} +WindowTitle: {self.window_title} +DllPath: {self.dll_path} +CurrentDirectory: {self.current_directory} +StandardInput: {self.standard_input} +StandardOutput: {self.standard_output} +StandardError: {self.standard_error} +EnvironmentVariables: + {envs} +""" + + def __repr__(self): + return self.__str__() + +