Skip to content

Commit 819db50

Browse files
author
SkelSec
committed
adding PEB fixes, some type hints
1 parent 23769ed commit 819db50

19 files changed

+290
-223
lines changed

minidump/__main__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def run():
2727
parser.add_argument('--exception', action='store_true', help='Show exception records')
2828
parser.add_argument('--handles', action='store_true', help='List handles')
2929
parser.add_argument('--misc', action='store_true', help='Show misc info')
30+
parser.add_argument('--peb', action='store_true', help='Show PEB info')
3031
parser.add_argument('--all', action='store_true', help='Show all info')
3132
parser.add_argument('-r', '--read-addr', type=lambda x: int(x,0), help='Dump a memory region from the process\'s addres space')
3233
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():
8990
print(str(mf.misc_info))
9091
if args.all or args.header:
9192
print(str(mf.header))
93+
94+
if args.all or args.peb:
95+
if mf.peb is not None:
96+
print(str(mf.peb))
9297

9398
if args.read_addr:
9499
buff_reader = reader.get_buffered_reader()

minidump/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
__version__ = "0.0.23"
2+
__version__ = "0.0.24"
33
__banner__ = \
44
"""
55
# minidump %s

minidump/constants.py

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -66,50 +66,3 @@ class MINIDUMP_TYPE(enum.IntFlag):
6666
MiniDumpFilterTriage = 0x00100000
6767
MiniDumpValidTypeFlags = 0x001fffff
6868

69-
70-
OFFSETS = [
71-
{ # x86 offsets
72-
# _TEB offsets
73-
"peb": 0x30,
74-
# _PEB offsets
75-
"being_debugged": 0x2,
76-
"image_base_address": 0x8,
77-
"process_parameters": 0x10,
78-
# _RTL_USER_PROCESS_PARAMETERS offsets
79-
"image_path": 0x38,
80-
"command_line": 0x40,
81-
"window_title": 0x70,
82-
"dll_path": 0x30,
83-
"current_directory": 0x24,
84-
"standard_input": 0x18,
85-
"standard_output": 0x1C,
86-
"standard_error": 0x20,
87-
"environment_variables": 0x48,
88-
# _UNICODE_STRING offsets
89-
"buffer": 0x4,
90-
},
91-
{ # x64 offsets
92-
# _TEB offsets
93-
"peb": 0x60,
94-
# _PEB offsets
95-
"being_debugged": 0x2,
96-
"image_base_address": 0x10,
97-
"process_parameters": 0x20,
98-
# _RTL_USER_PROCESS_PARAMETERS offsets
99-
"image_path": 0x60,
100-
"command_line": 0x70,
101-
"window_title": 0xB0,
102-
"dll_path": 0x50,
103-
"current_directory": 0x38,
104-
"standard_input": 0x20,
105-
"standard_output": 0x28,
106-
"standard_error": 0x30,
107-
"environment_variables": 0x80,
108-
# _UNICODE_STRING offsets
109-
"buffer": 0x8,
110-
},
111-
]
112-
113-
114-
POINTER_SIZE = [4, 8] # x86 (32 bit size pointer) # x64 (64 bit size pointer)
115-

minidump/directory.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
class MINIDUMP_DIRECTORY:
66
def __init__(self):
7-
self.StreamType = None
8-
self.Location = None
7+
self.StreamType:MINIDUMP_STREAM_TYPE = None
8+
self.Location:MINIDUMP_LOCATION_DESCRIPTOR = None
99

1010
def to_bytes(self):
1111
t = self.StreamType.value.to_bytes(4, byteorder = 'little', signed = False)

minidump/header.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55
# https://msdn.microsoft.com/en-us/library/windows/desktop/ms680378(v=vs.85).aspx
66
class MinidumpHeader:
77
def __init__(self):
8-
self.Signature = 'PMDM'
9-
self.Version = None
10-
self.ImplementationVersion = None
11-
self.NumberOfStreams = None
12-
self.StreamDirectoryRva = None
13-
self.CheckSum = 0
14-
self.Reserved = 0
15-
self.TimeDateStamp = 0
16-
self.Flags = None
8+
self.Signature:str = 'PMDM'
9+
self.Version:int = None
10+
self.ImplementationVersion:int = None
11+
self.NumberOfStreams:int = None
12+
self.StreamDirectoryRva:int = None
13+
self.CheckSum:int = 0
14+
self.Reserved:int = 0
15+
self.TimeDateStamp:int = 0
16+
self.Flags:MINIDUMP_TYPE = None
1717

1818
def to_bytes(self):
1919
t = self.Signature.encode('ascii')

minidump/minidumpfile.py

Lines changed: 34 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -9,37 +9,41 @@
99
import enum
1010
import struct
1111
import logging
12+
from typing import List
1213

1314
from minidump.header import MinidumpHeader
1415
from minidump.minidumpreader import MinidumpFileReader
1516
from minidump.streams import *
1617
from minidump.common_structs import *
17-
from minidump.constants import MINIDUMP_STREAM_TYPE, OFFSETS, POINTER_SIZE
18+
from minidump.constants import MINIDUMP_STREAM_TYPE
1819
from minidump.directory import MINIDUMP_DIRECTORY
1920
from minidump.streams.SystemInfoStream import PROCESSOR_ARCHITECTURE
21+
from minidump.structures.peb import PEB
2022

2123

2224
class MinidumpFile:
2325
def __init__(self):
24-
self.filename = None
26+
self.filename:str = None
2527
self.file_handle = None
26-
self.header = None
27-
self.directories = []
28-
29-
self.threads_ex = None
30-
self.threads = None
31-
self.modules = None
32-
self.memory_segments = None
33-
self.memory_segments_64 = None
34-
self.sysinfo = None
35-
self.comment_a = None
36-
self.comment_w = None
37-
self.exception = None
38-
self.handles = None
39-
self.unloaded_modules = None
40-
self.misc_info = None
41-
self.memory_info = None
42-
self.thread_info = None
28+
self.header:MinidumpHeader = None
29+
self.directories: List[MINIDUMP_DIRECTORY] = []
30+
31+
self.threads_ex:MinidumpThreadExList = None
32+
self.threads:MinidumpThreadList = None
33+
self.modules:MinidumpModuleList = None
34+
self.memory_segments:MinidumpMemoryList = None
35+
self.memory_segments_64:MinidumpMemory64List = None
36+
self.sysinfo:MinidumpSystemInfo = None
37+
self.comment_a:CommentStreamA = None
38+
self.comment_w:CommentStreamW = None
39+
self.exception:ExceptionList = None
40+
self.handles:MinidumpHandleDataStream = None
41+
self.unloaded_modules:MinidumpUnloadedModuleList = None
42+
self.misc_info:MinidumpMiscInfo = None
43+
self.memory_info:MinidumpMemoryInfoList = None
44+
self.thread_info:MinidumpThreadInfoList = None
45+
46+
self.peb:PEB = None
4347

4448
@staticmethod
4549
def parse(filename):
@@ -78,82 +82,10 @@ def get_reader(self):
7882
def _parse(self):
7983
self.__parse_header()
8084
self.__parse_directories()
81-
self.__parse_peb()
82-
83-
def __read_unicode_string_property(self, buff_reader, addr, x64):
84-
buff_reader.move(addr)
85-
string_length = int.from_bytes(buff_reader.read(2), "little")
86-
if not string_length:
87-
return ""
88-
buff_reader.move(addr + OFFSETS[x64]["buffer"])
89-
buff_va = int.from_bytes(buff_reader.read(POINTER_SIZE[x64]), "little")
90-
buff_reader.move(buff_va)
91-
return buff_reader.read(string_length).decode("utf-16")
92-
93-
def __parse_peb(self):
94-
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))
95-
offset_index = self.x64
96-
97-
reader = self.get_reader()
98-
buff_reader = reader.get_buffered_reader()
99-
100-
buff_reader.move(self.threads.threads[0].Teb + OFFSETS[offset_index]["peb"])
101-
102-
self.peb_address = int.from_bytes(buff_reader.read(POINTER_SIZE[self.x64]), "little")
103-
104-
buff_reader.move(self.peb_address + OFFSETS[offset_index]["being_debugged"])
105-
self.being_debugged = int.from_bytes(buff_reader.read(1), "little")
106-
107-
buff_reader.move(self.peb_address + OFFSETS[offset_index]["image_base_address"])
108-
self.image_base_address = int.from_bytes(buff_reader.read(POINTER_SIZE[self.x64]), "little")
109-
110-
buff_reader.move(self.peb_address + OFFSETS[offset_index]["process_parameters"])
111-
process_parameters = int.from_bytes(buff_reader.read(POINTER_SIZE[self.x64]), "little")
112-
113-
self.image_path = self.__read_unicode_string_property(
114-
buff_reader, process_parameters + OFFSETS[offset_index]["image_path"], self.x64
115-
)
116-
117-
self.command_line = self.__read_unicode_string_property(
118-
buff_reader, process_parameters + OFFSETS[offset_index]["command_line"], self.x64
119-
)
120-
121-
self.window_title = self.__read_unicode_string_property(
122-
buff_reader, process_parameters + OFFSETS[offset_index]["window_title"], self.x64
123-
)
124-
125-
self.dll_path = self.__read_unicode_string_property(buff_reader, process_parameters + OFFSETS[offset_index]["dll_path"],
126-
self.x64)
127-
128-
self.current_directory = self.__read_unicode_string_property(
129-
buff_reader, process_parameters + OFFSETS[offset_index]["current_directory"], self.x64
130-
)
131-
132-
buff_reader.move(process_parameters + OFFSETS[offset_index]["standard_input"])
133-
self.standard_input = int.from_bytes(buff_reader.read(POINTER_SIZE[self.x64]), "little")
134-
135-
buff_reader.move(process_parameters + OFFSETS[offset_index]["standard_output"])
136-
self.standard_output = int.from_bytes(buff_reader.read(POINTER_SIZE[self.x64]), "little")
137-
138-
buff_reader.move(process_parameters + OFFSETS[offset_index]["standard_error"])
139-
self.standard_error = int.from_bytes(buff_reader.read(POINTER_SIZE[self.x64]), "little")
140-
141-
# Parse Environment Variables from PEB
142-
self.environment_variables = []
143-
buff_reader.move(process_parameters + OFFSETS[offset_index]["environment_variables"])
144-
environment_va = int.from_bytes(buff_reader.read(POINTER_SIZE[self.x64]), "little")
145-
buff_reader.move(environment_va)
146-
147-
env_buffer = buff_reader.read(buff_reader.current_segment.end_address - buff_reader.current_position)
148-
while (env_len := env_buffer.find(b"\x00\x00")) and (env_len != -1):
149-
decoded_env = (env_buffer[:env_len] + b"\x00").decode("utf-16")
150-
name = decoded_env.split("=")[0]
151-
value = decoded_env.split("=")[1]
152-
self.environment_variables.append({"name": name, "value": value})
153-
environment_va += (len(decoded_env) + 1) * 2
154-
buff_reader.move(environment_va)
155-
env_buffer = buff_reader.read(buff_reader.current_segment.end_address - buff_reader.current_position)
156-
85+
try:
86+
self.__parse_peb()
87+
except Exception as e:
88+
logging.exception('PEB parsing error!')
15789

15890
def __parse_header(self):
15991
self.header = MinidumpHeader.parse(self.file_handle)
@@ -296,6 +228,13 @@ def __parse_thread_context(self):
296228
elif self.sysinfo.ProcessorArchitecture == PROCESSOR_ARCHITECTURE.INTEL:
297229
thread.ContextObject = WOW64_CONTEXT.parse(self.file_handle)
298230

231+
def __parse_peb(self):
232+
if not self.sysinfo or not self.threads:
233+
return
234+
235+
self.peb = PEB.from_minidump(self)
236+
237+
299238

300239
def __str__(self):
301240
t = '== Minidump File ==\n'

minidump/minidumpreader.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,6 @@ def find_in_module(self, module_name, pattern, find_first = False, reverse_order
272272
t = self.reader.search_module(module_name, pattern, find_first = find_first, reverse_order = reverse_order, chunksize = self.segment_chunk_size)
273273
return t
274274

275-
276-
277-
278275
class MinidumpFileReader:
279276
def __init__(self, minidumpfile):
280277
self.modules = minidumpfile.modules.modules
@@ -358,4 +355,3 @@ def read(self, virt_addr, size):
358355
if segment.inrange(virt_addr):
359356
return segment.read(virt_addr, size, self.file_handle)
360357
raise Exception('Address not in memory range! %s' % hex(virt_addr))
361-

minidump/minidumpshell.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ def do_open(self, filename):
2828
"""Opens minidump file"""
2929
self.mini = MinidumpFile.parse(filename)
3030
self.reader = self.mini.get_reader().get_buffered_reader()
31+
32+
def do_peb(self, args):
33+
"""Shows PEB information (if available)"""
34+
if self.mini.peb is not None:
35+
print(str(self.mini.peb))
3136

3237
def do_threads(self, args):
3338
"""Lists all thread information (if available)"""

minidump/streams/CommentStreamA.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#
66
class CommentStreamA:
77
def __init__(self):
8-
self.data = None
8+
self.data:str = None
99

1010
def to_bytes(self):
1111
return self.data.encode('ascii')

minidump/streams/CommentStreamW.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#
66
class CommentStreamW:
77
def __init__(self):
8-
self.data = None
8+
self.data:str = None
99

1010
def to_bytes(self):
1111
return self.data.encode('utf-16-le')

0 commit comments

Comments
 (0)