From e0a9a5fefb9db93635fa3468dd2ce9313907a1bd Mon Sep 17 00:00:00 2001 From: Danking555 Date: Mon, 12 Aug 2024 13:28:29 +0000 Subject: [PATCH] Added PEB parsing capabilities (extracting Command Line, Window Title, Current Directory, Environment Variables and much more) --- minidump/constants.py | 51 +++++++++++++++++++++++++- minidump/minidumpfile.py | 78 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 127 insertions(+), 2 deletions(-) diff --git a/minidump/constants.py b/minidump/constants.py index 82d77f7..4a9b947 100644 --- a/minidump/constants.py +++ b/minidump/constants.py @@ -40,6 +40,7 @@ class MINIDUMP_STREAM_TYPE(enum.Enum): ceStreamDiagnosisList = 37 LastReservedStream = 0xffff + class MINIDUMP_TYPE(enum.IntFlag): MiniDumpNormal = 0x00000000 MiniDumpWithDataSegs = 0x00000001 @@ -63,4 +64,52 @@ class MINIDUMP_TYPE(enum.IntFlag): MiniDumpWithTokenInformation = 0x00040000 MiniDumpWithModuleHeaders = 0x00080000 MiniDumpFilterTriage = 0x00100000 - MiniDumpValidTypeFlags = 0x001fffff \ No newline at end of file + MiniDumpValidTypeFlags = 0x001fffff + + +OFFSETS = [ + { # x86 offsets + # _TEB offsets + "peb": 0x30, + # _PEB offsets + "being_debugged": 0x2, + "image_base_address": 0x8, + "process_parameters": 0x10, + # _RTL_USER_PROCESS_PARAMETERS offsets + "image_path": 0x38, + "command_line": 0x40, + "window_title": 0x70, + "dll_path": 0x30, + "current_directory": 0x24, + "standard_input": 0x18, + "standard_output": 0x1C, + "standard_error": 0x20, + "environment_variables": 0x48, + # _UNICODE_STRING offsets + "buffer": 0x4, + }, + { # x64 offsets + # _TEB offsets + "peb": 0x60, + # _PEB offsets + "being_debugged": 0x2, + "image_base_address": 0x10, + "process_parameters": 0x20, + # _RTL_USER_PROCESS_PARAMETERS offsets + "image_path": 0x60, + "command_line": 0x70, + "window_title": 0xB0, + "dll_path": 0x50, + "current_directory": 0x38, + "standard_input": 0x20, + "standard_output": 0x28, + "standard_error": 0x30, + "environment_variables": 0x80, + # _UNICODE_STRING offsets + "buffer": 0x8, + }, +] + + +POINTER_SIZE = [4, 8] # x86 (32 bit size pointer) # x64 (64 bit size pointer) + diff --git a/minidump/minidumpfile.py b/minidump/minidumpfile.py index c83d10e..2dc52d1 100644 --- a/minidump/minidumpfile.py +++ b/minidump/minidumpfile.py @@ -14,7 +14,7 @@ from minidump.minidumpreader import MinidumpFileReader from minidump.streams import * from minidump.common_structs import * -from minidump.constants import MINIDUMP_STREAM_TYPE +from minidump.constants import MINIDUMP_STREAM_TYPE, OFFSETS, POINTER_SIZE from minidump.directory import MINIDUMP_DIRECTORY from minidump.streams.SystemInfoStream import PROCESSOR_ARCHITECTURE @@ -78,6 +78,82 @@ 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) + def __parse_header(self): self.header = MinidumpHeader.parse(self.file_handle)