Skip to content

Commit

Permalink
adding PEB fixes, some type hints
Browse files Browse the repository at this point in the history
  • Loading branch information
SkelSec committed Aug 15, 2024
1 parent 23769ed commit 819db50
Show file tree
Hide file tree
Showing 19 changed files with 290 additions and 223 deletions.
5 changes: 5 additions & 0 deletions minidump/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down Expand Up @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion minidump/_version.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

__version__ = "0.0.23"
__version__ = "0.0.24"
__banner__ = \
"""
# minidump %s
Expand Down
47 changes: 0 additions & 47 deletions minidump/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

4 changes: 2 additions & 2 deletions minidump/directory.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
18 changes: 9 additions & 9 deletions minidump/header.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
129 changes: 34 additions & 95 deletions minidump/minidumpfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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'
Expand Down
4 changes: 0 additions & 4 deletions minidump/minidumpreader.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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))

5 changes: 5 additions & 0 deletions minidump/minidumpshell.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)"""
Expand Down
2 changes: 1 addition & 1 deletion minidump/streams/CommentStreamA.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
2 changes: 1 addition & 1 deletion minidump/streams/CommentStreamW.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
11 changes: 6 additions & 5 deletions minidump/streams/ExceptionStream.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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):
Expand Down
12 changes: 6 additions & 6 deletions minidump/streams/FunctionTableStream.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
Loading

0 comments on commit 819db50

Please sign in to comment.