Files
iMHLv2 eab5ffc409 refs #89 fixing raw2dmp - make sure to set the DumpType since its now an assertion in the crash AS
note we have to use headerspace.write rather than header.DumpType = 1
because we can’t assign values to Enumeration types
2014-09-17 19:10:37 -05:00

174 lines
7.2 KiB
Python

# Volatility
# Copyright (C) 2009-2013 Volatility Foundation
# Copyright (C) Mike Auty <mike.auty@gmail.com>
#
# This file is part of Volatility.
#
# Volatility is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Volatility is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Volatility. If not, see <http://www.gnu.org/licenses/>.
#
import os
import volatility.obj as obj
import volatility.utils as utils
import volatility.addrspace as addrspace
import volatility.plugins.imagecopy as imagecopy
class Raw2dmp(imagecopy.ImageCopy):
"""Converts a physical memory sample to a windbg crash dump"""
def calculate(self):
config = self._config
output = self._config.OUTPUT_IMAGE
return self.convert_to_crash(config, output)
@staticmethod
def convert_to_crash(config, output):
blocksize = config.BLOCKSIZE
config.WRITE = True
pspace = utils.load_as(config, astype = 'physical')
vspace = utils.load_as(config)
memory_model = pspace.profile.metadata.get('memory_model', '32bit')
if memory_model == "64bit":
header_format = '_DMP_HEADER64'
else:
header_format = '_DMP_HEADER'
headerlen = pspace.profile.get_obj_size(header_format)
headerspace = addrspace.BufferAddressSpace(config, 0, "PAGE" * (headerlen / 4))
header = obj.Object(header_format, offset = 0, vm = headerspace)
kuser = obj.Object("_KUSER_SHARED_DATA",
offset = obj.VolMagic(vspace).KUSER_SHARED_DATA.v(),
vm = vspace)
kdbg = obj.VolMagic(vspace).KDBG.v()
# Scanning the memory region near KDDEBUGGER_DATA64 for
# DBGKD_GET_VERSION64
dbgkd = kdbg.dbgkd_version64()
# Set the correct file magic
for i in range(len("PAGE")):
header.Signature[i] = [ ord(x) for x in "PAGE"][i]
# Write the KeDebuggerDataBlock and ValidDump headers
dumptext = "DUMP"
header.KdDebuggerDataBlock = kdbg.obj_offset
if memory_model == "64bit":
dumptext = "DU64"
header.KdDebuggerDataBlock = kdbg.obj_offset | 0xFFFF000000000000
for i in range(len(dumptext)):
header.ValidDump[i] = ord(dumptext[i])
# The PaeEnabled member is essential for x86 crash files
if memory_model == "32bit":
if hasattr(vspace, "pae") and vspace.pae == True:
header.PaeEnabled = 0x1
else:
header.PaeEnabled = 0x0
# Set members of the crash header
header.MajorVersion = dbgkd.MajorVersion
header.MinorVersion = dbgkd.MinorVersion
header.DirectoryTableBase = vspace.dtb
header.PfnDataBase = kdbg.MmPfnDatabase
header.PsLoadedModuleList = kdbg.PsLoadedModuleList
header.PsActiveProcessHead = kdbg.PsActiveProcessHead
header.MachineImageType = dbgkd.MachineType
headerspace.write(header.DumpType.obj_offset, "\x01\x00\x00\x00")
# Find the number of processors
header.NumberProcessors = len(list(kdbg.kpcrs()))
# In MS crash dumps, SystemTime will not be set. It will
# represent the "Debug session time:". We are
# using the member to represent the time the sample was
# collected.
header.SystemTime = kuser.SystemTime.as_windows_timestamp()
# Zero out the BugCheck members
header.BugCheckCode = 0x00000000
header.BugCheckCodeParameter[0] = 0x00000000
header.BugCheckCodeParameter[1] = 0x00000000
header.BugCheckCodeParameter[2] = 0x00000000
header.BugCheckCodeParameter[3] = 0x00000000
# Set the sample run information. We used to take the sum of the size
# of all runs, but that assumed the base layer was raw. In the case
# of base layers such as ELF64 core dump or any other run-based address
# space that may have holes for device memory, that would fail because
# any runs after the first hole would then be at the wrong offset.
last_run = list(pspace.get_available_addresses())[-1]
num_pages = (last_run[0] + last_run[1]) / 0x1000
header.PhysicalMemoryBlockBuffer.NumberOfRuns = 0x00000001
header.PhysicalMemoryBlockBuffer.NumberOfPages = num_pages
header.PhysicalMemoryBlockBuffer.Run[0].BasePage = 0x0000000000000000
header.PhysicalMemoryBlockBuffer.Run[0].PageCount = num_pages
header.RequiredDumpSpace = (num_pages + 2) * 0x1000
# Zero out the remaining non-essential fields
ContextRecordOffset = headerspace.profile.get_obj_offset(header_format, "ContextRecord")
ExceptionOffset = headerspace.profile.get_obj_offset(header_format, "Exception")
headerspace.write(ContextRecordOffset, "\x00" * (ExceptionOffset - ContextRecordOffset))
# Set the "converted" comment
CommentOffset = headerspace.profile.get_obj_offset(header_format, "Comment")
headerspace.write(CommentOffset, "File was converted with Volatility" + "\x00")
# Yield the header
yield 0, headerspace.read(0, headerlen)
# Write the main body
for s, l in pspace.get_available_addresses():
for i in range(s, s + l, blocksize):
yield i + headerlen, pspace.read(i, min(blocksize, s + l - i))
# Reset the config so volatility opens the crash dump
config.LOCATION = "file://" + output
# Crash virtual space
crash_vspace = utils.load_as(config)
# The KDBG in the new crash dump
crash_kdbg = obj.VolMagic(crash_vspace).KDBG.v()
# The KPCR for the first CPU
kpcr = list(crash_kdbg.kpcrs())[0]
# Set the CPU CONTEXT properly for the architecure
if memory_model == "32bit":
kpcr.PrcbData.ProcessorState.ContextFrame.SegGs = 0x00
kpcr.PrcbData.ProcessorState.ContextFrame.SegCs = 0x08
kpcr.PrcbData.ProcessorState.ContextFrame.SegDs = 0x23
kpcr.PrcbData.ProcessorState.ContextFrame.SegEs = 0x23
kpcr.PrcbData.ProcessorState.ContextFrame.SegFs = 0x30
kpcr.PrcbData.ProcessorState.ContextFrame.SegSs = 0x10
else:
kpcr.Prcb.ProcessorState.ContextFrame.SegGs = 0x00
kpcr.Prcb.ProcessorState.ContextFrame.SegCs = 0x18
kpcr.Prcb.ProcessorState.ContextFrame.SegDs = 0x2b
kpcr.Prcb.ProcessorState.ContextFrame.SegEs = 0x2b
kpcr.Prcb.ProcessorState.ContextFrame.SegFs = 0x53
kpcr.Prcb.ProcessorState.ContextFrame.SegSs = 0x18
# Write the decoded KDBG block so Windbg can interpret it properly
if hasattr(kdbg, 'block_encoded') and kdbg.block_encoded:
crash_vspace.write(crash_kdbg.obj_offset, kdbg.obj_vm.data)