diff options
| author | Fabrice Desclaux <fabrice.desclaux@cea.fr> | 2019-03-04 12:22:16 +0100 |
|---|---|---|
| committer | Fabrice Desclaux <fabrice.desclaux@cea.fr> | 2019-03-05 16:52:51 +0100 |
| commit | 26c1075723a02984da6d3bc7423c5c0c43082dc3 (patch) | |
| tree | b67e7b072439f84109bd39dad8ed7f3f135224f8 /miasm/loader/minidump_init.py | |
| parent | bb675f5cb34a482c964249656d539e67718bd8dc (diff) | |
| download | focaccia-miasm-26c1075723a02984da6d3bc7423c5c0c43082dc3.tar.gz focaccia-miasm-26c1075723a02984da6d3bc7423c5c0c43082dc3.zip | |
Rename elfesteem loader
Diffstat (limited to 'miasm/loader/minidump_init.py')
| -rw-r--r-- | miasm/loader/minidump_init.py | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/miasm/loader/minidump_init.py b/miasm/loader/minidump_init.py new file mode 100644 index 00000000..dd37f730 --- /dev/null +++ b/miasm/loader/minidump_init.py @@ -0,0 +1,194 @@ +""" +High-level abstraction of Minidump file +""" +from builtins import range +import struct + +from miasm.loader.strpatchwork import StrPatchwork +from miasm.loader import minidump as mp + + +class MemorySegment(object): + """Stand for a segment in memory with additional information""" + + def __init__(self, offset, memory_desc, module=None, memory_info=None): + self.offset = offset + self.memory_desc = memory_desc + self.module = module + self.memory_info = memory_info + self.minidump = self.memory_desc.parent_head + + @property + def address(self): + return self.memory_desc.StartOfMemoryRange + + @property + def size(self): + if isinstance(self.memory_desc, mp.MemoryDescriptor64): + return self.memory_desc.DataSize + elif isinstance(self.memory_desc, mp.MemoryDescriptor): + return self.memory_desc.Memory.DataSize + raise TypeError + + @property + def name(self): + if not self.module: + return "" + name = mp.MinidumpString.unpack(self.minidump._content, + self.module.ModuleNameRva.rva, + self.minidump) + return b"".join( + struct.pack("B", x) for x in name.Buffer + ).decode("utf-16") + + @property + def content(self): + return self.minidump._content[self.offset:self.offset + self.size] + + @property + def protect(self): + if self.memory_info: + return self.memory_info.Protect + return None + + @property + def pretty_protect(self): + if self.protect is None: + return "UNKNOWN" + return mp.memProtect[self.protect] + + +class Minidump(object): + """Stand for a Minidump file + + Here is a few limitation: + - only < 4GB Minidump are supported (LocationDescriptor handling) + - only Stream relative to memory mapping are implemented + + Official description is available on MSDN: + https://msdn.microsoft.com/en-us/library/ms680378(VS.85).aspx + """ + + _sex = 0 + _wsize = 32 + + def __init__(self, minidump_str): + self._content = StrPatchwork(minidump_str) + + # Specific streams + self.modulelist = None + self.memory64list = None + self.memorylist = None + self.memoryinfolist = None + self.systeminfo = None + + # Get information + self.streams = [] + self.threads = None + self.parse_content() + + # Memory information + self.memory = {} # base address (virtual) -> Memory information + self.build_memory() + + def parse_content(self): + """Build structures corresponding to current content""" + + # Header + offset = 0 + self.minidumpHDR = mp.MinidumpHDR.unpack(self._content, offset, self) + assert self.minidumpHDR.Magic == 0x504d444d + + # Streams + base_offset = self.minidumpHDR.StreamDirectoryRva.rva + empty_stream = mp.StreamDirectory( + StreamType=0, + Location=mp.LocationDescriptor( + DataSize=0, + Rva=mp.Rva(rva=0) + ) + ) + streamdir_size = len(empty_stream) + for i in range(self.minidumpHDR.NumberOfStreams): + stream_offset = base_offset + i * streamdir_size + stream = mp.StreamDirectory.unpack(self._content, stream_offset, self) + self.streams.append(stream) + + # Launch specific action depending on the stream + datasize = stream.Location.DataSize + offset = stream.Location.Rva.rva + if stream.StreamType == mp.streamType.ModuleListStream: + self.modulelist = mp.ModuleList.unpack(self._content, offset, self) + elif stream.StreamType == mp.streamType.MemoryListStream: + self.memorylist = mp.MemoryList.unpack(self._content, offset, self) + elif stream.StreamType == mp.streamType.Memory64ListStream: + self.memory64list = mp.Memory64List.unpack(self._content, offset, self) + elif stream.StreamType == mp.streamType.MemoryInfoListStream: + self.memoryinfolist = mp.MemoryInfoList.unpack(self._content, offset, self) + elif stream.StreamType == mp.streamType.SystemInfoStream: + self.systeminfo = mp.SystemInfo.unpack(self._content, offset, self) + + # Some streams need the SystemInfo stream to work + for stream in self.streams: + datasize = stream.Location.DataSize + offset = stream.Location.Rva.rva + if (self.systeminfo is not None and + stream.StreamType == mp.streamType.ThreadListStream): + self.threads = mp.ThreadList.unpack(self._content, offset, self) + + + def build_memory(self): + """Build an easier to use memory view based on ModuleList and + Memory64List streams""" + + addr2module = dict((module.BaseOfImage, module) + for module in (self.modulelist.Modules if + self.modulelist else [])) + addr2meminfo = dict((memory.BaseAddress, memory) + for memory in (self.memoryinfolist.MemoryInfos if + self.memoryinfolist else [])) + + mode64 = self.minidumpHDR.Flags & mp.minidumpType.MiniDumpWithFullMemory + + if mode64: + offset = self.memory64list.BaseRva + memranges = self.memory64list.MemoryRanges + else: + memranges = self.memorylist.MemoryRanges + + for memory in memranges: + if not mode64: + offset = memory.Memory.Rva.rva + + # Create a MemorySegment with augmented information + base_address = memory.StartOfMemoryRange + module = addr2module.get(base_address, None) + meminfo = addr2meminfo.get(base_address, None) + self.memory[base_address] = MemorySegment(offset, memory, + module, meminfo) + + if mode64: + offset += memory.DataSize + + # Sanity check + if mode64: + assert all(addr in self.memory for addr in addr2module) + + def get(self, virt_start, virt_stop): + """Return the content at the (virtual addresses) + [virt_start:virt_stop]""" + + # Find the corresponding memory segment + for addr in self.memory: + if virt_start <= addr <= virt_stop: + break + else: + return b"" + + memory = self.memory[addr] + shift = addr - virt_start + last = virt_stop - addr + if last > memory.size: + raise RuntimeError("Multi-page not implemented") + + return self._content[memory.offset + shift:memory.offset + last] |