From 09a7b6f4debfa02790623089b4d0e5c8385f2c4f Mon Sep 17 00:00:00 2001 From: Duncan Ogilvie Date: Sun, 10 Dec 2023 21:09:20 +0100 Subject: [PATCH 1/2] Fix leftover issue with inrange calls Closes #35 --- minidump/aminidumpreader.py | 4 ++-- minidump/minidumpreader.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/minidump/aminidumpreader.py b/minidump/aminidumpreader.py index 9cb16df..f398a8c 100644 --- a/minidump/aminidumpreader.py +++ b/minidump/aminidumpreader.py @@ -157,7 +157,7 @@ async def peek(self, length): Returns up to length bytes from the current memory segment """ t = self.current_position + length - if not self.current_segment.inrange(t): + if not self.current_segment.inrange(t - 1): raise Exception('Would read over segment boundaries!') return await self.current_segment.read(self.reader.file_handle, self.current_position - self.current_segment.start_address , t - self.current_segment.start_address) @@ -177,7 +177,7 @@ async def read(self, size = -1): return await self.current_segment.read(self.reader.file_handle, old_new_pos - self.current_segment.start_address, None) t = self.current_position + size - if not self.current_segment.inrange(t): + if not self.current_segment.inrange(t - 1): raise Exception('Would read over segment boundaries!') old_new_pos = self.current_position diff --git a/minidump/minidumpreader.py b/minidump/minidumpreader.py index 43477fa..382cfe9 100644 --- a/minidump/minidumpreader.py +++ b/minidump/minidumpreader.py @@ -163,7 +163,7 @@ def peek(self, length): Returns up to length bytes from the current memory segment """ t = self.current_position + length - if not self.current_segment.inrange(t): + if not self.current_segment.inrange(t - 1): raise Exception('Would read over segment boundaries!') return self.current_segment.read(self.reader.file_handle, self.current_position - self.current_segment.start_address , t - self.current_segment.start_address) From 37454bcb877f9eff3dd5ec5ec2086a34cad08181 Mon Sep 17 00:00:00 2001 From: Duncan Ogilvie Date: Sun, 10 Dec 2023 21:13:33 +0100 Subject: [PATCH 2/2] Remove trailing whitespace --- minidump/__amain__.py | 8 +- minidump/__main__.py | 10 +-- minidump/_version.py | 2 +- minidump/aminidumpreader.py | 10 +-- minidump/common_structs.py | 82 +++++++++---------- minidump/directory.py | 2 +- minidump/exceptions.py | 4 +- minidump/minidumpfile.py | 6 +- minidump/minidumpreader.py | 14 ++-- minidump/minidumpshell.py | 6 +- minidump/streams/CommentStreamA.py | 4 +- minidump/streams/CommentStreamW.py | 6 +- minidump/streams/ContextStream.py | 34 ++++---- minidump/streams/ExceptionStream.py | 35 ++++---- minidump/streams/FunctionTableStream.py | 4 +- minidump/streams/HandleDataStream.py | 52 ++++++------ minidump/streams/HandleOperationListStream.py | 5 +- minidump/streams/LastReservedStream.py | 4 +- minidump/streams/Memory64ListStream.py | 21 +++-- minidump/streams/MemoryInfoListStream.py | 36 ++++---- minidump/streams/MemoryListStream.py | 28 +++---- minidump/streams/MiscInfoStream.py | 18 ++-- minidump/streams/ModuleListStream.py | 39 +++++---- minidump/streams/ThreadExListStream.py | 27 +++--- minidump/streams/ThreadInfoListStream.py | 37 ++++----- minidump/streams/ThreadListStream.py | 24 +++--- minidump/streams/UnloadedModuleListStream.py | 34 ++++---- minidump/utils/createminidump.py | 61 +++++++------- minidump/utils/winapi/kernel32.py | 4 +- minidump/win_datatypes.py | 67 ++++++++------- minidump/writer.py | 40 ++++----- 31 files changed, 358 insertions(+), 366 deletions(-) diff --git a/minidump/__amain__.py b/minidump/__amain__.py index ba2abfc..e6742e4 100644 --- a/minidump/__amain__.py +++ b/minidump/__amain__.py @@ -28,7 +28,7 @@ async def run(): 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') - + args = parser.parse_args() if args.verbose == 0: logging.basicConfig(level=logging.INFO) @@ -38,11 +38,11 @@ async def run(): logging.basicConfig(level=1) print(__banner__) - + mf = await AMinidumpFile.parse(args.minidumpfile) reader = mf.get_reader() - + if args.all or args.threads: if mf.threads is not None: print(str(mf.threads)) @@ -81,7 +81,7 @@ async def run(): print(str(mf.misc_info)) if args.all or args.header: print(str(mf.header)) - + if args.read_addr: buff_reader = reader.get_buffered_reader() await buff_reader.move(args.read_addr) diff --git a/minidump/__main__.py b/minidump/__main__.py index 52d96f4..e0ab944 100644 --- a/minidump/__main__.py +++ b/minidump/__main__.py @@ -30,7 +30,7 @@ def run(): 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') - + args = parser.parse_args() if args.verbose == 0: logging.basicConfig(level=logging.INFO) @@ -40,17 +40,17 @@ def run(): logging.basicConfig(level=1) print(__banner__) - + if args.interactive: shell = MinidumpShell() shell.do_open(args.minidumpfile) shell.cmdloop() else: - + mf = MinidumpFile.parse(args.minidumpfile) reader = mf.get_reader() - + if args.all or args.threads: if mf.threads is not None: print(str(mf.threads)) @@ -89,7 +89,7 @@ def run(): print(str(mf.misc_info)) if args.all or args.header: print(str(mf.header)) - + if args.read_addr: buff_reader = reader.get_buffered_reader() buff_reader.move(args.read_addr) diff --git a/minidump/_version.py b/minidump/_version.py index 7dfc411..367d96c 100644 --- a/minidump/_version.py +++ b/minidump/_version.py @@ -2,6 +2,6 @@ __version__ = "0.0.22" __banner__ = \ """ -# minidump %s +# minidump %s # Author: Tamas Jos @skelsec (skelsecprojects@gmail.com) """ % __version__ \ No newline at end of file diff --git a/minidump/aminidumpreader.py b/minidump/aminidumpreader.py index f398a8c..79c5f4d 100644 --- a/minidump/aminidumpreader.py +++ b/minidump/aminidumpreader.py @@ -16,7 +16,7 @@ def __init__(self, start, end, start_file_address): self.start_file_address = start_file_address self.data = None - + def inrange(self, start, end): return self.start <= start and end<= self.end @@ -45,11 +45,11 @@ async def read(self, file_handle, start, end): if end is None: await file_handle.seek(self.start_file_address + start) return await file_handle.read(self.end_address - (self.start_file_address + start)) - + for chunk in self.chunks: if chunk.inrange(start, end): return chunk.data[start - chunk.start: end - chunk.start] - + if self.total_size <= 2*self.chunksize: chunksize = self.total_size vs = VirtualSegment(0, chunksize, self.start_file_address) @@ -61,12 +61,12 @@ async def read(self, file_handle, start, end): chunksize = max((end-start), self.chunksize) if start + chunksize > self.end_address: chunksize = self.end_address - start - + vs = VirtualSegment(start, start+chunksize, self.start_file_address + start) await file_handle.seek(vs.start_file_address) vs.data = await file_handle.read(chunksize) self.chunks.append(vs) - + return vs.data[start - vs.start: end - vs.start] class AMinidumpBufferedReader: diff --git a/minidump/common_structs.py b/minidump/common_structs.py index e0d03ef..1ec4eec 100644 --- a/minidump/common_structs.py +++ b/minidump/common_structs.py @@ -1,5 +1,5 @@ -# https://msdn.microsoft.com/en-us/library/windows/desktop/ms680383(v=vs.85).aspx +# https://msdn.microsoft.com/en-us/library/windows/desktop/ms680383(v=vs.85).aspx class MINIDUMP_LOCATION_DESCRIPTOR: def __init__(self): self.DataSize = None @@ -12,7 +12,7 @@ def to_bytes(self): t = self.DataSize.to_bytes(4, byteorder = 'little', signed = False) t += self.Rva.to_bytes(4, byteorder = 'little', signed = False) return t - + @staticmethod def parse(buff): mld = MINIDUMP_LOCATION_DESCRIPTOR() @@ -28,11 +28,11 @@ async def aparse(buff): t = await buff.read(4) mld.Rva = int.from_bytes(t, byteorder = 'little', signed = False) return mld - + def __str__(self): t = 'Size: %s File offset: %s' % (self.DataSize, self.Rva) return t - + class MINIDUMP_LOCATION_DESCRIPTOR64: def __init__(self): self.DataSize = None @@ -45,23 +45,23 @@ def to_bytes(self): t = self.DataSize.to_bytes(8, byteorder = 'little', signed = False) t += self.Rva.to_bytes(8, byteorder = 'little', signed = False) return t - + @staticmethod def parse(buff): mld = MINIDUMP_LOCATION_DESCRIPTOR64() mld.DataSize = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) mld.Rva = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) return mld - + def __str__(self): t = 'Size: %s File offset: %s' % (self.DataSize, self.Rva) return t - + class MINIDUMP_STRING: def __init__(self): self.Length = None self.Buffer = None - + @staticmethod def parse(buff): ms = MINIDUMP_STRING() @@ -76,7 +76,7 @@ async def aparse(buff): ms.Length = int.from_bytes(t, byteorder = 'little', signed = False) ms.Buffer = await buff.read(ms.Length) return ms - + @staticmethod def get_from_rva(rva, buff): pos = buff.tell() @@ -87,7 +87,7 @@ def get_from_rva(rva, buff): return ms.Buffer.decode('utf-16-le') except: return '' - + @staticmethod async def aget_from_rva(rva, buff): pos = buff.tell() @@ -98,14 +98,14 @@ async def aget_from_rva(rva, buff): return ms.Buffer.decode('utf-16-le') except: return '' - + class MinidumpMemorySegment: def __init__(self): self.start_virtual_address = None self.size = None self.end_virtual_address = None self.start_file_address = None - + @staticmethod def parse_mini(memory_decriptor, buff): """ @@ -118,7 +118,7 @@ def parse_mini(memory_decriptor, buff): mms.start_file_address = memory_decriptor.Rva mms.end_virtual_address = mms.start_virtual_address + mms.size return mms - + @staticmethod def parse_full(memory_decriptor, rva): mms = MinidumpMemorySegment() @@ -126,20 +126,20 @@ def parse_full(memory_decriptor, rva): mms.size = memory_decriptor.DataSize mms.start_file_address = rva mms.end_virtual_address = mms.start_virtual_address + mms.size - return mms - + return mms + def inrange(self, virt_addr): if virt_addr >= self.start_virtual_address and virt_addr < self.end_virtual_address: return True return False - + def read(self, virtual_address, size, file_handler): if virtual_address > self.end_virtual_address or virtual_address < self.start_virtual_address: raise Exception('Reading from wrong segment!') - + if virtual_address+size > self.end_virtual_address: raise Exception('Read would cross boundaries!') - + pos = file_handler.tell() offset = virtual_address - self.start_virtual_address file_handler.seek(self.start_file_address + offset, 0) @@ -150,17 +150,17 @@ def read(self, virtual_address, size, file_handler): async def aread(self, virtual_address, size, file_handler): if virtual_address > self.end_virtual_address or virtual_address < self.start_virtual_address: raise Exception('Reading from wrong segment!') - + if virtual_address+size > self.end_virtual_address: raise Exception('Read would cross boundaries!') - + pos = file_handler.tell() offset = virtual_address - self.start_virtual_address await file_handler.seek(self.start_file_address + offset, 0) data = await file_handler.read(size) await file_handler.seek(pos, 0) return data - + def search(self, pattern, file_handler, find_first = False, chunksize = 50*1024): if len(pattern) > self.size: return [] @@ -181,14 +181,14 @@ def search(self, pattern, file_handler, find_first = False, chunksize = 50*1024) #print('FOUND! size: %s i: %s read: %s perc: %s' % (self.size, i, i*chunksize, 100*((i*chunksize)/self.size))) file_handler.seek(pos, 0) return [self.start_virtual_address + marker] - - + + #print('NOTFOUND! size: %s i: %s read: %s perc %s' % (self.size, i, len(data), 100*(len(data)/self.size) )) - + else: data = file_handler.read(self.size) file_handler.seek(pos, 0) - + offset = 0 while len(data) > len(pattern): marker = data.find(pattern) @@ -199,7 +199,7 @@ def search(self, pattern, file_handler, find_first = False, chunksize = 50*1024) offset += marker + 1 if find_first is True: return fl - + file_handler.seek(pos, 0) return fl @@ -209,7 +209,7 @@ async def asearch(self, pattern, file_handler, find_first = False, chunksize = 5 pos = file_handler.tell() await file_handler.seek(self.start_file_address, 0) fl = [] - + if find_first is True: chunksize = min(chunksize, self.size) data = b'' @@ -224,10 +224,10 @@ async def asearch(self, pattern, file_handler, find_first = False, chunksize = 5 #print('FOUND! size: %s i: %s read: %s perc: %s' % (self.size, i, i*chunksize, 100*((i*chunksize)/self.size))) await file_handler.seek(pos, 0) return [self.start_virtual_address + marker] - - + + #print('NOTFOUND! size: %s i: %s read: %s perc %s' % (self.size, i, len(data), 100*(len(data)/self.size) )) - + else: offset = 0 data = await file_handler.read(self.size) @@ -241,11 +241,11 @@ async def asearch(self, pattern, file_handler, find_first = False, chunksize = 5 offset += marker + 1 if find_first is True: return fl - + await file_handler.seek(pos, 0) return fl - - + + @staticmethod def get_header(): t = [ @@ -254,7 +254,7 @@ def get_header(): 'Size', ] return t - + def to_row(self): t = [ hex(self.start_virtual_address), @@ -262,12 +262,12 @@ def to_row(self): hex(self.size) ] return t - + def __str__(self): t = 'VA Start: %s, RVA: %s, Size: %s' % (hex(self.start_virtual_address), hex(self.start_file_address), hex(self.size)) return t - - + + def hexdump( src, length=16, sep='.', start = 0): ''' @@ -314,7 +314,7 @@ def hexdump( src, length=16, sep='.', start = 0): else: result.append(('%08x(+%04x): %-'+str(length*(2+1)+1)+'s |%s|') % (start+i, i, hexa, text)); return '\n'.join(result); - + def construct_table(lines, separate_head=True): """Prints a formatted table given a 2 dimensional array""" #Count the column width @@ -325,7 +325,7 @@ def construct_table(lines, separate_head=True): widths.append(0) if size > widths[i]: widths[i] = size - + #Generate the format string to pad the columns print_string = "" for i,width in enumerate(widths): @@ -333,12 +333,12 @@ def construct_table(lines, separate_head=True): if (len(print_string) == 0): return print_string = print_string[:-3] - + #Print the actual data t = '' for i,line in enumerate(lines): t += print_string.format(*line) + '\n' if (i == 0 and separate_head): t += "-"*(sum(widths)+3*(len(widths)-1)) + '\n' - + return t diff --git a/minidump/directory.py b/minidump/directory.py index 6ba4173..75993a9 100644 --- a/minidump/directory.py +++ b/minidump/directory.py @@ -36,7 +36,7 @@ def parse(buff): @staticmethod async def aparse(buff): - + t = await buff.read(4) raw_stream_type_value = int.from_bytes(t, byteorder = 'little', signed = False) diff --git a/minidump/exceptions.py b/minidump/exceptions.py index 32d4f2d..d6e373b 100644 --- a/minidump/exceptions.py +++ b/minidump/exceptions.py @@ -2,11 +2,11 @@ class MinidumpException(Exception): """Generic Exception from minidump module""" pass - + class MinidumpHeaderSignatureMismatchException(Exception): """Header signature was not correct""" pass - + class MinidumpHeaderFlagsException(Exception): """Header flags value was not correct""" pass \ No newline at end of file diff --git a/minidump/minidumpfile.py b/minidump/minidumpfile.py index f342610..c83d10e 100644 --- a/minidump/minidumpfile.py +++ b/minidump/minidumpfile.py @@ -84,7 +84,7 @@ def __parse_header(self): for i in range(0, self.header.NumberOfStreams): self.file_handle.seek(self.header.StreamDirectoryRva + i * 12, 0 ) minidump_dir = MINIDUMP_DIRECTORY.parse(self.file_handle) - + if minidump_dir: self.directories.append(minidump_dir) else: @@ -202,7 +202,7 @@ def __parse_directories(self): """ elif dir.StreamType == MINIDUMP_STREAM_TYPE.HandleOperationListStream: elif dir.StreamType == MINIDUMP_STREAM_TYPE.LastReservedStream: - + """ try: self.__parse_thread_context() @@ -219,7 +219,7 @@ def __parse_thread_context(self): thread.ContextObject = CONTEXT.parse(self.file_handle) elif self.sysinfo.ProcessorArchitecture == PROCESSOR_ARCHITECTURE.INTEL: thread.ContextObject = WOW64_CONTEXT.parse(self.file_handle) - + def __str__(self): t = '== Minidump File ==\n' diff --git a/minidump/minidumpreader.py b/minidump/minidumpreader.py index 382cfe9..98b0048 100644 --- a/minidump/minidumpreader.py +++ b/minidump/minidumpreader.py @@ -14,10 +14,10 @@ def __init__(self, start, end, start_file_address): self.end = end self.start_file_address = start_file_address - + self.data = None - + def inrange(self, start, end): return self.start <= start and end<= self.end @@ -46,11 +46,11 @@ def read(self, file_handle, start, end): if end is None: file_handle.seek(self.start_file_address + start) return file_handle.read(self.end_address - (self.start_file_address + start)) - + for chunk in self.chunks: if chunk.inrange(start, end): return chunk.data[start - chunk.start: end - chunk.start] - + if self.total_size <= 2*self.chunksize: chunksize = self.total_size vs = VirtualSegment(0, chunksize, self.start_file_address) @@ -62,12 +62,12 @@ def read(self, file_handle, start, end): chunksize = max((end-start), self.chunksize) if start + chunksize > self.end_address: chunksize = self.end_address - start - + vs = VirtualSegment(start, start+chunksize, self.start_file_address + start) file_handle.seek(vs.start_file_address) vs.data = file_handle.read(chunksize) self.chunks.append(vs) - + return vs.data[start - vs.start: end - vs.start] @@ -335,7 +335,7 @@ def search_module(self, module_name, pattern, find_first = False, reverse_order mod = self.get_unloaded_by_name(module_name) if mod is None: raise Exception('Could not find module! %s' % module_name) - + needles = [] for ms in self.memory_segments: if mod.baseaddress <= ms.start_virtual_address < mod.endaddress: diff --git a/minidump/minidumpshell.py b/minidump/minidumpshell.py index 8f27dc7..cc70598 100644 --- a/minidump/minidumpshell.py +++ b/minidump/minidumpshell.py @@ -109,7 +109,7 @@ def do_tell(self, args): if x is None: print('Reader not yet positioned! Issue a "move" command with the desired memory address!') print(hex(x)) - + def do_move(self, position): """Sets the current position in the process' virtual memory space""" pos = args2int(position) @@ -145,13 +145,13 @@ def do_peek(self, count): data = self.reader.peek(count) print(hexdump( data, length=self.hexdump_size, sep='.', start = pos_before)) self.update_prompt(None) - + def main(): import argparse parser = argparse.ArgumentParser(description='A parser for minidumnp files') - parser.add_argument('-f', '--minidumpfile', help='path to the minidump file of lsass.exe') + parser.add_argument('-f', '--minidumpfile', help='path to the minidump file of lsass.exe') args = parser.parse_args() shell = MinidumpShell() diff --git a/minidump/streams/CommentStreamA.py b/minidump/streams/CommentStreamA.py index ef3a7c1..55b7d16 100644 --- a/minidump/streams/CommentStreamA.py +++ b/minidump/streams/CommentStreamA.py @@ -9,7 +9,7 @@ def __init__(self): def to_bytes(self): return self.data.encode('ascii') - + @staticmethod def parse(dir, buff): csa = CommentStreamA() @@ -24,6 +24,6 @@ async def aparse(dir, buff): csdata = await buff.read(dir.Location.DataSize) csa.data = csdata.decode() return csa - + def __str__(self): return 'CommentA: %s' % self.data \ No newline at end of file diff --git a/minidump/streams/CommentStreamW.py b/minidump/streams/CommentStreamW.py index c3a5e2f..b3fce15 100644 --- a/minidump/streams/CommentStreamW.py +++ b/minidump/streams/CommentStreamW.py @@ -9,14 +9,14 @@ def __init__(self): def to_bytes(self): return self.data.encode('utf-16-le') - + @staticmethod def parse(dir, buff): csa = CommentStreamW() buff.seek(dir.Location.Rva) csa.data = buff.read(dir.Location.DataSize).decode('utf-16-le') return csa - + @staticmethod async def aparse(dir, buff): csa = CommentStreamW() @@ -24,6 +24,6 @@ async def aparse(dir, buff): csdata = await buff.read(dir.Location.DataSize) csa.data = csdata.decode('utf-16-le') return csa - + def __str__(self): return 'CommentW: %s' % self.data \ No newline at end of file diff --git a/minidump/streams/ContextStream.py b/minidump/streams/ContextStream.py index 6a79c55..55c347f 100644 --- a/minidump/streams/ContextStream.py +++ b/minidump/streams/ContextStream.py @@ -38,17 +38,17 @@ class NEON128(M128A): # https://www.vergiliusproject.com/kernels/x64/Windows%20Vista%20%7C%202008/SP2/_XMM_SAVE_AREA32 class XMM_SAVE_AREA32: def __init__(self): - self.ControlWord = 0 # 0x0 USHORT - self.StatusWord = 0 # 0x2 USHORT - self.TagWord = 0 # 0x4 UCHAR - self.Reserved1 = 0 # 0x5 UCHAR + self.ControlWord = 0 # 0x0 USHORT + self.StatusWord = 0 # 0x2 USHORT + self.TagWord = 0 # 0x4 UCHAR + self.Reserved1 = 0 # 0x5 UCHAR self.ErrorOpcode = 0 # 0x6 USHORT self.ErrorOffset = 0 # 0x8 ULONG - self.ErrorSelector = 0 # 0xc USHORT - self.Reserved2 = 0 # 0xe USHORT + self.ErrorSelector = 0 # 0xc USHORT + self.Reserved2 = 0 # 0xe USHORT self.DataOffset = 0 # 0x10 ULONG - self.DataSelector = 0 # 0x14 USHORT - self.Reserved3 = 0 # 0x16 USHORT + self.DataSelector = 0 # 0x14 USHORT + self.Reserved3 = 0 # 0x16 USHORT self.MxCsr = 0 # 0x18 ULONG self.MxCsr_Mask = 0 # 0x1c ULONG self.FloatRegisters = [] # 0x20 struct M128A[8] @@ -128,7 +128,7 @@ def __init__(self): self.Xmm13 = 0 self.Xmm14 = 0 self.Xmm15 = 0 - + @classmethod def parse(cls, buff): dsn = cls() @@ -189,7 +189,7 @@ def __init__(self): self.D = [] # ULONGLONG [32] self.DUMMYSTRUCTNAME = [] self.S = [] # DWORD [32] - + @classmethod def parse(cls, buff): dun = cls() @@ -221,7 +221,7 @@ def __str__(self): s += "\t%d" % (e) return s - + # https:# docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-context class CONTEXT: @@ -265,7 +265,7 @@ def __init__(self): self.R15 = 0 # DWORD64 self.Rip = 0 # DWORD64 self.DUMMYUNIONNAME = None - + self.VectorRegister = [] # M128A [26] self.VectorControl = 0 # DWORD64 self.DebugControl = 0 # DWORD64 @@ -277,7 +277,7 @@ def __init__(self): @classmethod def parse(cls, buff): ctx = cls() - + ctx.P1Home = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) # DWORD64 ctx.P2Home = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) # DWORD64 ctx.P3Home = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) # DWORD64 @@ -317,7 +317,7 @@ def parse(cls, buff): ctx.R15 = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) # DWORD64 ctx.Rip = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) # DWORD64 ctx.DUMMYUNIONNAME = CTX_DUMMYUNIONNAME.parse(buff) - + ctx.VectorRegister = M128A.parse_array(buff, 26) # M128A [26] ctx.VectorControl = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) # DWORD64 ctx.DebugControl = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) # DWORD64 @@ -329,7 +329,7 @@ def parse(cls, buff): return ctx def __str__(self): - s = "" + s = "" s += "%s: 0x%x (%d)\n" % ("P1Home",self.P1Home,self.P1Home) s += "%s: 0x%x (%d)\n" % ("P2Home",self.P2Home,self.P2Home) s += "%s: 0x%x (%d)\n" % ("P3Home",self.P3Home,self.P3Home) @@ -386,7 +386,7 @@ def __init__(self): self.DataSelector = 0 # DWORD self.RegisterArea = [] # BYTE self.Cr0NpxState = 0 # DWORD - + @classmethod def parse(cls, buff): ctx = cls() @@ -400,7 +400,7 @@ def parse(cls, buff): ctx.RegisterArea = int.from_bytes(buff.read(80), byteorder = 'little', signed = False) ctx.Cr0NpxState = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) return ctx - + def __str__(self): s = '' s += "ControlWord: %x (%d)\n" % (self.ControlWord, self.ControlWord) diff --git a/minidump/streams/ExceptionStream.py b/minidump/streams/ExceptionStream.py index d6f44b9..7980f36 100644 --- a/minidump/streams/ExceptionStream.py +++ b/minidump/streams/ExceptionStream.py @@ -7,7 +7,7 @@ import io import enum -from minidump.common_structs import * +from minidump.common_structs import * # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680368(v=vs.85).aspx class MINIDUMP_EXCEPTION_STREAM: @@ -16,7 +16,7 @@ def __init__(self): self.alignment = None self.ExceptionRecord = None self.ThreadContext = None - + @staticmethod def parse(buff): mes = MINIDUMP_EXCEPTION_STREAM() @@ -33,14 +33,14 @@ def __str__(self): t += 'ExceptionRecord:\n %s\n' % str(self.ExceptionRecord) t += 'ThreadContext: %s\n' % str(self.ThreadContext) return t - + @staticmethod def get_header(): return [ 'ThreadId', *MINIDUMP_EXCEPTION.get_header() ] - + def to_row(self): return [ @@ -48,7 +48,7 @@ def to_row(self): *self.ExceptionRecord.to_row() ] - + class ExceptionCode(enum.Enum): # Not a real exception code, it's just a placeholder to prevent the parser from raising an error EXCEPTION_UNKNOWN = 'EXCEPTION_UNKNOWN_CHECK_RAW' @@ -107,7 +107,7 @@ class ExceptionCode(enum.Enum): EXCEPTION_PRIV_INSTRUCTION = 0xC0000096 # The thread tried to execute an instruction whose operation is not allowed in the current machine mode. EXCEPTION_SINGLE_STEP = 0x80000004 # A trace trap or other single-instruction mechanism signaled that one instruction has been executed. EXCEPTION_STACK_OVERFLOW = 0xC00000FD # The thread used up its stack. - + #https://msdn.microsoft.com/en-us/library/windows/desktop/ms680367(v=vs.85).aspx class MINIDUMP_EXCEPTION: def __init__(self): @@ -119,7 +119,7 @@ def __init__(self): self.__unusedAlignment = None self.ExceptionInformation = [] self.ExceptionCode_raw = None - + @staticmethod def parse(buff): me = MINIDUMP_EXCEPTION() @@ -136,13 +136,13 @@ def parse(buff): me.__unusedAlignment = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) for _ in range(me.NumberParameters): me.ExceptionInformation.append(int.from_bytes(buff.read(8), byteorder = 'little', signed = False)) - + return me def __str__(self): t = '== MINIDUExceptionInformationMP_EXCEPTION ==\n' - t += "ExceptionCode : %s\n" % self.ExceptionCode - t += "ExceptionFlags : %s\n" % self.ExceptionFlags + t += "ExceptionCode : %s\n" % self.ExceptionCode + t += "ExceptionFlags : %s\n" % self.ExceptionFlags t += "ExceptionRecord : %s\n" % self.ExceptionRecord t += "ExceptionAddress : 0x%x\n" % self.ExceptionAddress t += "NumberParameters : %s\n" % self.NumberParameters @@ -159,7 +159,7 @@ def get_header(): 'ExceptionAddress', 'ExceptionInformation' ] - + def to_row(self): return [ @@ -174,11 +174,11 @@ def to_row(self): class ExceptionList: def __init__(self): self.exception_records = [] - + @staticmethod def parse(dir, buff): t = ExceptionList() - + buff.seek(dir.Location.Rva) chunk = io.BytesIO(buff.read(dir.Location.DataSize)) @@ -197,13 +197,13 @@ def parse(dir, buff): break t.exception_records.append(mes) - + return t @staticmethod async def aparse(dir, buff): t = ExceptionList() - + await buff.seek(dir.Location.Rva) chunk_data = await buff.read(dir.Location.DataSize) chunk = io.BytesIO(chunk_data) @@ -223,9 +223,9 @@ async def aparse(dir, buff): break t.exception_records.append(mes) - + return t - + def to_table(self): t = [] t.append(MINIDUMP_EXCEPTION_STREAM.get_header()) @@ -235,4 +235,3 @@ def to_table(self): def __str__(self): return '== ExceptionList ==\n' + construct_table(self.to_table()) - \ No newline at end of file diff --git a/minidump/streams/FunctionTableStream.py b/minidump/streams/FunctionTableStream.py index df79d36..a247091 100644 --- a/minidump/streams/FunctionTableStream.py +++ b/minidump/streams/FunctionTableStream.py @@ -11,7 +11,7 @@ def __init__(self): self.SizeOfFunctionEntry = None self.NumberOfDescriptors = None self.SizeOfAlignPad = None - + @staticmethod def parse(dir, buff): mfts = MINIDUMP_FUNCTION_TABLE_STREAM() @@ -21,5 +21,5 @@ def parse(dir, buff): mfts.SizeOfFunctionEntry = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) mfts.NumberOfDescriptors = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) mfts.SizeOfAlignPad = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) - + return mfts \ No newline at end of file diff --git a/minidump/streams/HandleDataStream.py b/minidump/streams/HandleDataStream.py index 6767dea..7899b26 100644 --- a/minidump/streams/HandleDataStream.py +++ b/minidump/streams/HandleDataStream.py @@ -5,7 +5,7 @@ # import io import enum -from minidump.common_structs import * +from minidump.common_structs import * # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680372(v=vs.85).aspx class MINIDUMP_HANDLE_DATA_STREAM: @@ -14,7 +14,7 @@ def __init__(self): self.SizeOfDescriptor = None self.NumberOfDescriptors = None self.Reserved = None - + @staticmethod def parse(buff): mhds = MINIDUMP_HANDLE_DATA_STREAM() @@ -22,9 +22,9 @@ def parse(buff): mhds.SizeOfDescriptor = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) mhds.NumberOfDescriptors = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) mhds.Reserved = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) - + return mhds - + # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680374(v=vs.85).aspx class MINIDUMP_HANDLE_DESCRIPTOR: size = 32 @@ -36,7 +36,7 @@ def __init__(self): self.GrantedAccess = None self.HandleCount = None self.PointerCount = None - + @staticmethod def parse(buff): mhd = MINIDUMP_HANDLE_DESCRIPTOR() @@ -47,11 +47,11 @@ def parse(buff): mhd.GrantedAccess = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) mhd.HandleCount = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) mhd.PointerCount = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) - + return mhd - + # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680373(v=vs.85).aspx -class MINIDUMP_HANDLE_DESCRIPTOR_2: +class MINIDUMP_HANDLE_DESCRIPTOR_2: def __init__(self): self.Handle = None self.TypeNameRva = None @@ -62,7 +62,7 @@ def __init__(self): self.PointerCount = None self.ObjectInfoRva = None self.Reserved0 = None - + @staticmethod def parse(buff): mhd = MINIDUMP_HANDLE_DESCRIPTOR_2() @@ -78,24 +78,24 @@ def parse(buff): return mhd # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680376(v=vs.85).aspx -class MINIDUMP_HANDLE_OBJECT_INFORMATION_TYPE(enum.Enum): +class MINIDUMP_HANDLE_OBJECT_INFORMATION_TYPE(enum.Enum): MiniHandleObjectInformationNone = 0 MiniThreadInformation1 = 1 MiniMutantInformation1 = 2 MiniMutantInformation2 = 3 MiniProcessInformation1 = 4 MiniProcessInformation2 = 5 - + class MINIDUMP_HANDLE_OBJECT_INFORMATION: def __init__(self): self.NextInfoRva = None self.InfoType = None self.SizeOfInfo = None - + #high-level, delete this when documentation becomes available! self.info_bytes = None - + @staticmethod def parse(buff): mhoi = MINIDUMP_HANDLE_OBJECT_INFORMATION() @@ -116,14 +116,14 @@ async def aparse(buff): mhoi.SizeOfInfo = int.from_bytes(t, byteorder = 'little', signed = False) mhoi.info_bytes = await buff.read(mhoi.SizeOfInfo) return mhoi - + class MinidumpHandleObjectInformation: def __init__(self): self.NextInfo = None self.InfoType = None self.SizeOfInfo = None self.info_bytes = None - + @staticmethod def parse(mhoi): t = MinidumpHandleObjectInformation() @@ -131,12 +131,12 @@ def parse(mhoi): t.SizeOfInfo = mhoi.SizeOfInfo t.info_bytes = mhoi.info_bytes return t - + def __str__(self): return self.info_bytes.hex() - - - + + + class MinidumpHandleDescriptor: def __init__(self): self.Handle = None @@ -147,7 +147,7 @@ def __init__(self): self.HandleCount = None self.PointerCount = None self.ObjectInfos = [] - + @staticmethod def parse(t, buff): mhd = MinidumpHandleDescriptor() @@ -181,7 +181,7 @@ async def aparse(t, buff): if t.ObjectInfoRva is not None and t.ObjectInfoRva != 0: await MinidumpHandleDescriptor.awalk_objectinfo(mhd, t.ObjectInfoRva, buff) return mhd - + @staticmethod def walk_objectinfo(mhd, start, buff): while start is not None and start != 0: @@ -199,8 +199,8 @@ async def awalk_objectinfo(mhd, start, buff): t = MinidumpHandleObjectInformation.parse(mhoi) mhd.ObjectInfos.append(t) start = t.NextInfo - - + + def __str__(self): t = '== MinidumpHandleDescriptor == \n' t += 'Handle 0x%08x ' % self.Handle @@ -213,12 +213,12 @@ def __str__(self): for oi in self.ObjectInfos: t += str(oi) return t - + class MinidumpHandleDataStream: def __init__(self): self.header = None self.handles = [] - + @staticmethod def parse(dir, buff): t = MinidumpHandleDataStream() @@ -251,7 +251,7 @@ async def aparse(dir, buff): r = await MinidumpHandleDescriptor.aparse(mhd, buff) t.handles.append(r) return t - + def __str__(self): t = '== MinidumpHandleDataStream ==\n' for handle in self.handles: diff --git a/minidump/streams/HandleOperationListStream.py b/minidump/streams/HandleOperationListStream.py index 8e01de8..47a30fb 100644 --- a/minidump/streams/HandleOperationListStream.py +++ b/minidump/streams/HandleOperationListStream.py @@ -9,7 +9,7 @@ def __init__(self): self.SizeOfEntry = None self.NumberOfEntries = None self.Reserved = None - + @staticmethod def parse(dir, buff): mhds = MINIDUMP_HANDLE_OPERATION_LIST() @@ -17,6 +17,5 @@ def parse(dir, buff): mhds.SizeOfEntry = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) mhds.NumberOfEntries = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) mhds.Reserved = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) - + return mhds - \ No newline at end of file diff --git a/minidump/streams/LastReservedStream.py b/minidump/streams/LastReservedStream.py index 77dd233..55ffed9 100644 --- a/minidump/streams/LastReservedStream.py +++ b/minidump/streams/LastReservedStream.py @@ -8,7 +8,7 @@ def __init__(self): self.Type = None self.BufferSize = None self.Buffer = None - + @staticmethod def parse(buff): mus = MINIDUMP_USER_STREAM() @@ -16,5 +16,5 @@ def parse(buff): mus.BufferSize = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) #this type is PVOID, not sure on the size mus.Buffer = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) - + return mus \ No newline at end of file diff --git a/minidump/streams/Memory64ListStream.py b/minidump/streams/Memory64ListStream.py index ba7547b..57d4466 100644 --- a/minidump/streams/Memory64ListStream.py +++ b/minidump/streams/Memory64ListStream.py @@ -4,7 +4,7 @@ # Tamas Jos (@skelsec) # import io -from minidump.common_structs import * +from minidump.common_structs import * # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680387(v=vs.85).aspx class MINIDUMP_MEMORY64_LIST: @@ -22,7 +22,7 @@ def to_bytes(self): for memrange in self.MemoryRanges: t += memrange.to_bytes() return t - + @staticmethod def parse(buff): mml = MINIDUMP_MEMORY64_LIST() @@ -32,14 +32,14 @@ def parse(buff): mml.BaseRva = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) for _ in range(mml.NumberOfMemoryRanges): mml.MemoryRanges.append(MINIDUMP_MEMORY_DESCRIPTOR64.parse(buff)) - + #sometimes buggy minidumps have a wrong number of memory ranges, so we need to check if we reached the end of the buffer curpos = buff.tell() if curpos == buffsize: break - + return mml - + def __str__(self): t = '== MINIDUMP_MEMORY64_LIST ==\n' t += 'NumberOfMemoryRanges: %s\n' % self.NumberOfMemoryRanges @@ -62,14 +62,14 @@ def to_bytes(self): t = self.StartOfMemoryRange.to_bytes(8, byteorder = 'little', signed = False) t += self.DataSize.to_bytes(8, byteorder = 'little', signed = False) return t - + @staticmethod def parse(buff): md = MINIDUMP_MEMORY_DESCRIPTOR64() md.StartOfMemoryRange = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) md.DataSize = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) return md - + def __str__(self): t = 'Start: %s' % hex(self.StartOfMemoryRange) t += 'Size: %s' % self.DataSize @@ -78,7 +78,7 @@ def __str__(self): class MinidumpMemory64List: def __init__(self): self.memory_segments = [] - + @staticmethod def parse(dir, buff): t = MinidumpMemory64List() @@ -104,14 +104,13 @@ async def aparse(dir, buff): mml.memory_segments.append(ms) rva += mod.DataSize return mml - + def to_table(self): t = [] t.append(MinidumpMemorySegment.get_header()) for mod in self.memory_segments: t.append(mod.to_row()) return t - + def __str__(self): return '== MinidumpMemory64List ==\n' + construct_table(self.to_table()) - \ No newline at end of file diff --git a/minidump/streams/MemoryInfoListStream.py b/minidump/streams/MemoryInfoListStream.py index de5fe07..557620a 100644 --- a/minidump/streams/MemoryInfoListStream.py +++ b/minidump/streams/MemoryInfoListStream.py @@ -5,7 +5,7 @@ # import io import enum -from minidump.common_structs import * +from minidump.common_structs import * class AllocationProtect(enum.Enum): NONE = 0 @@ -51,7 +51,7 @@ class AllocationProtect(enum.Enum): #The PAGE_WRITECOMBINE flag cannot be specified with the PAGE_NOACCESS, PAGE_GUARD, and PAGE_NOCACHE flags. #The PAGE_WRITECOMBINE flag can be used only when allocating private memory with the VirtualAlloc, VirtualAllocEx, or VirtualAllocExNuma functions. To enable write-combined memory access for shared memory, specify the SEC_WRITECOMBINE flag when calling the CreateFileMapping function. #Windows Server 2003 and Windows XP: This flag is not supported until Windows Server 2003 with SP1. - + class MemoryType(enum.Enum): MEM_IMAGE = 0x1000000 #Indicates that the memory pages within the region are mapped into the view of an image section. MEM_MAPPED = 0x40000 #Indicates that the memory pages within the region are mapped into the view of a section. @@ -78,17 +78,17 @@ def to_bytes(self): t += self.SizeOfEntry.to_bytes(4, byteorder = 'little', signed = False) t += len(self.entries).to_bytes(8, byteorder = 'little', signed = False) return t - + @staticmethod def parse(buff): mhds = MINIDUMP_MEMORY_INFO_LIST() mhds.SizeOfHeader = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) mhds.SizeOfEntry = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) mhds.NumberOfEntries = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) - + return mhds - -# https://msdn.microsoft.com/en-us/library/windows/desktop/ms680386(v=vs.85).aspx + +# https://msdn.microsoft.com/en-us/library/windows/desktop/ms680386(v=vs.85).aspx class MINIDUMP_MEMORY_INFO: def __init__(self): self.BaseAddress = None @@ -121,7 +121,7 @@ def to_bytes(self): t += self.Type.value.to_bytes(4, byteorder = 'little', signed = False) t += self.__alignment2.to_bytes(4, byteorder = 'little', signed = False) return t - + @staticmethod def parse(buff): mmi = MINIDUMP_MEMORY_INFO() @@ -143,9 +143,9 @@ def parse(buff): except: pass mmi.__alignment2 = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) - + return mmi - + class MinidumpMemoryInfo: def __init__(self): self.BaseAddress = None @@ -155,7 +155,7 @@ def __init__(self): self.State = None self.Protect = None self.Type = None - + @staticmethod def parse(t, buff): mmi = MinidumpMemoryInfo() @@ -167,7 +167,7 @@ def parse(t, buff): mmi.Protect = t.Protect mmi.Type = t.Type return mmi - + @staticmethod def get_header(): t = [ @@ -192,13 +192,13 @@ def to_row(self): self.Type.name if self.Type else 'N/A', ] return t - - + + class MinidumpMemoryInfoList: def __init__(self): self.header = None self.infos = [] - + @staticmethod def parse(dir, buff): t = MinidumpMemoryInfoList() @@ -209,7 +209,7 @@ def parse(dir, buff): for _ in range(t.header.NumberOfEntries): mi = MINIDUMP_MEMORY_INFO.parse(chunk) t.infos.append(MinidumpMemoryInfo.parse(mi, buff)) - + return t @staticmethod @@ -222,15 +222,15 @@ async def aparse(dir, buff): for _ in range(t.header.NumberOfEntries): mi = MINIDUMP_MEMORY_INFO.parse(chunk) t.infos.append(MinidumpMemoryInfo.parse(mi, None)) - + return t - + def to_table(self): t = [] t.append(MinidumpMemoryInfo.get_header()) for info in self.infos: t.append(info.to_row()) return t - + def __str__(self): return '== MinidumpMemoryInfoList ==\n' + construct_table(self.to_table()) \ No newline at end of file diff --git a/minidump/streams/MemoryListStream.py b/minidump/streams/MemoryListStream.py index 734a256..77c6672 100644 --- a/minidump/streams/MemoryListStream.py +++ b/minidump/streams/MemoryListStream.py @@ -4,7 +4,7 @@ # Tamas Jos (@skelsec) # import io -from minidump.common_structs import * +from minidump.common_structs import * # https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory_list class MINIDUMP_MEMORY_LIST: @@ -17,16 +17,16 @@ def to_bytes(self): for memrange in self.MemoryRanges: t += memrange.to_bytes() return t - + @staticmethod def parse(buff): mml = MINIDUMP_MEMORY_LIST() mml.NumberOfMemoryRanges = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) for _ in range(mml.NumberOfMemoryRanges): mml.MemoryRanges.append(MINIDUMP_MEMORY_DESCRIPTOR.parse(buff)) - + return mml - + def __str__(self): t = '== MINIDUMP_MEMORY_LIST ==\n' t += 'NumberOfMemoryRanges: %s\n' % self.NumberOfMemoryRanges @@ -34,12 +34,12 @@ def __str__(self): t+= str(range) return t -# https://msdn.microsoft.com/en-us/library/windows/desktop/ms680384(v=vs.85).aspx +# https://msdn.microsoft.com/en-us/library/windows/desktop/ms680384(v=vs.85).aspx class MINIDUMP_MEMORY_DESCRIPTOR: def __init__(self): self.StartOfMemoryRange = None self.MemoryLocation = None - + #we do not use MemoryLocation but immediately store its fields in this object for easy access self.DataSize = None self.Rva = None @@ -48,12 +48,12 @@ def to_bytes(self): t = self.StartOfMemoryRange.to_bytes(4, byteorder = 'little', signed = False) t += self.MemoryLocation.to_bytes() return t - + @staticmethod def parse(buff): md = MINIDUMP_MEMORY_DESCRIPTOR() md.StartOfMemoryRange = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) - + #TODO: figure out what the documentation says, the person writign it was probably high... # The deal is: RVA sizes differ on where in the file the memory data is stored. but it's not possible to know it up front if we need to read 32 or 64 bytes... # @@ -61,22 +61,22 @@ def parse(buff): # md.MemoryLocation = MINIDUMP_LOCATION_DESCRIPTOR.parse(buff) #else: # md.MemoryLocation = MINIDUMP_LOCATION_DESCRIPTOR64.parse(buff) - + md.MemoryLocation = MINIDUMP_LOCATION_DESCRIPTOR.parse(buff) md.DataSize = md.MemoryLocation.DataSize md.Rva = md.MemoryLocation.Rva return md - + def __str__(self): t = 'Start: %s' % hex(self.StartOfMemoryRange) t += 'Size: %s' % self.DataSize t += 'Rva: %s' % self.Rva return t - + class MinidumpMemoryList: def __init__(self): self.memory_segments = [] - + @staticmethod def parse(dir, buff): t = MinidumpMemoryList() @@ -86,7 +86,7 @@ def parse(dir, buff): for mod in mtl.MemoryRanges: t.memory_segments.append(MinidumpMemorySegment.parse_mini(mod, buff)) return t - + @staticmethod async def aparse(dir, buff): t = MinidumpMemoryList() @@ -97,7 +97,7 @@ async def aparse(dir, buff): for mod in mtl.MemoryRanges: t.memory_segments.append(MinidumpMemorySegment.parse_mini(mod, buff)) return t - + def __str__(self): t = '== MinidumpMemoryList ==\n' for mod in self.memory_segments: diff --git a/minidump/streams/MiscInfoStream.py b/minidump/streams/MiscInfoStream.py index 2654581..7144aec 100644 --- a/minidump/streams/MiscInfoStream.py +++ b/minidump/streams/MiscInfoStream.py @@ -6,7 +6,7 @@ import io import enum -#https://msdn.microsoft.com/en-us/library/windows/desktop/ms680388(v=vs.85).aspx +#https://msdn.microsoft.com/en-us/library/windows/desktop/ms680388(v=vs.85).aspx class MinidumpMiscInfo2Flags1(enum.IntFlag): MINIDUMP_MISC1_PROCESS_ID = 0x00000001 #ProcessId is used. MINIDUMP_MISC1_PROCESS_TIMES = 0x00000002 #ProcessCreateTime, ProcessKernelTime, and ProcessUserTime are used. @@ -27,7 +27,7 @@ def __init__(self): self.ProcessCreateTime = None self.ProcessUserTime = None self.ProcessKernelTime = None - + @staticmethod def parse(buff): mmi = MINIDUMP_MISC_INFO() @@ -43,10 +43,10 @@ def parse(buff): mmi.ProcessKernelTime = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) else: buff.read(12) - + return mmi -#https://msdn.microsoft.com/en-us/library/windows/desktop/ms680388(v=vs.85).aspx +#https://msdn.microsoft.com/en-us/library/windows/desktop/ms680388(v=vs.85).aspx class MINIDUMP_MISC_INFO_2: size = 44 def __init__(self): @@ -61,7 +61,7 @@ def __init__(self): self.ProcessorMhzLimit = None self.ProcessorMaxIdleState = None self.ProcessorCurrentIdleState = None - + @staticmethod def parse(buff): mmi = MINIDUMP_MISC_INFO_2() @@ -85,9 +85,9 @@ def parse(buff): mmi.ProcessorCurrentIdleState = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) else: buff.read(20) - + return mmi - + class MinidumpMiscInfo: def __init__(self): self.ProcessId = None @@ -99,7 +99,7 @@ def __init__(self): self.ProcessorMhzLimit = None self.ProcessorMaxIdleState = None self.ProcessorCurrentIdleState = None - + @staticmethod def parse(dir, buff): t = MinidumpMiscInfo() @@ -148,7 +148,7 @@ async def aparse(dir, buff): t.ProcessorMaxIdleState = misc.ProcessorMaxIdleState t.ProcessorCurrentIdleState = misc.ProcessorCurrentIdleState return t - + def __str__(self): t = '== MinidumpMiscInfo ==\n' t += 'ProcessId %s\n' % self.ProcessId diff --git a/minidump/streams/ModuleListStream.py b/minidump/streams/ModuleListStream.py index d251a02..b021d8a 100644 --- a/minidump/streams/ModuleListStream.py +++ b/minidump/streams/ModuleListStream.py @@ -4,7 +4,7 @@ # Tamas Jos (@skelsec) # import io -from minidump.common_structs import * +from minidump.common_structs import * class MinidumpModule: def __init__(self): @@ -12,11 +12,11 @@ def __init__(self): self.baseaddress = None self.size = None self.endaddress = None - + self.versioninfo = None self.checksum = None self.timestamp = None - + @staticmethod def parse(mod, buff): """ @@ -48,10 +48,10 @@ async def aparse(mod, buff): mm.versioninfo = mod.VersionInfo mm.endaddress = mm.baseaddress + mm.size return mm - + def inrange(self, memory_loc): return self.baseaddress <= memory_loc < self.endaddress - + @staticmethod def get_header(): return [ @@ -61,7 +61,7 @@ def get_header(): 'Endaddress', 'Timestamp', ] - + def to_row(self): return [ str(self.name), @@ -70,11 +70,11 @@ def to_row(self): '0x%08x' % self.endaddress, '0x%08x' % self.timestamp, ] - - + + def __str__(self): return 'Module name: %s BaseAddress: 0x%08x Size: 0x%x Endaddress: 0x%08x' % (self.name, self.baseaddress, self.size, self.endaddress) - + # https://msdn.microsoft.com/en-us/library/windows/desktop/ms646997(v=vs.85).aspx class VS_FIXEDFILEINFO: def __init__(self): @@ -110,7 +110,7 @@ def to_bytes(self): t += self.dwFileDateMS.to_bytes(4, byteorder = 'little', signed = False) t += self.dwFileDateLS.to_bytes(4, byteorder = 'little', signed = False) return t - + @staticmethod def from_bytes(data): return VS_FIXEDFILEINFO.parse(io.BytesIO(data)) @@ -171,7 +171,7 @@ def to_bytes(self): t += self.Reserved0.to_bytes(8, byteorder = 'little', signed = False) t += self.Reserved1.to_bytes(8, byteorder = 'little', signed = False) return t - + @staticmethod def parse(buff): mm = MINIDUMP_MODULE() @@ -192,7 +192,7 @@ def __str__(self): for k in self.__dict__: t += '%s : %s\r\n' % (k, str(self.__dict__[k])) return t - + # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680391(v=vs.85).aspx class MINIDUMP_MODULE_LIST: def __init__(self): @@ -207,20 +207,20 @@ def to_bytes(self): for module in self.Modules: t += module.to_bytes() return t - + @staticmethod def parse(buff): mml = MINIDUMP_MODULE_LIST() mml.NumberOfModules = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) for _ in range(mml.NumberOfModules): mml.Modules.append(MINIDUMP_MODULE.parse(buff)) - + return mml - + class MinidumpModuleList: def __init__(self): self.modules = [] - + @staticmethod def parse(dir, buff): t = MinidumpModuleList() @@ -230,7 +230,7 @@ def parse(dir, buff): for mod in mtl.Modules: t.modules.append(MinidumpModule.parse(mod, buff)) return t - + @staticmethod async def aparse(dir, buff): t = MinidumpModuleList() @@ -242,15 +242,14 @@ async def aparse(dir, buff): x = await MinidumpModule.aparse(mod, buff) t.modules.append(x) return t - + def to_table(self): t = [] t.append(MinidumpModule.get_header()) for mod in self.modules: t.append(mod.to_row()) return t - + def __str__(self): t = '== ModuleList ==\n' + construct_table(self.to_table()) return t - \ No newline at end of file diff --git a/minidump/streams/ThreadExListStream.py b/minidump/streams/ThreadExListStream.py index ba9f854..313723c 100644 --- a/minidump/streams/ThreadExListStream.py +++ b/minidump/streams/ThreadExListStream.py @@ -5,7 +5,7 @@ # import io -from minidump.common_structs import * +from minidump.common_structs import * from minidump.streams.MemoryListStream import MINIDUMP_MEMORY_DESCRIPTOR # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680399(v=vs.85).aspx @@ -13,16 +13,16 @@ class MINIDUMP_THREAD_EX_LIST: def __init__(self): self.NumberOfThreads = None self.Threads = [] - + @staticmethod def parse(buff): mtel = MINIDUMP_THREAD_EX_LIST() mtel.NumberOfThreads = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) for _ in range(mtel.NumberOfThreads): mtel.Threads.append(MINIDUMP_THREAD_EX.parse(buff)) - + return mtel - + # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680400(v=vs.85).aspx class MINIDUMP_THREAD_EX: def __init__(self): @@ -34,7 +34,7 @@ def __init__(self): self.Stack = None self.ThreadContext = None self.BackingStore = None - + @staticmethod def parse(buff): mte = MINIDUMP_THREAD_EX() @@ -47,7 +47,7 @@ def parse(buff): mte.ThreadContext = MINIDUMP_LOCATION_DESCRIPTOR.parse(buff) mte.BackingStore = MINIDUMP_MEMORY_DESCRIPTOR.parse(buff) return mte - + @staticmethod def get_header(): return [ @@ -59,7 +59,7 @@ def get_header(): #'Stack', #'ThreadContext', ] - + def to_row(self): return [ hex(self.ThreadId), @@ -70,12 +70,12 @@ def to_row(self): #self.Stack, #self.ThreadContext, ] - - + + class MinidumpThreadExList: def __init__(self): self.threads = [] - + @staticmethod def parse(dir, buff): t = MinidumpThreadExList() @@ -94,14 +94,13 @@ async def aparse(dir, buff): mtl = MINIDUMP_THREAD_EX_LIST.parse(chunk) t.threads = mtl.Threads return t - + def to_table(self): t = [] t.append(MINIDUMP_THREAD_EX.get_header()) for thread in self.threads: t.append(thread.to_row()) return t - + def __str__(self): - return '== ThreadExList ==\n' + construct_table(self.to_table()) - \ No newline at end of file + return '== ThreadExList ==\n' + construct_table(self.to_table()) diff --git a/minidump/streams/ThreadInfoListStream.py b/minidump/streams/ThreadInfoListStream.py index 069f689..5c0d612 100644 --- a/minidump/streams/ThreadInfoListStream.py +++ b/minidump/streams/ThreadInfoListStream.py @@ -5,7 +5,7 @@ # import io import enum -from minidump.common_structs import * +from minidump.common_structs import * # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680510(v=vs.85).aspx class DumpFlags(enum.Enum): @@ -22,7 +22,7 @@ def __init__(self): self.SizeOfHeader = None self.SizeOfEntry = None self.NumberOfEntries = None - + def to_bytes(self): t = self.SizeOfHeader.value.to_bytes(4, byteorder = 'little', signed = False) t += self.SizeOfEntry.to_bytes(4, byteorder = 'little', signed = False) @@ -35,10 +35,10 @@ def parse(buff): mtil.SizeOfHeader = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) mtil.SizeOfEntry = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) mtil.NumberOfEntries = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) - + return mtil - - + + # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680510(v=vs.85).aspx class MINIDUMP_THREAD_INFO: def __init__(self): @@ -68,7 +68,7 @@ def to_bytes(self): t += self.StartAddress.to_bytes(8, byteorder = 'little', signed = False) t += self.Affinity.to_bytes(8, byteorder = 'little', signed = False) return t - + @staticmethod def parse(buff): mti = MINIDUMP_THREAD_INFO() @@ -86,7 +86,7 @@ def parse(buff): mti.StartAddress = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) mti.Affinity = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) return mti - + class MinidumpThreadInfo: def __init__(self): self.ThreadId = None @@ -99,7 +99,7 @@ def __init__(self): self.UserTime = None self.StartAddress = None self.Affinity = None - + @staticmethod def parse(t, buff): mti = MinidumpThreadInfo() @@ -114,7 +114,7 @@ def parse(t, buff): mti.StartAddress = t.StartAddress mti.Affinity = t.Affinity return mti - + @staticmethod def get_header(): return [ @@ -129,7 +129,7 @@ def get_header(): 'StartAddress', 'Affinity', ] - + def to_row(self): return [ hex(self.ThreadId), @@ -143,16 +143,16 @@ def to_row(self): hex(self.StartAddress), str(self.Affinity), ] - + def __str__(self): return 'ThreadId: %x DumpFlags: %s DumpError: %s ExitStatus: %x CreateTime: %s ExitTime: %s KernelTime: %s UserTime: %s StartAddress: %x Affinity: %d' % \ (self.ThreadId, self.DumpFlags, self.DumpError, self.ExitStatus, self.CreateTime, self.ExitTime, self.KernelTime, self.UserTime, self.StartAddress, self.Affinity) - + class MinidumpThreadInfoList: def __init__(self): self.header = None self.infos = [] - + @staticmethod def parse(dir, buff): t = MinidumpThreadInfoList() @@ -163,7 +163,7 @@ def parse(dir, buff): for _ in range(t.header.NumberOfEntries): mi = MINIDUMP_THREAD_INFO.parse(chunk) t.infos.append(MinidumpThreadInfo.parse(mi, buff)) - + return t @staticmethod @@ -176,16 +176,15 @@ async def aparse(dir, buff): for _ in range(t.header.NumberOfEntries): mi = MINIDUMP_THREAD_INFO.parse(chunk) t.infos.append(MinidumpThreadInfo.parse(mi, None)) - + return t - + def to_table(self): t = [] t.append(MinidumpThreadInfo.get_header()) for info in self.infos: t.append(info.to_row()) return t - + def __str__(self): - return '== ThreadInfoList ==\n' + construct_table(self.to_table()) - \ No newline at end of file + return '== ThreadInfoList ==\n' + construct_table(self.to_table()) diff --git a/minidump/streams/ThreadListStream.py b/minidump/streams/ThreadListStream.py index 8048507..135ead5 100644 --- a/minidump/streams/ThreadListStream.py +++ b/minidump/streams/ThreadListStream.py @@ -4,7 +4,7 @@ # Tamas Jos (@skelsec) # import io -from minidump.common_structs import * +from minidump.common_structs import * from minidump.streams.MemoryListStream import MINIDUMP_MEMORY_DESCRIPTOR # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680515(v=vs.85).aspx @@ -18,7 +18,7 @@ def to_bytes(self): for th in self.Threads: t += th.to_bytes() return t - + @staticmethod def parse(buff): mtl = MINIDUMP_THREAD_LIST() @@ -26,8 +26,8 @@ def parse(buff): for _ in range(mtl.NumberOfThreads): mtl.Threads.append(MINIDUMP_THREAD.parse(buff)) return mtl - -# https://msdn.microsoft.com/en-us/library/windows/desktop/ms680517(v=vs.85).aspx + +# https://msdn.microsoft.com/en-us/library/windows/desktop/ms680517(v=vs.85).aspx class MINIDUMP_THREAD: def __init__(self): self.ThreadId = None @@ -47,7 +47,7 @@ def to_bytes(self): t += self.Stack.to_bytes() t += self.ThreadContext.to_bytes() return t - + @staticmethod def parse(buff): mt = MINIDUMP_THREAD() @@ -58,9 +58,9 @@ def parse(buff): mt.Teb = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) mt.Stack = MINIDUMP_MEMORY_DESCRIPTOR.parse(buff) mt.ThreadContext = MINIDUMP_LOCATION_DESCRIPTOR.parse(buff) - + return mt - + @staticmethod def get_header(): return [ @@ -72,7 +72,7 @@ def get_header(): #'Stack', #'ThreadContext', ] - + def to_row(self): return [ hex(self.ThreadId), @@ -83,11 +83,11 @@ def to_row(self): #self.Stack, #self.ThreadContext, ] - + class MinidumpThreadList: def __init__(self): self.threads = [] - + @staticmethod def parse(dir, buff): t = MinidumpThreadList() @@ -106,13 +106,13 @@ async def aparse(dir, buff): mtl = MINIDUMP_THREAD_LIST.parse(chunk) t.threads = mtl.Threads return t - + def to_table(self): t = [] t.append(MINIDUMP_THREAD.get_header()) for thread in self.threads: t.append(thread.to_row()) return t - + def __str__(self): return 'ThreadList\n' + construct_table(self.to_table()) \ No newline at end of file diff --git a/minidump/streams/UnloadedModuleListStream.py b/minidump/streams/UnloadedModuleListStream.py index 2b1d143..28fdaa4 100644 --- a/minidump/streams/UnloadedModuleListStream.py +++ b/minidump/streams/UnloadedModuleListStream.py @@ -5,7 +5,7 @@ # import io -from minidump.common_structs import * +from minidump.common_structs import * # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680521(v=vs.85).aspx class MINIDUMP_UNLOADED_MODULE_LIST: @@ -19,7 +19,7 @@ def to_bytes(self): t += self.SizeOfEntry.to_bytes(4, byteorder = 'little', signed = False) t += self.NumberOfEntries.to_bytes(4, byteorder = 'little', signed = False) return t - + @staticmethod def parse(buff): muml = MINIDUMP_UNLOADED_MODULE_LIST() @@ -27,7 +27,7 @@ def parse(buff): muml.SizeOfEntry = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) muml.NumberOfEntries = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) return muml - + # https://msdn.microsoft.com/en-us/library/windows/desktop/ms680523(v=vs.85).aspx class MINIDUMP_UNLOADED_MODULE: def __init__(self): @@ -44,7 +44,7 @@ def to_bytes(self): t += self.TimeDateStamp.to_bytes(4, byteorder = 'little', signed = False) t += self.ModuleNameRva.to_bytes(4, byteorder = 'little', signed = False) return t - + @staticmethod def parse(buff): mum = MINIDUMP_UNLOADED_MODULE() @@ -62,10 +62,10 @@ def __init__(self): self.size = None self.endaddress = None self.memorysegments = [] #list of memory segments the module takes place in - + self.checksum = None self.timestamp = None - + @staticmethod def parse(mod, buff): """ @@ -95,14 +95,14 @@ async def aparse(mod, buff): mm.name = await MINIDUMP_STRING.aget_from_rva(mod.ModuleNameRva, buff) mm.endaddress = mm.baseaddress + mm.size return mm - + def assign_memory_regions(self, segments): for segment in segments: if self.baseaddress <= segment.start_virtual_address < self.endaddress: self.memorysegments.append(segment) - + def __str__(self): - return 'Unloaded Module name: %s Size: %s BaseAddress: %s' % (self.name, hex(self.size), hex(self.baseaddress)) + return 'Unloaded Module name: %s Size: %s BaseAddress: %s' % (self.name, hex(self.size), hex(self.baseaddress)) @staticmethod def get_header(): @@ -112,7 +112,7 @@ def get_header(): 'Size', 'Endaddress', ] - + def to_row(self): return [ str(self.name), @@ -120,12 +120,12 @@ def to_row(self): hex(self.size), '0x%08x' % self.endaddress, ] - - + + class MinidumpUnloadedModuleList: def __init__(self): self.modules = [] - + @staticmethod def parse(dir, buff): t = MinidumpUnloadedModuleList() @@ -135,7 +135,7 @@ def parse(dir, buff): for _ in range(muml.NumberOfEntries): mod = MINIDUMP_UNLOADED_MODULE.parse(chunk) t.modules.append(MinidumpUnloadedModule.parse(mod, buff)) - + return t @staticmethod @@ -149,16 +149,16 @@ async def aparse(dir, buff): mod = MINIDUMP_UNLOADED_MODULE.parse(chunk) dr = await MinidumpUnloadedModule.aparse(mod, buff) t.modules.append(dr) - + return t - + def to_table(self): t = [] t.append(MinidumpUnloadedModule.get_header()) for mod in self.modules: t.append(mod.to_row()) return t - + def __str__(self): t = '== UnloadedModuleList ==\n' + construct_table(self.to_table()) return t \ No newline at end of file diff --git a/minidump/utils/createminidump.py b/minidump/utils/createminidump.py index 940e8df..ef29e09 100644 --- a/minidump/utils/createminidump.py +++ b/minidump/utils/createminidump.py @@ -17,7 +17,7 @@ # https://stackoverflow.com/questions/1405913/how-do-i-determine-if-my-python-shell-is-executing-in-32bit-or-64bit-mode-on-os IS_PYTHON_64 = False if (8 * struct.calcsize("P")) == 32 else True -class MINIDUMP_TYPE(enum.IntFlag): +class MINIDUMP_TYPE(enum.IntFlag): MiniDumpNormal = 0x00000000 MiniDumpWithDataSegs = 0x00000001 MiniDumpWithFullMemory = 0x00000002 @@ -41,7 +41,7 @@ class MINIDUMP_TYPE(enum.IntFlag): MiniDumpWithModuleHeaders = 0x00080000 MiniDumpFilterTriage = 0x00100000 MiniDumpValidTypeFlags = 0x001fffff - + class WindowsBuild(enum.Enum): WIN_XP = 2600 WIN_2K3 = 3790 @@ -53,7 +53,7 @@ class WindowsBuild(enum.Enum): WIN_10_1511 = 10586 WIN_10_1607 = 14393 WIN_10_1707 = 15063 - + class WindowsMinBuild(enum.Enum): WIN_XP = 2500 WIN_2K3 = 3000 @@ -62,9 +62,9 @@ class WindowsMinBuild(enum.Enum): WIN_8 = 8000 WIN_BLUE = 9400 WIN_10 = 9800 - + #utter microsoft bullshit commencing.. -def getWindowsBuild(): +def getWindowsBuild(): class OSVersionInfo(ctypes.Structure): _fields_ = [ ("dwOSVersionInfoSize" , ctypes.c_int), @@ -76,9 +76,9 @@ class OSVersionInfo(ctypes.Structure): GetVersionEx = getattr( ctypes.windll.kernel32 , "GetVersionExA") version = OSVersionInfo() version.dwOSVersionInfoSize = ctypes.sizeof(OSVersionInfo) - GetVersionEx( ctypes.byref(version) ) + GetVersionEx( ctypes.byref(version) ) return version.dwBuildNumber - + DELETE = 0x00010000 READ_CONTROL = 0x00020000 WRITE_DAC = 0x00040000 @@ -93,7 +93,7 @@ class OSVersionInfo(ctypes.Structure): PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF else: PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF - + FILE_SHARE_READ = 1 FILE_SHARE_WRITE = 2 FILE_SHARE_DELETE = 4 @@ -133,7 +133,7 @@ class SECURITY_ATTRIBUTES(ctypes.Structure): ('p_security_descriptor', ctypes.wintypes.LPVOID), ('inherit_handle', ctypes.wintypes.BOOLEAN), ) -LPSECURITY_ATTRIBUTES = ctypes.POINTER(SECURITY_ATTRIBUTES) +LPSECURITY_ATTRIBUTES = ctypes.POINTER(SECURITY_ATTRIBUTES) """ Psapi = windll.psapi GetProcessImageFileName = Psapi.GetProcessImageFileNameA @@ -165,7 +165,7 @@ class SECURITY_ATTRIBUTES(ctypes.Structure): GetCurrentProcess.restype = HANDLE # https://msdn.microsoft.com/en-us/library/ms684139.aspx -IsWow64Process = ctypes.windll.kernel32.IsWow64Process +IsWow64Process = ctypes.windll.kernel32.IsWow64Process IsWow64Process.argtypes = (HANDLE, PBOOL) IsWow64Process.restype = BOOL @@ -190,14 +190,14 @@ def is64bitProc(process_handle): logging.warning('Failed to get process version info!') WinError(get_last_error()) return not bool(is64.value) - + # https://waitfordebug.wordpress.com/2012/01/27/pid-enumeration-on-windows-with-pure-python-ctypes/ def enum_pids(): - + max_array = c_ulong * 4096 # define long array to capture all the processes pProcessIds = max_array() # array to store the list of processes pBytesReturned = c_ulong() # the number of bytes returned in the array - #EnumProcess + #EnumProcess res = EnumProcesses( ctypes.byref(pProcessIds), ctypes.sizeof(pProcessIds), @@ -206,22 +206,22 @@ def enum_pids(): if res == 0: logging.error(WinError(get_last_error())) return [] - + # get the number of returned processes nReturned = int(pBytesReturned.value/ctypes.sizeof(c_ulong())) return [i for i in pProcessIds[:nReturned]] - + #https://msdn.microsoft.com/en-us/library/windows/desktop/ms683217(v=vs.85).aspx def enum_process_names(): pid_to_name = {} - + for pid in enum_pids(): pid_to_name[pid] = 'Not found' process_handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, False, pid) if process_handle is None: logging.debug('[Enum Processes]Failed to open process PID: %d Reason: %s ' % (pid, WinError(get_last_error()))) continue - + image_name = (ctypes.c_char*MAX_PATH)() max_path = DWORD(4096) #res = GetProcessImageFileName(process_handle, image_name, MAX_PATH) @@ -229,7 +229,7 @@ def enum_process_names(): if res == 0: logging.debug('[Enum Proceses]Failed GetProcessImageFileName on PID: %d Reason: %s ' % (pid, WinError(get_last_error()))) continue - + pid_to_name[pid] = image_name.value.decode() return pid_to_name @@ -239,7 +239,7 @@ def create_dump(pid, output_filename, mindumptype, with_debug = False): assigned = enable_debug_privilege() msg = ['failure', 'success'][assigned] logging.debug('SeDebugPrivilege assignment %s' % msg) - + logging.debug('Opening process PID: %d' % pid) process_handle = OpenProcess(PROCESS_ALL_ACCESS, False, pid) if process_handle is None: @@ -250,7 +250,7 @@ def create_dump(pid, output_filename, mindumptype, with_debug = False): is64 = is64bitProc(process_handle) if is64 != IS_PYTHON_64: logging.warning('process architecture mismatch! This could case error! Python arch: %s Target process arch: %s' % ('x86' if not IS_PYTHON_64 else 'x64', 'x86' if not is64 else 'x64')) - + logging.debug('Creating file handle for output file') file_handle = CreateFile(output_filename, FILE_GENERIC_READ | FILE_GENERIC_WRITE, 0, None, FILE_CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, None) if file_handle == -1: @@ -265,14 +265,14 @@ def create_dump(pid, output_filename, mindumptype, with_debug = False): logging.info('Dump file created succsessfully') CloseHandle(file_handle) CloseHandle(process_handle) - + def main(): import argparse parser = argparse.ArgumentParser(description='Tool to create process dumps using windows API') parser.add_argument('-d', '--with-debug', action='store_true', help='enable SeDebugPrivilege, use this if target process is not in the same user context as your script') parser.add_argument('-v', '--verbose', action='count', default=0, help = 'verbosity, add more - see more') - + subparsers = parser.add_subparsers(help = 'commands') subparsers.required = True subparsers.dest = 'command' @@ -282,24 +282,24 @@ def main(): target_group.add_argument('-p', '--pid', type=int, help='PID of process to dump') target_group.add_argument('-n', '--name', help='Name of process to dump') dump_group.add_argument('-o', '--outfile', help='Output .dmp file name', required = True) - + args = parser.parse_args() - + if args.verbose == 0: logging.basicConfig(level=logging.INFO) elif args.verbose == 1: logging.basicConfig(level=logging.DEBUG) else: logging.basicConfig(level=1) - + mindumptype = MINIDUMP_TYPE.MiniDumpNormal | MINIDUMP_TYPE.MiniDumpWithFullMemory - + if args.with_debug: logging.debug('Enabling SeDebugPrivilege') assigned = enable_debug_privilege() msg = ['failure', 'success'][assigned] logging.debug('SeDebugPrivilege assignment %s' % msg) - + if args.command == 'enum': pid_to_name = enum_process_names() t = [p for p in pid_to_name] @@ -307,12 +307,12 @@ def main(): for pid in t: logging.info('PID: %d Name: %s' % (pid, pid_to_name[pid])) return - + if args.command == 'dump': if args.pid: logging.info('Dumpig process PID %d' % args.pid) create_dump(args.pid, args.outfile, mindumptype, with_debug = args.with_debug) - + if args.name: pid_to_name = enum_process_names() for pid in pid_to_name: @@ -321,8 +321,7 @@ def main(): create_dump(pid, args.outfile, mindumptype, with_debug = args.with_debug) return logging.info('Failed to find process by name!') - + if __name__=='__main__': main() - \ No newline at end of file diff --git a/minidump/utils/winapi/kernel32.py b/minidump/utils/winapi/kernel32.py index 8a955d9..0bb427d 100644 --- a/minidump/utils/winapi/kernel32.py +++ b/minidump/utils/winapi/kernel32.py @@ -19,7 +19,7 @@ class WindowsMinBuild(enum.Enum): WIN_10 = 9800 #utter microsoft bullshit commencing.. -def getWindowsBuild(): +def getWindowsBuild(): class OSVersionInfo(ctypes.Structure): _fields_ = [ ("dwOSVersionInfoSize" , ctypes.c_int), @@ -31,7 +31,7 @@ class OSVersionInfo(ctypes.Structure): GetVersionEx = getattr( ctypes.windll.kernel32 , "GetVersionExA") version = OSVersionInfo() version.dwOSVersionInfoSize = ctypes.sizeof(OSVersionInfo) - GetVersionEx( ctypes.byref(version) ) + GetVersionEx( ctypes.byref(version) ) return version.dwBuildNumber def get_all_access_flags(): diff --git a/minidump/win_datatypes.py b/minidump/win_datatypes.py index d5cc5ef..8c6c23e 100644 --- a/minidump/win_datatypes.py +++ b/minidump/win_datatypes.py @@ -11,7 +11,7 @@ def __init__(self, reader, finaltype): self.location = reader.tell() self.value = reader.read_uint() self.finaltype = finaltype - + def read(self, reader, override_finaltype = None): if self.value == 0: return None @@ -23,7 +23,7 @@ def read(self, reader, override_finaltype = None): data = self.finaltype(reader) reader.move(pos) return data - + def read_raw(self, reader, size ): #we do not know the finaltype, just want the data if self.value == 0: @@ -33,23 +33,23 @@ def read_raw(self, reader, size ): data = reader.read(size) reader.move(pos) return data - + class PVOID(POINTER): def __init__(self, reader): super().__init__(reader, None) #with void we cannot determine the final type - + class BOOL: def __init__(self, reader): self.value = bool(reader.read_uint()) - + class BOOLEAN: def __init__(self, reader): self.value = reader.read(1) - + class BYTE: def __init__(self, reader): self.value = reader.read(1) - + class PBYTE(POINTER): def __init__(self, reader): super().__init__(reader, BYTE) @@ -57,52 +57,52 @@ def __init__(self, reader): class CCHAR: def __init__(self, reader): self.value = reader.read(1).decode('ascii') - + class CHAR: def __init__(self, reader): self.value = reader.read(1).decode('ascii') - + class UCHAR: def __init__(self, reader): self.value = int.from_bytes(reader.read(1), byteorder = 'little', signed = False) class WORD: def __init__(self, reader): - self.value = int.from_bytes(reader.read(2), byteorder = 'little', signed = False) + self.value = int.from_bytes(reader.read(2), byteorder = 'little', signed = False) class DWORD: def __init__(self, reader): self.value = int.from_bytes(reader.read(4), byteorder = 'little', signed = False) - + class DWORDLONG: def __init__(self, reader): self.value = int.from_bytes(reader.read(8), byteorder = 'little', signed = False) - + class DWORD_PTR(POINTER): def __init__(self, reader): super().__init__(reader, DWORD) - + class DWORD32: def __init__(self, reader): self.value = int.from_bytes(reader.read(4), byteorder = 'little', signed = False) class DWORD64: def __init__(self, reader): - self.value = int.from_bytes(reader.read(8), byteorder = 'little', signed = False) + self.value = int.from_bytes(reader.read(8), byteorder = 'little', signed = False) + - class HANDLE: def __init__(self, reader): self.value = reader.read_uint() - + class HFILE: def __init__(self, reader): self.value = int.from_bytes(reader.read(4), byteorder = 'little', signed = False) - + class HINSTANCE: def __init__(self, reader): - self.value = reader.read_uint() - + self.value = reader.read_uint() + class HKEY: def __init__(self, reader): @@ -112,7 +112,7 @@ def __init__(self, reader): class HKL: def __init__(self, reader): self.value = reader.read_uint() - + class HLOCAL: def __init__(self, reader): self.value = reader.read_uint() @@ -180,7 +180,7 @@ def __init__(self, reader): class ULONG: def __init__(self, reader): self.value = int.from_bytes(reader.read(4), byteorder = 'little', signed = False) - + class ULONGLONG: def __init__(self, reader): self.value = int.from_bytes(reader.read(8), byteorder = 'little', signed = False) @@ -188,51 +188,50 @@ def __init__(self, reader): class ULONG32: def __init__(self, reader): self.value = int.from_bytes(reader.read(4), byteorder = 'little', signed = False) - + class ULONG64: def __init__(self, reader): self.value = int.from_bytes(reader.read(8), byteorder = 'little', signed = False) - + class PWSTR(POINTER): def __init__(self, reader): super().__init__(reader, None) - + class PCHAR(POINTER): def __init__(self, reader): super().__init__(reader, CHAR) - + class USHORT: def __init__(self, reader): self.value = int.from_bytes(reader.read(2), byteorder = 'little', signed = False) - + class SHORT: def __init__(self, reader): self.value = int.from_bytes(reader.read(2), byteorder = 'little', signed = True) - + #https://msdn.microsoft.com/en-us/library/windows/hardware/ff554296(v=vs.85).aspx class LIST_ENTRY: def __init__(self, reader, finaltype = None): self.Flink = POINTER(reader, finaltype) self.Blink = POINTER(reader, finaltype) - + class FILETIME: def __init__(self, reader): self.dwLowDateTime = DWORD(reader) self.dwHighDateTime = DWORD(reader) self.value = (self.dwHighDateTime.value << 32) + self.dwLowDateTime.value - + class PUCHAR(POINTER): def __init__(self, reader): super().__init__(reader, UCHAR) - + class PCWSTR(POINTER): def __init__(self, reader): super().__init__(reader, None) - + class SIZE_T: def __init__(self, reader): self.value = reader.read_uint() - - - \ No newline at end of file + + diff --git a/minidump/writer.py b/minidump/writer.py index b5fcb8e..b8038ae 100644 --- a/minidump/writer.py +++ b/minidump/writer.py @@ -118,7 +118,7 @@ def get_modules(self): mmod.ModuleName = modname module_list.Modules.append(mmod) - + return module_list def get_sections(self): @@ -149,11 +149,11 @@ def get_sections(self): meminfolist.entries.append(mi) print(str(mi)) - + i += mi_raw.RegionSize self.meminfolist = meminfolist return meminfolist - + def get_threads(self): pass @@ -219,24 +219,24 @@ def prepare_directory(self): self.header_buffer.write(directory.to_bytes()) def finalize_header(self): - # currently only using the 32 bit MINIDUMP_LOCATION_DESCRIPTOR, this is because we expect that the header + # currently only using the 32 bit MINIDUMP_LOCATION_DESCRIPTOR, this is because we expect that the header # and any data in the header (including all streams data except memory stream) will not be bigger than 4GB - # memory stream is a special case, as it cvan be longer than 4GB but the RVA to the beginning of the memory stream + # memory stream is a special case, as it cvan be longer than 4GB but the RVA to the beginning of the memory stream # is not expected to be bigger than 4G max. # if this becomes the case then this all will fail :) header_size = 28 header_size += len(self.streams) * 8 #this is for the dictionary itself, not the streams for stream in self.streams: header_size += self.streams[stream].get_size() - + header_size += 10 * 1024 #allocating 10k for the memory info self.prepare_header() self.prepare_directory() - - - + + + def create_streams(self): sysinfo = self.sysreader.get_sysinfo() @@ -245,32 +245,32 @@ def create_streams(self): print(str(sysinfo)) moduleinfo = self.sysreader.get_modules() self.streams[MINIDUMP_STREAM_TYPE.ModuleListStream] = moduleinfo - + sections = self.sysreader.get_sections() self.streams[MINIDUMP_STREAM_TYPE.MemoryInfoListStream] = sections - + self.finalize_header() memory = self.sysreader.get_memory() - - + + #def get_total_streams_cnt(self): # total = 0 # for t in self.streams: # total += len(t) # return total - - + + #def construct_directory(self): # # total_streams = self.get_total_streams_cnt() # - # for stype in self.streams: + # for stype in self.streams: # for stream in self.streams[stype]: - # + # # stream # # loc = MINIDUMP_LOCATION_DESCRIPTOR() @@ -295,13 +295,13 @@ def construct_directory(self): #modules #self.sysreader.get_modules(self.hdr_buff, self.data_buff) #self.stream_cnt += 1 - + #write header self.write_header() - + #append datastream for memory, with correct rva - + #dump memory def run(self):