1#!/usr/bin/env python3 2# 3# Author: 4# Tamas Jos (@skelsec) 5# 6import io 7from minidump.common_structs import * 8 9class MinidumpModule: 10 def __init__(self): 11 self.name = None 12 self.baseaddress = None 13 self.size = None 14 self.endaddress = None 15 16 self.versioninfo = None 17 self.checksum = None 18 self.timestamp = None 19 20 @staticmethod 21 def parse(mod, buff): 22 """ 23 mod: MINIDUMP_MODULE 24 buff: file handle 25 """ 26 mm = MinidumpModule() 27 mm.baseaddress = mod.BaseOfImage 28 mm.size = mod.SizeOfImage 29 mm.checksum = mod.CheckSum 30 mm.timestamp = mod.TimeDateStamp 31 mm.name = MINIDUMP_STRING.get_from_rva(mod.ModuleNameRva, buff) 32 mm.versioninfo = mod.VersionInfo 33 mm.endaddress = mm.baseaddress + mm.size 34 return mm 35 36 @staticmethod 37 async def aparse(mod, buff): 38 """ 39 mod: MINIDUMP_MODULE 40 buff: file handle 41 """ 42 mm = MinidumpModule() 43 mm.baseaddress = mod.BaseOfImage 44 mm.size = mod.SizeOfImage 45 mm.checksum = mod.CheckSum 46 mm.timestamp = mod.TimeDateStamp 47 mm.name = await MINIDUMP_STRING.aget_from_rva(mod.ModuleNameRva, buff) 48 mm.versioninfo = mod.VersionInfo 49 mm.endaddress = mm.baseaddress + mm.size 50 return mm 51 52 def inrange(self, memory_loc): 53 return self.baseaddress <= memory_loc < self.endaddress 54 55 @staticmethod 56 def get_header(): 57 return [ 58 'Module name', 59 'BaseAddress', 60 'Size', 61 'Endaddress', 62 'Timestamp', 63 ] 64 65 def to_row(self): 66 return [ 67 str(self.name), 68 '0x%08x' % self.baseaddress, 69 hex(self.size), 70 '0x%08x' % self.endaddress, 71 '0x%08x' % self.timestamp, 72 ] 73 74 75 def __str__(self): 76 return 'Module name: %s BaseAddress: 0x%08x Size: 0x%x Endaddress: 0x%08x' % (self.name, self.baseaddress, self.size, self.endaddress) 77 78# https://msdn.microsoft.com/en-us/library/windows/desktop/ms646997(v=vs.85).aspx 79class VS_FIXEDFILEINFO: 80 def __init__(self): 81 self.dwSignature = None 82 self.dwStrucVersion = None 83 self.dwFileVersionMS = None 84 self.dwFileVersionLS = None 85 self.dwProductVersionMS = None 86 self.dwProductVersionLS = None 87 self.dwFileFlagsMask = None 88 self.dwFileFlags = None 89 self.dwFileOS = None 90 self.dwFileType = None 91 self.dwFileSubtype = None 92 self.dwFileDateMS = None 93 self.dwFileDateLS = None 94 95 def get_size(self): 96 return 13*4 97 98 def to_bytes(self): 99 t = self.dwSignature.to_bytes(4, byteorder = 'little', signed = False) 100 t += self.dwStrucVersion.to_bytes(4, byteorder = 'little', signed = False) 101 t += self.dwFileVersionMS.to_bytes(4, byteorder = 'little', signed = False) 102 t += self.dwFileVersionLS.to_bytes(4, byteorder = 'little', signed = False) 103 t += self.dwProductVersionMS.to_bytes(4, byteorder = 'little', signed = False) 104 t += self.dwProductVersionLS.to_bytes(4, byteorder = 'little', signed = False) 105 t += self.dwFileFlagsMask.to_bytes(4, byteorder = 'little', signed = False) 106 t += self.dwFileFlags.to_bytes(4, byteorder = 'little', signed = False) 107 t += self.dwFileOS.to_bytes(4, byteorder = 'little', signed = False) 108 t += self.dwFileType.to_bytes(4, byteorder = 'little', signed = False) 109 t += self.dwFileSubtype.to_bytes(4, byteorder = 'little', signed = False) 110 t += self.dwFileDateMS.to_bytes(4, byteorder = 'little', signed = False) 111 t += self.dwFileDateLS.to_bytes(4, byteorder = 'little', signed = False) 112 return t 113 114 @staticmethod 115 def from_bytes(data): 116 return VS_FIXEDFILEINFO.parse(io.BytesIO(data)) 117 118 @staticmethod 119 def parse(buff): 120 vf = VS_FIXEDFILEINFO() 121 vf.dwSignature = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) 122 vf.dwStrucVersion = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) 123 vf.dwFileVersionMS = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) 124 vf.dwFileVersionLS = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) 125 vf.dwProductVersionMS = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) 126 vf.dwProductVersionLS = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) 127 vf.dwFileFlagsMask = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) 128 vf.dwFileFlags = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) 129 vf.dwFileOS = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) 130 vf.dwFileType = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) 131 vf.dwFileSubtype = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) 132 vf.dwFileDateMS = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) 133 vf.dwFileDateLS = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) 134 return vf 135 136 def __str__(self): 137 t = '' 138 for k in self.__dict__: 139 t += '%s : %s\r\n' % (k, str(self.__dict__[k])) 140 return t 141 142# https://msdn.microsoft.com/en-us/library/windows/desktop/ms680392(v=vs.85).aspx 143class MINIDUMP_MODULE: 144 def __init__(self): 145 self.BaseOfImage = None 146 self.SizeOfImage = None 147 self.CheckSum = 0 148 self.TimeDateStamp = None 149 self.ModuleNameRva = None 150 self.VersionInfo = None 151 self.CvRecord = None 152 self.MiscRecord = None 153 self.Reserved0 = 0 154 self.Reserved1 = 0 155 156 #for writer 157 self.ModuleName = None 158 159 def get_size(self): 160 return 8+4+4+4+4+8+8+VS_FIXEDFILEINFO().get_size() + 2 * MINIDUMP_LOCATION_DESCRIPTOR().get_size() 161 162 def to_bytes(self): 163 t = self.BaseOfImage.to_bytes(8, byteorder = 'little', signed = False) 164 t += self.SizeOfImage.to_bytes(4, byteorder = 'little', signed = False) 165 t += self.CheckSum.to_bytes(4, byteorder = 'little', signed = False) 166 t += self.TimeDateStamp.to_bytes(4, byteorder = 'little', signed = False) 167 t += self.ModuleNameRva.to_bytes(4, byteorder = 'little', signed = False) 168 t += self.VersionInfo.to_bytes() 169 t += self.CvRecord.to_bytes() 170 t += self.MiscRecord.to_bytes() 171 t += self.Reserved0.to_bytes(8, byteorder = 'little', signed = False) 172 t += self.Reserved1.to_bytes(8, byteorder = 'little', signed = False) 173 return t 174 175 @staticmethod 176 def parse(buff): 177 mm = MINIDUMP_MODULE() 178 mm.BaseOfImage = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) 179 mm.SizeOfImage = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) 180 mm.CheckSum = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) 181 mm.TimeDateStamp = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) 182 mm.ModuleNameRva = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) 183 mm.VersionInfo = VS_FIXEDFILEINFO.parse(buff) 184 mm.CvRecord = MINIDUMP_LOCATION_DESCRIPTOR.parse(buff) 185 mm.MiscRecord = MINIDUMP_LOCATION_DESCRIPTOR.parse(buff) 186 mm.Reserved0 = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) 187 mm.Reserved1 = int.from_bytes(buff.read(8), byteorder = 'little', signed = False) 188 return mm 189 190 def __str__(self): 191 t = '' 192 for k in self.__dict__: 193 t += '%s : %s\r\n' % (k, str(self.__dict__[k])) 194 return t 195 196# https://msdn.microsoft.com/en-us/library/windows/desktop/ms680391(v=vs.85).aspx 197class MINIDUMP_MODULE_LIST: 198 def __init__(self): 199 self.NumberOfModules = None 200 self.Modules = [] 201 202 def get_size(self): 203 return 4 + len(self.Modules) * MINIDUMP_MODULE().get_size() 204 205 def to_bytes(self): 206 t = len(self.Modules).to_bytes(4, byteorder = 'little', signed = False) 207 for module in self.Modules: 208 t += module.to_bytes() 209 return t 210 211 @staticmethod 212 def parse(buff): 213 mml = MINIDUMP_MODULE_LIST() 214 mml.NumberOfModules = int.from_bytes(buff.read(4), byteorder = 'little', signed = False) 215 for _ in range(mml.NumberOfModules): 216 mml.Modules.append(MINIDUMP_MODULE.parse(buff)) 217 218 return mml 219 220class MinidumpModuleList: 221 def __init__(self): 222 self.modules = [] 223 224 @staticmethod 225 def parse(dir, buff): 226 t = MinidumpModuleList() 227 buff.seek(dir.Location.Rva) 228 chunk = io.BytesIO(buff.read(dir.Location.DataSize)) 229 mtl = MINIDUMP_MODULE_LIST.parse(chunk) 230 for mod in mtl.Modules: 231 t.modules.append(MinidumpModule.parse(mod, buff)) 232 return t 233 234 @staticmethod 235 async def aparse(dir, buff): 236 t = MinidumpModuleList() 237 await buff.seek(dir.Location.Rva) 238 chunk_data = await buff.read(dir.Location.DataSize) 239 chunk = io.BytesIO(chunk_data) 240 mtl = MINIDUMP_MODULE_LIST.parse(chunk) 241 for mod in mtl.Modules: 242 x = await MinidumpModule.aparse(mod, buff) 243 t.modules.append(x) 244 return t 245 246 def to_table(self): 247 t = [] 248 t.append(MinidumpModule.get_header()) 249 for mod in self.modules: 250 t.append(mod.to_row()) 251 return t 252 253 def __str__(self): 254 t = '== ModuleList ==\n' + construct_table(self.to_table()) 255 return t 256