# Volatility # Copyright (C) 2007-2013 Volatility Foundation # Copyright (c) 2010, 2011, 2012 Michael Ligh # # 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 . # import re import volatility.obj as obj import volatility.plugins.filescan as filescan import volatility.win32.modules as modules import volatility.win32.tasks as tasks import volatility.utils as utils import volatility.plugins.malware.malfind as malfind import volatility.plugins.overlays.windows.windows as windows #-------------------------------------------------------------------------------- # constants #-------------------------------------------------------------------------------- MAJOR_FUNCTIONS = [ 'IRP_MJ_CREATE', 'IRP_MJ_CREATE_NAMED_PIPE', 'IRP_MJ_CLOSE', 'IRP_MJ_READ', 'IRP_MJ_WRITE', 'IRP_MJ_QUERY_INFORMATION', 'IRP_MJ_SET_INFORMATION', 'IRP_MJ_QUERY_EA', 'IRP_MJ_SET_EA', 'IRP_MJ_FLUSH_BUFFERS', 'IRP_MJ_QUERY_VOLUME_INFORMATION', 'IRP_MJ_SET_VOLUME_INFORMATION', 'IRP_MJ_DIRECTORY_CONTROL', 'IRP_MJ_FILE_SYSTEM_CONTROL', 'IRP_MJ_DEVICE_CONTROL', 'IRP_MJ_INTERNAL_DEVICE_CONTROL', 'IRP_MJ_SHUTDOWN', 'IRP_MJ_LOCK_CONTROL', 'IRP_MJ_CLEANUP', 'IRP_MJ_CREATE_MAILSLOT', 'IRP_MJ_QUERY_SECURITY', 'IRP_MJ_SET_SECURITY', 'IRP_MJ_POWER', 'IRP_MJ_SYSTEM_CONTROL', 'IRP_MJ_DEVICE_CHANGE', 'IRP_MJ_QUERY_QUOTA', 'IRP_MJ_SET_QUOTA', 'IRP_MJ_PNP' ] DEVICE_CODES = { 0x00000027 : 'FILE_DEVICE_8042_PORT', 0x00000032 : 'FILE_DEVICE_ACPI', 0x00000029 : 'FILE_DEVICE_BATTERY', 0x00000001 : 'FILE_DEVICE_BEEP', 0x0000002a : 'FILE_DEVICE_BUS_EXTENDER', 0x00000002 : 'FILE_DEVICE_CD_ROM', 0x00000003 : 'FILE_DEVICE_CD_ROM_FILE_SYSTEM', 0x00000030 : 'FILE_DEVICE_CHANGER', 0x00000004 : 'FILE_DEVICE_CONTROLLER', 0x00000005 : 'FILE_DEVICE_DATALINK', 0x00000006 : 'FILE_DEVICE_DFS', 0x00000035 : 'FILE_DEVICE_DFS_FILE_SYSTEM', 0x00000036 : 'FILE_DEVICE_DFS_VOLUME', 0x00000007 : 'FILE_DEVICE_DISK', 0x00000008 : 'FILE_DEVICE_DISK_FILE_SYSTEM', 0x00000033 : 'FILE_DEVICE_DVD', 0x00000009 : 'FILE_DEVICE_FILE_SYSTEM', 0x0000003a : 'FILE_DEVICE_FIPS', 0x00000034 : 'FILE_DEVICE_FULLSCREEN_VIDEO', 0x0000000a : 'FILE_DEVICE_INPORT_PORT', 0x0000000b : 'FILE_DEVICE_KEYBOARD', 0x0000002f : 'FILE_DEVICE_KS', 0x00000039 : 'FILE_DEVICE_KSEC', 0x0000000c : 'FILE_DEVICE_MAILSLOT', 0x0000002d : 'FILE_DEVICE_MASS_STORAGE', 0x0000000d : 'FILE_DEVICE_MIDI_IN', 0x0000000e : 'FILE_DEVICE_MIDI_OUT', 0x0000002b : 'FILE_DEVICE_MODEM', 0x0000000f : 'FILE_DEVICE_MOUSE', 0x00000010 : 'FILE_DEVICE_MULTI_UNC_PROVIDER', 0x00000011 : 'FILE_DEVICE_NAMED_PIPE', 0x00000012 : 'FILE_DEVICE_NETWORK', 0x00000013 : 'FILE_DEVICE_NETWORK_BROWSER', 0x00000014 : 'FILE_DEVICE_NETWORK_FILE_SYSTEM', 0x00000028 : 'FILE_DEVICE_NETWORK_REDIRECTOR', 0x00000015 : 'FILE_DEVICE_NULL', 0x00000016 : 'FILE_DEVICE_PARALLEL_PORT', 0x00000017 : 'FILE_DEVICE_PHYSICAL_NETCARD', 0x00000018 : 'FILE_DEVICE_PRINTER', 0x00000019 : 'FILE_DEVICE_SCANNER', 0x0000001c : 'FILE_DEVICE_SCREEN', 0x00000037 : 'FILE_DEVICE_SERENUM', 0x0000001a : 'FILE_DEVICE_SERIAL_MOUSE_PORT', 0x0000001b : 'FILE_DEVICE_SERIAL_PORT', 0x00000031 : 'FILE_DEVICE_SMARTCARD', 0x0000002e : 'FILE_DEVICE_SMB', 0x0000001d : 'FILE_DEVICE_SOUND', 0x0000001e : 'FILE_DEVICE_STREAMS', 0x0000001f : 'FILE_DEVICE_TAPE', 0x00000020 : 'FILE_DEVICE_TAPE_FILE_SYSTEM', 0x00000038 : 'FILE_DEVICE_TERMSRV', 0x00000021 : 'FILE_DEVICE_TRANSPORT', 0x00000022 : 'FILE_DEVICE_UNKNOWN', 0x0000002c : 'FILE_DEVICE_VDM', 0x00000023 : 'FILE_DEVICE_VIDEO', 0x00000024 : 'FILE_DEVICE_VIRTUAL_DISK', 0x00000025 : 'FILE_DEVICE_WAVE_IN', 0x00000026 : 'FILE_DEVICE_WAVE_OUT', } #-------------------------------------------------------------------------------- # object classes #-------------------------------------------------------------------------------- class _DRIVER_OBJECT(obj.CType, windows.ExecutiveObjectMixin): "Class for driver objects" def devices(self): "Enumerate the driver's device objects" device = self.DeviceObject.dereference() while device: yield device device = device.NextDevice.dereference() def is_valid(self): return (obj.CType.is_valid(self) and self.DriverStart % 0x1000 == 0) class _DEVICE_OBJECT(obj.CType, windows.ExecutiveObjectMixin): "Class for device objects" def attached_devices(self): "Enumerate the device's attachees" device = self.AttachedDevice.dereference() while device: yield device device = device.AttachedDevice.dereference() #-------------------------------------------------------------------------------- # profile modifications #-------------------------------------------------------------------------------- class MalwareDrivers(obj.ProfileModification): before = ['WindowsObjectClasses'] conditions = {'os': lambda x: x == 'windows'} def modification(self, profile): profile.object_classes.update({ '_DRIVER_OBJECT': _DRIVER_OBJECT, '_DEVICE_OBJECT': _DEVICE_OBJECT, }) #-------------------------------------------------------------------------------- # devicetree plugin #-------------------------------------------------------------------------------- class DeviceTree(filescan.DriverScan): "Show device tree" def render_text(self, outfd, data): for driver in data: header = driver.get_object_header() outfd.write("DRV 0x{0:08x} {1}\n".format(driver.obj_offset, str(driver.DriverName or header.NameInfo.Name or ''))) for device in driver.devices(): device_header = obj.Object("_OBJECT_HEADER", offset = device.obj_offset - device.obj_vm.profile.get_obj_offset("_OBJECT_HEADER", "Body"), vm = device.obj_vm, native_vm = device.obj_native_vm ) device_name = str(device_header.NameInfo.Name or '') outfd.write("---| DEV {0:#x} {1} {2}\n".format( device.obj_offset, device_name, DEVICE_CODES.get(device.DeviceType.v(), "UNKNOWN"))) level = 0 for att_device in device.attached_devices(): device_header = obj.Object("_OBJECT_HEADER", offset = att_device.obj_offset - att_device.obj_vm.profile.get_obj_offset("_OBJECT_HEADER", "Body"), vm = att_device.obj_vm, native_vm = att_device.obj_native_vm ) device_name = str(device_header.NameInfo.Name or '') name = (device_name + " - " + str(att_device.DriverObject.DriverName or '')) outfd.write("------{0}| ATT {1:#x} {2} {3}\n".format( "---" * level, att_device.obj_offset, name, DEVICE_CODES.get(att_device.DeviceType.v(), "UNKNOWN"))) level += 1 #-------------------------------------------------------------------------------- # driverirp plugin #-------------------------------------------------------------------------------- class DriverIrp(filescan.DriverScan): "Driver IRP hook detection" def __init__(self, config, *args, **kwargs): filescan.DriverScan.__init__(self, config, *args, **kwargs) config.add_option("REGEX", short_option = 'r', type = 'str', action = 'store', help = 'Analyze drivers matching REGEX') def render_text(self, outfd, data): addr_space = utils.load_as(self._config) # Compile the regular expression for filtering by driver name if self._config.regex != None: mod_re = re.compile(self._config.regex, re.I) else: mod_re = None mods = dict((addr_space.address_mask(mod.DllBase), mod) for mod in modules.lsmod(addr_space)) mod_addrs = sorted(mods.keys()) bits = addr_space.profile.metadata.get('memory_model', '32bit') self.table_header(None, [('i', ">4"), ('Funcs', "36"), ('addr', '[addrpad]'), ('name', '') ]) for driver in data: header = driver.get_object_header() driver_name = str(header.NameInfo.Name or '') # Continue if a regex was supplied and it doesn't match if mod_re != None: if not (mod_re.search(driver_name) or mod_re.search(driver_name)): continue # Write the standard header for each driver object outfd.write("{0}\n".format("-" * 50)) outfd.write("DriverName: {0}\n".format(driver_name)) outfd.write("DriverStart: {0:#x}\n".format(driver.DriverStart)) outfd.write("DriverSize: {0:#x}\n".format(driver.DriverSize)) outfd.write("DriverStartIo: {0:#x}\n".format(driver.DriverStartIo)) # Write the address and owner of each IRP function for i, function in enumerate(driver.MajorFunction): function = driver.MajorFunction[i] module = tasks.find_module(mods, mod_addrs, addr_space.address_mask(function)) if module: module_name = str(module.BaseDllName or '') else: module_name = "Unknown" # This is where we check for inline hooks once the # ApiHooks plugin is ported to 2.1. self.table_row(outfd, i, MAJOR_FUNCTIONS[i], function, module_name) if self._config.verbose: data = addr_space.zread(function, 64) outfd.write("\n".join( ["{0:#x} {1:<16} {2}".format(o, h, i) for o, i, h in malfind.Disassemble(data = data, start = function, bits = bits, stoponret = True) ])) outfd.write("\n")