yapf and some corrections

This commit is contained in:
AsafEitani
2020-08-31 17:05:20 +01:00
committed by ikelos
parent 81d346438a
commit 7ab72a1066
33 changed files with 213 additions and 255 deletions
+4 -4
View File
@@ -69,6 +69,7 @@ def multitypedata_as_text(value: format_hints.MultiTypeData) -> str:
def optional(func):
@wraps(func)
def wrapped(x: Any) -> str:
if isinstance(x, interfaces.renderers.BaseAbsentValue):
@@ -82,6 +83,7 @@ def optional(func):
def quoted_optional(func):
@wraps(func)
def wrapped(x: Any) -> str:
result = optional(func)(x)
@@ -264,8 +266,7 @@ class PrettyTextRenderer(CLIRenderer):
max_column_widths = dict([(column.name, len(column.name)) for column in grid.columns])
def visitor(
node: interfaces.renderers.TreeNode,
accumulator: List[Tuple[int, Dict[interfaces.renderers.Column, bytes]]]
node: interfaces.renderers.TreeNode, accumulator: List[Tuple[int, Dict[interfaces.renderers.Column, bytes]]]
) -> List[Tuple[int, Dict[interfaces.renderers.Column, bytes]]]:
# Nodes always have a path value, giving them a path_depth of at least 1, we use max just in case
max_column_widths[tree_indent_column] = max(max_column_widths.get(tree_indent_column, 0), node.path_depth)
@@ -327,8 +328,7 @@ class JsonRenderer(CLIRenderer):
{}, []) # type: Tuple[Dict[str, List[interfaces.renderers.TreeNode]], List[interfaces.renderers.TreeNode]]
def visitor(
node: interfaces.renderers.TreeNode,
accumulator: Tuple[Dict[str, Dict[str, Any]], List[Dict[str, Any]]]
node: interfaces.renderers.TreeNode, accumulator: Tuple[Dict[str, Dict[str, Any]], List[Dict[str, Any]]]
) -> Tuple[Dict[str, Dict[str, Any]], List[Dict[str, Any]]]:
# Nodes always have a path value, giving them a path_depth of at least 1, we use max just in case
acc_map, final_tree = accumulator
@@ -89,7 +89,8 @@ class SymbolFinder(interfaces.automagic.AutomagicInterface):
# Check if the Stacker has already found what we're looking for
if layer.config.get(self.banner_config_key, None):
banner_list = [(0, bytes(layer.config[self.banner_config_key], 'raw_unicode_escape'))] # type: Iterable[Any]
banner_list = [(0, bytes(layer.config[self.banner_config_key],
'raw_unicode_escape'))] # type: Iterable[Any]
else:
# Swap to the physical layer for scanning
# TODO: Fix this so it works for layers other than just Intel
@@ -300,8 +300,7 @@ class TranslationLayerRequirement(interfaces.configuration.ConstructableRequirem
args = {"context": context, "config_path": config_path, "name": name}
if any(
[subreq.unsatisfied(context, config_path) for subreq in self.requirements.values() if
not subreq.optional]):
[subreq.unsatisfied(context, config_path) for subreq in self.requirements.values() if not subreq.optional]):
return None
obj = self._construct_class(context, config_path, args)
@@ -356,8 +355,7 @@ class SymbolTableRequirement(interfaces.configuration.ConstructableRequirementIn
args = {"context": context, "config_path": config_path, "name": name}
if any(
[subreq.unsatisfied(context, config_path) for subreq in self.requirements.values() if
not subreq.optional]):
[subreq.unsatisfied(context, config_path) for subreq in self.requirements.values() if not subreq.optional]):
return None
# Fill out the parameter for class creation
@@ -2,5 +2,3 @@
"""
+3 -4
View File
@@ -33,7 +33,6 @@ except ImportError:
vollog = logging.getLogger(__name__)
# TODO: Type-annotating the ResourceAccessor.open method is difficult because HTTPResponse is not actually an IO[Any] type
# fix this
@@ -117,9 +116,9 @@ class ResourceAccessor(object):
else:
# TODO: find a way to check if we already have this file (look at http headers?)
block_size = 1028 * 8
temp_filename = os.path.join(constants.CACHE_PATH,
"data_" + hashlib.sha512(
bytes(url, 'raw_unicode_escape')).hexdigest() + ".cache")
temp_filename = os.path.join(
constants.CACHE_PATH,
"data_" + hashlib.sha512(bytes(url, 'raw_unicode_escape')).hexdigest() + ".cache")
if not os.path.exists(temp_filename):
vollog.debug("Caching file at: {}".format(temp_filename))
+7 -7
View File
@@ -93,6 +93,7 @@ class IsfInfo(plugins.PluginInterface):
def check_valid(data):
return "True" if schemas.validate(data, True) else "False"
except ImportError:
def check_valid(data):
return "Unknown"
@@ -116,14 +117,13 @@ class IsfInfo(plugins.PluginInterface):
valid = check_valid(data)
except (UnicodeDecodeError, json.decoder.JSONDecodeError):
vollog.warning("Invalid ISF: {}".format(entry))
yield (0, (entry, valid, num_bases, num_types, num_symbols, num_enums,
windows_info, linux_banner, mac_banner))
yield (0, (entry, valid, num_bases, num_types, num_symbols, num_enums, windows_info, linux_banner,
mac_banner))
# Try to open the file, load it as JSON, read the data from it
def run(self):
return renderers.TreeGrid(
[("URI", str), ("Valid", str),
("Number of base_types", int), ("Number of types", int), ("Number of symbols", int),
("Number of enums", int), ("Windows info", str), ("Linux banner", str), ("Mac banner", str)],
self._generator())
return renderers.TreeGrid([("URI", str), ("Valid", str),
("Number of base_types", int), ("Number of types", int), ("Number of symbols", int),
("Number of enums", int), ("Windows info", str), ("Linux banner", str),
("Mac banner", str)], self._generator())
@@ -23,7 +23,6 @@ class Check_idt(interfaces.plugins.PluginInterface):
requirements.TranslationLayerRequirement(name = 'primary',
description = 'Memory layer for the kernel',
architectures = ["Intel32", "Intel64"]),
requirements.SymbolTableRequirement(name = "vmlinux", description = "Linux kernel symbols"),
requirements.VersionRequirement(name = 'linuxutils', component = linux.LinuxUtilities, version = (1, 0, 0)),
requirements.PluginRequirement(name = 'lsmod', plugin = lsmod.Lsmod, version = (1, 0, 0))
@@ -61,7 +60,9 @@ class Check_idt(interfaces.plugins.PluginInterface):
addrs = vmlinux.object_from_symbol("idt_table")
table = vmlinux.object(object_type = 'array', offset = addrs.vol.offset, subtype = vmlinux.get_type(idt_type),
table = vmlinux.object(object_type = 'array',
offset = addrs.vol.offset,
subtype = vmlinux.get_type(idt_type),
count = idt_table_size)
for i in check_idxs:
@@ -90,6 +91,5 @@ class Check_idt(interfaces.plugins.PluginInterface):
yield (0, [format_hints.Hex(i), format_hints.Hex(idt_addr), module_name, symbol_name])
def run(self):
return renderers.TreeGrid(
[("Index", format_hints.Hex), ("Address", format_hints.Hex), ("Module", str), ("Symbol", str)],
self._generator())
return renderers.TreeGrid([("Index", format_hints.Hex), ("Address", format_hints.Hex), ("Module", str),
("Symbol", str)], self._generator())
+7 -8
View File
@@ -143,13 +143,12 @@ class Timeliner(interfaces.plugins.PluginInterface):
# Body format is: MD5|name|inode|mode_as_string|UID|GID|size|atime|mtime|ctime|crtime
if self._any_time_present(times):
fp.write(
"|{} - {}||||||{}|{}|{}|{}\n".format(
plugin_name, self._sanitize_body_format(item),
self._text_format(times.get(TimeLinerType.ACCESSED, "")),
self._text_format(times.get(TimeLinerType.MODIFIED, "")),
self._text_format(times.get(TimeLinerType.CHANGED, "")),
self._text_format(times.get(TimeLinerType.CREATED, ""))))
fp.write("|{} - {}||||||{}|{}|{}|{}\n".format(
plugin_name, self._sanitize_body_format(item),
self._text_format(times.get(TimeLinerType.ACCESSED, "")),
self._text_format(times.get(TimeLinerType.MODIFIED, "")),
self._text_format(times.get(TimeLinerType.CHANGED, "")),
self._text_format(times.get(TimeLinerType.CREATED, ""))))
self.produce_file(filedata)
def _sanitize_body_format(self, value):
@@ -188,7 +187,7 @@ class Timeliner(interfaces.plugins.PluginInterface):
if isinstance(plugin, TimeLinerInterface):
if not len(filter_list) or any(
[filter in plugin.__module__ + '.' + plugin.__class__.__name__ for filter in filter_list]):
[filter in plugin.__module__ + '.' + plugin.__class__.__name__ for filter in filter_list]):
plugins_to_run.append(plugin)
except exceptions.UnsatisfiedException as excp:
# Remove the failed plugin from the list and continue
@@ -21,14 +21,14 @@ class Cachedump(interfaces.plugins.PluginInterface):
@classmethod
def get_requirements(cls):
return [requirements.TranslationLayerRequirement(name = 'primary',
description = 'Memory layer for the kernel',
architectures = ["Intel32", "Intel64"]),
requirements.SymbolTableRequirement(name = "nt_symbols",
description = "Windows kernel symbols"),
requirements.PluginRequirement(name = 'hivelist', plugin = hivelist.HiveList, version = (1, 0, 0)),
requirements.PluginRequirement(name = 'lsadump', plugin = lsadump.Lsadump, version = (1, 0, 0))
]
return [
requirements.TranslationLayerRequirement(name = 'primary',
description = 'Memory layer for the kernel',
architectures = ["Intel32", "Intel64"]),
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
requirements.PluginRequirement(name = 'hivelist', plugin = hivelist.HiveList, version = (1, 0, 0)),
requirements.PluginRequirement(name = 'lsadump', plugin = lsadump.Lsadump, version = (1, 0, 0))
]
def get_nlkm(self, sechive, lsakey, is_vista_or_later):
return lsadump.Lsadump.get_secret_by_name(sechive, 'NL$KM', lsakey, is_vista_or_later)
@@ -44,7 +44,7 @@ class Cachedump(interfaces.plugins.PluginInterface):
aes = AES.new(nlkm[16:32], AES.MODE_CBC, ch)
data = ""
for i in range(0, len(edata), 16):
buf = edata[i: i + 16]
buf = edata[i:i + 16]
if len(buf) < 16:
buf += (16 - len(buf)) * "\00"
data += aes.decrypt(buf)
@@ -54,13 +54,12 @@ class Cachedump(interfaces.plugins.PluginInterface):
(uname_len, domain_len) = unpack("<HH", cache_data[:4])
if len(cache_data[60:62]) == 0:
return (uname_len, domain_len, 0, '', '')
(domain_name_len,) = unpack("<H", cache_data[60:62])
(domain_name_len, ) = unpack("<H", cache_data[60:62])
ch = cache_data[64:80]
enc_data = cache_data[96:]
return (uname_len, domain_len, domain_name_len, enc_data, ch)
def parse_decrypted_cache(self, dec_data, uname_len,
domain_len, domain_name_len):
def parse_decrypted_cache(self, dec_data, uname_len, domain_len, domain_name_len):
"""Get the data from the cache and separate it into the username, domain name, and hash data"""
uname_offset = 72
pad = 2 * ((uname_len / 2) % 2)
@@ -103,16 +102,14 @@ class Cachedump(interfaces.plugins.PluginInterface):
data = sechive.read(cache_item.Data + 4, cache_item.DataLength)
if data == None:
continue
(uname_len, domain_len, domain_name_len,
enc_data, ch) = self.parse_cache_entry(data)
(uname_len, domain_len, domain_name_len, enc_data, ch) = self.parse_cache_entry(data)
# Skip if nothing in this cache entry
if uname_len == 0 or len(ch) == 0:
continue
dec_data = self.decrypt_hash(enc_data, nlkm, ch, not vista_or_later)
(username, domain, domain_name,
hashh) = self.parse_decrypted_cache(dec_data, uname_len,
domain_len, domain_name_len)
(username, domain, domain_name, hashh) = self.parse_decrypted_cache(dec_data, uname_len, domain_len,
domain_name_len)
yield (0, (username, domain, domain_name, hashh))
def run(self):
@@ -33,8 +33,7 @@ class CmdLine(interfaces.plugins.PluginInterface):
]
@classmethod
def get_cmdline(cls, context: interfaces.context.ContextInterface,
kernel_table_name: str, proc):
def get_cmdline(cls, context: interfaces.context.ContextInterface, kernel_table_name: str, proc):
"""Extracts the cmdline from PEB
Args:
+13 -12
View File
@@ -68,8 +68,8 @@ class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
if layer_name is None:
layer_name = dll_entry.vol.layer_name
filedata = interfaces.plugins.FileInterface(
"{0}.{1:#x}.{2:#x}.dmp".format(ntpath.basename(name), dll_entry.vol.offset, dll_entry.DllBase))
filedata = interfaces.plugins.FileInterface("{0}.{1:#x}.{2:#x}.dmp".format(
ntpath.basename(name), dll_entry.vol.offset, dll_entry.DllBase))
dos_header = context.object(pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER",
offset = dll_entry.DllBase,
@@ -92,7 +92,7 @@ class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
kuser = info.Info.get_kuser_structure(self.context, self.config['primary'], self.config['nt_symbols'])
nt_major_version = int(kuser.NtMajorVersion)
nt_minor_version = int(kuser.NtMinorVersion)
# this only applies to versions higher or equal to Window 7 (6.1 and higher)
# LoadTime only applies to versions higher or equal to Window 7 (6.1 and higher)
dll_load_time_field = (nt_major_version > 6) or (nt_major_version == 6 and nt_minor_version >= 1)
for proc in procs:
@@ -110,13 +110,15 @@ class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
pass
if dll_load_time_field:
# Versions prior to 6.1 won't have the LoadTime attribute
# and 32bit version shouldn't have the Quadpart according to MSDN
try:
DllLoadTime = conversion.wintime_to_datetime(entry.LoadTime.QuadPart)
except:
except AttributeError:
pass
dumped = False
if self.config.get('dump'):
if self.config['dump']:
filedata = self.dump_pe(self.context, pe_table_name, entry, proc_layer_name)
if filedata:
filedata.preferred_filename = "pid.{0}.".format(proc_id) + filedata.preferred_filename
@@ -130,16 +132,15 @@ class DllList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
format_hints.Hex(entry.SizeOfImage), BaseDllName, FullDllName, DllLoadTime, dumped))
def generate_timeline(self):
for row in self._generator(pslist.PsList.list_processes(context = self.context,
layer_name = self.config['primary'],
symbol_table = self.config['nt_symbols'],
filter_func = pslist.PsList.create_pid_filter(None))):
for row in self._generator(
pslist.PsList.list_processes(context = self.context,
layer_name = self.config['primary'],
symbol_table = self.config['nt_symbols'])):
_depth, row_data = row
if not isinstance(row_data[6], datetime.datetime):
continue
description = "DLL Load: Process {} {} Loaded {} ({}) Size {} Offset {}".format(row_data[0], row_data[1],
row_data[4], row_data[5],
row_data[3], row_data[2])
description = "DLL Load: Process {} {} Loaded {} ({}) Size {} Offset {}".format(
row_data[0], row_data[1], row_data[4], row_data[5], row_data[3], row_data[2])
yield (description, timeliner.TimeLinerType.CREATED, row_data[6])
def run(self):
@@ -58,8 +58,4 @@ class FileScan(interfaces.plugins.PluginInterface):
yield (0, (format_hints.Hex(fileobj.vol.offset), file_name, fileobj.Size))
def run(self):
return renderers.TreeGrid([
("Offset", format_hints.Hex),
("Name", str),
("Size", int)
], self._generator())
return renderers.TreeGrid([("Offset", format_hints.Hex), ("Name", str), ("Size", int)], self._generator())
+12 -15
View File
@@ -23,13 +23,13 @@ class Lsadump(interfaces.plugins.PluginInterface):
@classmethod
def get_requirements(cls):
return [requirements.TranslationLayerRequirement(name = 'primary',
description = 'Memory layer for the kernel',
architectures = ["Intel32", "Intel64"]),
requirements.SymbolTableRequirement(name = "nt_symbols",
description = "Windows kernel symbols"),
requirements.PluginRequirement(name = 'hivelist', plugin = hivelist.HiveList, version = (1, 0, 0))
]
return [
requirements.TranslationLayerRequirement(name = 'primary',
description = 'Memory layer for the kernel',
architectures = ["Intel32", "Intel64"]),
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
requirements.PluginRequirement(name = 'hivelist', plugin = hivelist.HiveList, version = (1, 0, 0))
]
@classmethod
def decrypt_aes(cls, secret, key):
@@ -45,7 +45,7 @@ class Lsadump(interfaces.plugins.PluginInterface):
data = b""
for i in range(60, len(secret), 16):
aes = AES.new(aeskey, AES.MODE_CBC, b'\x00' * 16)
buf = secret[i: i + 16]
buf = secret[i:i + 16]
if len(buf) < 16:
buf += (16 - len(buf)) * "\00"
data += aes.decrypt(buf)
@@ -100,8 +100,7 @@ class Lsadump(interfaces.plugins.PluginInterface):
if not enc_secret_value:
return None
enc_secret = sechive.read(enc_secret_value.Data + 4,
enc_secret_value.DataLength)
enc_secret = sechive.read(enc_secret_value.Data + 4, enc_secret_value.DataLength)
if not enc_secret:
return None
@@ -131,7 +130,7 @@ class Lsadump(interfaces.plugins.PluginInterface):
if len(key[j:j + 7]) < 7:
j = len(key[j:j + 7])
(dec_data_len,) = unpack("<L", decrypted_data[:4])
(dec_data_len, ) = unpack("<L", decrypted_data[:4])
return decrypted_data[8:8 + dec_data_len]
@@ -161,8 +160,7 @@ class Lsadump(interfaces.plugins.PluginInterface):
if not enc_secret_value:
continue
enc_secret = sechive.read(enc_secret_value.Data + 4,
enc_secret_value.DataLength)
enc_secret = sechive.read(enc_secret_value.Data + 4, enc_secret_value.DataLength)
if not enc_secret:
continue
if not vista_or_later:
@@ -187,5 +185,4 @@ class Lsadump(interfaces.plugins.PluginInterface):
if hive.get_name().split('\\')[-1].upper() == 'SECURITY':
sechive = hive
return renderers.TreeGrid([("Key", str), ("Secret", str), ('Hex', bytes)],
self._generator(syshive, sechive))
return renderers.TreeGrid([("Key", str), ("Secret", str), ('Hex', bytes)], self._generator(syshive, sechive))
+19 -21
View File
@@ -21,20 +21,20 @@ class Malfind(interfaces.plugins.PluginInterface):
def get_requirements(cls):
# Since we're calling the plugin, make sure we have the plugin's requirements
return [
requirements.TranslationLayerRequirement(name='primary',
description='Memory layer for the kernel',
architectures=["Intel32", "Intel64"]),
requirements.SymbolTableRequirement(name="nt_symbols", description="Windows kernel symbols"),
requirements.ListRequirement(name='pid',
element_type=int,
description="Process IDs to include (all other processes are excluded)",
optional=True),
requirements.BooleanRequirement(name='dump',
description="Extract injected VADs",
default=False,
optional=True),
requirements.VersionRequirement(name='pslist', component=pslist.PsList, version=(1, 1, 0)),
requirements.VersionRequirement(name='vadinfo', component=vadinfo.VadInfo, version=(1, 1, 0))
requirements.TranslationLayerRequirement(name = 'primary',
description = 'Memory layer for the kernel',
architectures = ["Intel32", "Intel64"]),
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
requirements.ListRequirement(name = 'pid',
element_type = int,
description = "Process IDs to include (all other processes are excluded)",
optional = True),
requirements.BooleanRequirement(name = 'dump',
description = "Extract injected VADs",
default = False,
optional = True),
requirements.VersionRequirement(name = 'pslist', component = pslist.PsList, version = (1, 1, 0)),
requirements.VersionRequirement(name = 'vadinfo', component = vadinfo.VadInfo, version = (1, 1, 0))
]
@classmethod
@@ -66,8 +66,6 @@ class Malfind(interfaces.plugins.PluginInterface):
return True
@classmethod
def list_injections(
cls, context: interfaces.context.ContextInterface, kernel_layer_name: str, symbol_table: str,
@@ -139,16 +137,16 @@ class Malfind(interfaces.plugins.PluginInterface):
self.produce_file(filedata)
dumped = True
except Exception as excp:
vollog.debug("Unable to dump PE with pid {0}.{1:#x}: {2}".format(proc.UniqueProcessId,
vad.get_start(), excp))
vollog.debug("Unable to dump PE with pid {0}.{1:#x}: {2}".format(
proc.UniqueProcessId, vad.get_start(), excp))
yield (0, (proc.UniqueProcessId, process_name, format_hints.Hex(vad.get_start()),
format_hints.Hex(vad.get_end()), vad.get_tag(),
vad.get_protection(
vadinfo.VadInfo.protect_values(self.context, self.config["primary"],
self.config["nt_symbols"]), vadinfo.winnt_protections),
vad.get_commit_charge(), vad.get_private_memory(), dumped, format_hints.HexBytes(data),
disasm))
self.config["nt_symbols"]),
vadinfo.winnt_protections), vad.get_commit_charge(), vad.get_private_memory(), dumped,
format_hints.HexBytes(data), disasm))
def run(self):
filter_func = pslist.PsList.create_pid_filter(self.config.get('pid', None))
+13 -18
View File
@@ -42,8 +42,8 @@ class Memmap(interfaces.plugins.PluginInterface):
proc_layer_name = proc.add_process_layer()
proc_layer = self.context.layers[proc_layer_name]
except exceptions.InvalidAddressException as excp:
vollog.debug("Process {}: invalid address {} in layer {}".format(
pid, excp.invalid_address, excp.layer_name))
vollog.debug("Process {}: invalid address {} in layer {}".format(pid, excp.invalid_address,
excp.layer_name))
continue
filedata = interfaces.plugins.FileInterface("pid.{}.dmp".format(pid))
@@ -58,15 +58,11 @@ class Memmap(interfaces.plugins.PluginInterface):
filedata.data.write(data)
dumped = True
except exceptions.InvalidAddressException:
vollog.debug("Unable to write {}'s address {} to {}.dmp".format(proc_layer_name, offset,
filedata.preferred_filename))
vollog.debug("Unable to write {}'s address {} to {}.dmp".format(
proc_layer_name, offset, filedata.preferred_filename))
yield (0, (
format_hints.Hex(offset),
format_hints.Hex(mapped_offset),
format_hints.Hex(mapped_size),
format_hints.Hex(offset),
dumped))
yield (0, (format_hints.Hex(offset), format_hints.Hex(mapped_offset), format_hints.Hex(mapped_size),
format_hints.Hex(offset), dumped))
offset += mapped_size
self.produce_file(filedata)
@@ -74,11 +70,10 @@ class Memmap(interfaces.plugins.PluginInterface):
def run(self):
filter_func = pslist.PsList.create_pid_filter([self.config.get('pid', None)])
return renderers.TreeGrid(
[("Virtual", format_hints.Hex), ("Physical", format_hints.Hex), ("Size", format_hints.Hex),
("Offset", format_hints.Hex), ("Dumped", bool)],
self._generator(
pslist.PsList.list_processes(context = self.context,
layer_name = self.config['primary'],
symbol_table = self.config['nt_symbols'],
filter_func = filter_func)))
return renderers.TreeGrid([("Virtual", format_hints.Hex), ("Physical", format_hints.Hex),
("Size", format_hints.Hex), ("Offset", format_hints.Hex), ("Dumped", bool)],
self._generator(
pslist.PsList.list_processes(context = self.context,
layer_name = self.config['primary'],
symbol_table = self.config['nt_symbols'],
filter_func = filter_func)))
@@ -22,7 +22,8 @@ class ModScan(interfaces.plugins.PluginInterface):
description = 'Memory layer for the kernel',
architectures = ["Intel32", "Intel64"]),
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
requirements.VersionRequirement(name = 'poolerscanner', component = poolscanner.PoolScanner,
requirements.VersionRequirement(name = 'poolerscanner',
component = poolscanner.PoolScanner,
version = (1, 0, 0)),
requirements.VersionRequirement(name = 'dlllist', component = dlllist.DllList, version = (1, 0, 0)),
requirements.BooleanRequirement(name = 'dump',
@@ -81,14 +82,8 @@ class ModScan(interfaces.plugins.PluginInterface):
self.produce_file(filedata)
dumped = True
yield (0, (
format_hints.Hex(mod.vol.offset),
format_hints.Hex(mod.DllBase),
format_hints.Hex(mod.SizeOfImage),
BaseDllName,
FullDllName,
dumped
))
yield (0, (format_hints.Hex(mod.vol.offset), format_hints.Hex(mod.DllBase),
format_hints.Hex(mod.SizeOfImage), BaseDllName, FullDllName, dumped))
def run(self):
return renderers.TreeGrid([("Offset", format_hints.Hex), ("Base", format_hints.Hex), ("Size", format_hints.Hex),
@@ -62,14 +62,8 @@ class Modules(interfaces.plugins.PluginInterface):
self.produce_file(filedata)
dumped = True
yield (0, (
format_hints.Hex(mod.vol.offset),
format_hints.Hex(mod.DllBase),
format_hints.Hex(mod.SizeOfImage),
BaseDllName,
FullDllName,
dumped
))
yield (0, (format_hints.Hex(mod.vol.offset), format_hints.Hex(mod.DllBase),
format_hints.Hex(mod.SizeOfImage), BaseDllName, FullDllName, dumped))
@classmethod
def get_session_layers(cls,
+44 -58
View File
@@ -16,6 +16,7 @@ from volatility.plugins.windows import info, poolscanner
vollog = logging.getLogger(__name__)
class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
"""Scans for network objects present in a particular windows memory image."""
@@ -28,17 +29,21 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
description = 'Memory layer for the kernel',
architectures = ["Intel32", "Intel64"]),
requirements.SymbolTableRequirement(name = "nt_symbols", description = "Windows kernel symbols"),
requirements.VersionRequirement(name='poolscanner', component=poolscanner.PoolScanner, version=(1, 0, 0)),
requirements.VersionRequirement(name='info', component=info.Info, version=(1, 0, 0)),
requirements.BooleanRequirement(name = 'include-corrupt',
description = "Radically eases result validation. This will show partially overwritten data. WARNING: the results are likely to include garbage and/or corrupt data. Be cautious!",
requirements.VersionRequirement(name = 'poolscanner',
component = poolscanner.PoolScanner,
version = (1, 0, 0)),
requirements.VersionRequirement(name = 'info', component = info.Info, version = (1, 0, 0)),
requirements.BooleanRequirement(
name = 'include-corrupt',
description =
"Radically eases result validation. This will show partially overwritten data. WARNING: the results are likely to include garbage and/or corrupt data. Be cautious!",
default = False,
optional = True
),
optional = True),
]
@staticmethod
def create_netscan_constraints(context: interfaces.context.ContextInterface, symbol_table: str) -> List[poolscanner.PoolConstraint]:
def create_netscan_constraints(context: interfaces.context.ContextInterface,
symbol_table: str) -> List[poolscanner.PoolConstraint]:
"""Creates a list of Pool Tag Constraints for network objects.
Args:
@@ -74,10 +79,8 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
]
@classmethod
def determine_tcpip_version(cls,
context: interfaces.context.ContextInterface,
layer_name: str,
nt_symbol_table: str) -> str:
def determine_tcpip_version(cls, context: interfaces.context.ContextInterface, layer_name: str,
nt_symbol_table: str) -> str:
"""Tries to determine which symbol filename to use for the image's tcpip driver. The logic is partially taken from the info plugin.
Args:
@@ -116,10 +119,11 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
except:
# unsure what to raise here. Also, it might be useful to add some kind of fallback,
# either to a user-provided version or to another method to determine tcpip.sys's version
raise exceptions.VolatilityException("Kernel Debug Structure missing VERSION/KUSER structure, unable to determine Windows version!")
raise exceptions.VolatilityException(
"Kernel Debug Structure missing VERSION/KUSER structure, unable to determine Windows version!")
vollog.debug("Determined OS Version: {}.{} {}.{}".format(kuser.NtMajorVersion, kuser.NtMinorVersion,
vers.MajorVersion, vers.MinorVersion))
vollog.debug("Determined OS Version: {}.{} {}.{}".format(kuser.NtMajorVersion, kuser.NtMinorVersion,
vers.MajorVersion, vers.MinorVersion))
if nt_major_version == 10 and arch == "x64":
# win10 x64 has an additional class type we have to include.
@@ -127,9 +131,9 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
else:
# default to general class types
class_types = network.class_types
# these versions are listed explicitly because symbol files differ based on
# version *and* architecture. this is currently the clearest way to show
# these versions are listed explicitly because symbol files differ based on
# version *and* architecture. this is currently the clearest way to show
# the differences, even if it introduces a fair bit of redundancy.
# furthermore, it is easy to append new versions.
if arch == "x86":
@@ -192,21 +196,16 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
filename = version_dict.get(latest_version)
vollog.debug("Unable to find exact matching symbol file, going with latest: {}".format(filename))
else:
raise NotImplementedError("This version of Windows is not supported: {}.{} {}.{}!".format(nt_major_version,
nt_minor_version,
vers.MajorVersion,
vers_minor_version))
raise NotImplementedError("This version of Windows is not supported: {}.{} {}.{}!".format(
nt_major_version, nt_minor_version, vers.MajorVersion, vers_minor_version))
vollog.debug("Determined symbol filename: {}".format(filename))
return filename, class_types
@classmethod
def create_netscan_symbol_table(cls,
context: interfaces.context.ContextInterface,
layer_name: str,
nt_symbol_table: str,
config_path: str) -> str:
def create_netscan_symbol_table(cls, context: interfaces.context.ContextInterface, layer_name: str,
nt_symbol_table: str, config_path: str) -> str:
"""Creates a symbol table for TCP Listeners and TCP/UDP Endpoints.
Args:
@@ -262,10 +261,8 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
def _generator(self, show_corrupt_results: Optional[bool] = None):
""" Generates the network objects for use in rendering. """
netscan_symbol_table = self.create_netscan_symbol_table(self.context,
self.config["primary"],
self.config["nt_symbols"],
self.config_path)
netscan_symbol_table = self.create_netscan_symbol_table(self.context, self.config["primary"],
self.config["nt_symbols"], self.config_path)
for netw_obj in self.scan(self.context, self.config['primary'], self.config['nt_symbols'],
netscan_symbol_table):
@@ -280,14 +277,10 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
# For UdpA, the state is always blank and the remote end is asterisks
for ver, laddr, _ in netw_obj.dual_stack_sockets():
yield (0, (format_hints.Hex(netw_obj.vol.offset),
"UDP" + ver,
laddr,
netw_obj.Port,
"*", 0, "",
netw_obj.get_owner_pid() or renderers.UnreadableValue(),
netw_obj.get_owner_procname() or renderers.UnreadableValue(),
netw_obj.get_create_time() or renderers.UnreadableValue()))
yield (0, (format_hints.Hex(netw_obj.vol.offset), "UDP" + ver, laddr, netw_obj.Port, "*", 0, "",
netw_obj.get_owner_pid() or renderers.UnreadableValue(), netw_obj.get_owner_procname()
or renderers.UnreadableValue(), netw_obj.get_create_time()
or renderers.UnreadableValue()))
elif isinstance(netw_obj, network._TCP_ENDPOINT):
vollog.debug("Found _TCP_ENDPOINT @ 0x{:2x}".format(netw_obj.vol.offset))
@@ -303,14 +296,10 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
except ValueError:
state = renderers.UnreadableValue()
yield (0, (format_hints.Hex(netw_obj.vol.offset), proto,
netw_obj.get_local_address() or renderers.UnreadableValue(),
netw_obj.LocalPort,
netw_obj.get_remote_address() or renderers.UnreadableValue(),
netw_obj.RemotePort,
state,
netw_obj.get_owner_pid() or renderers.UnreadableValue(),
netw_obj.get_owner_procname() or renderers.UnreadableValue(),
yield (0, (format_hints.Hex(netw_obj.vol.offset), proto, netw_obj.get_local_address()
or renderers.UnreadableValue(), netw_obj.LocalPort, netw_obj.get_remote_address()
or renderers.UnreadableValue(), netw_obj.RemotePort, state, netw_obj.get_owner_pid()
or renderers.UnreadableValue(), netw_obj.get_owner_procname() or renderers.UnreadableValue(),
netw_obj.get_create_time() or renderers.UnreadableValue()))
# check for isinstance of tcp listener last, because all other objects are inherited from here
@@ -319,15 +308,10 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
# For TcpL, the state is always listening and the remote port is zero
for ver, laddr, raddr in netw_obj.dual_stack_sockets():
yield (0, (format_hints.Hex(netw_obj.vol.offset), "TCP" + ver,
laddr,
netw_obj.Port,
raddr,
0,
"LISTENING",
netw_obj.get_owner_pid() or renderers.UnreadableValue(),
netw_obj.get_owner_procname() or renderers.UnreadableValue(),
netw_obj.get_create_time() or renderers.UnreadableValue()))
yield (0, (format_hints.Hex(netw_obj.vol.offset), "TCP" + ver, laddr, netw_obj.Port, raddr, 0,
"LISTENING", netw_obj.get_owner_pid() or renderers.UnreadableValue(),
netw_obj.get_owner_procname() or renderers.UnreadableValue(), netw_obj.get_create_time()
or renderers.UnreadableValue()))
else:
# this should not happen therefore we log it.
vollog.debug("Found network object unsure of its type: {} of type {}".format(netw_obj, type(netw_obj)))
@@ -338,8 +322,10 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
# Skip network connections without creation time
if not isinstance(row_data[9], datetime.datetime):
continue
row_data = ["N/A" if isinstance(i, renderers.UnreadableValue) or isinstance(i, renderers.UnparsableValue)
else i for i in row_data]
row_data = [
"N/A" if isinstance(i, renderers.UnreadableValue) or isinstance(i, renderers.UnparsableValue) else i
for i in row_data
]
description = "Network connection: Process {} {} Local Address {}:{} " \
"Remote Address {}:{} State {} Protocol {} ".format(row_data[7], row_data[8],
row_data[2], row_data[3],
@@ -361,4 +347,4 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
("PID", int),
("Owner", str),
("Created", datetime.datetime),
], self._generator(show_corrupt_results=show_corrupt_results))
], self._generator(show_corrupt_results = show_corrupt_results))
@@ -386,13 +386,14 @@ class PoolScanner(plugins.PluginInterface):
else:
class_type = extensions.pool.POOL_HEADER
table_name = intermed.IntermediateSymbolTable.create(
context = context,
config_path = configuration.path_join(context.symbol_space[symbol_table].config_path, "poolheader"),
sub_path = "windows",
filename = pool_header_json_filename,
table_mapping = {'nt_symbols': symbol_table},
class_types = {'_POOL_HEADER': class_type})
table_name = intermed.IntermediateSymbolTable.create(context = context,
config_path = configuration.path_join(
context.symbol_space[symbol_table].config_path,
"poolheader"),
sub_path = "windows",
filename = pool_header_json_filename,
table_mapping = {'nt_symbols': symbol_table},
class_types = {'_POOL_HEADER': class_type})
return table_name
def run(self) -> renderers.TreeGrid:
@@ -209,5 +209,4 @@ class PsList(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface):
("Offset{0}".format(offsettype), format_hints.Hex), ("Threads", int),
("Handles", int), ("SessionId", int), ("Wow64", bool),
("CreateTime", datetime.datetime), ("ExitTime", datetime.datetime),
("Dumped", bool)],
self._generator())
("Dumped", bool)], self._generator())
@@ -56,7 +56,6 @@ class HiveList(interfaces.plugins.PluginInterface):
description = "Extract listed registry hives",
default = False,
optional = True)
]
def _sanitize_hive_name(self, name: str) -> str:
@@ -73,11 +72,12 @@ class HiveList(interfaces.plugins.PluginInterface):
dumped = False
if self.config['dump']:
# Construct the hive
hive = next(self.list_hives(self.context,
self.config_path,
layer_name = self.config["primary"],
symbol_table = self.config["nt_symbols"],
hive_offsets = [hive_object.vol.offset]))
hive = next(
self.list_hives(self.context,
self.config_path,
layer_name = self.config["primary"],
symbol_table = self.config["nt_symbols"],
hive_offsets = [hive_object.vol.offset]))
maxaddr = hive.hive.Storage[0].Length
hive_name = self._sanitize_hive_name(hive.get_name())
@@ -69,7 +69,7 @@ class HiveScan(interfaces.plugins.PluginInterface):
def _generator(self):
for hive in self.scan_hives(self.context, self.config['primary'], self.config['nt_symbols']):
yield (0, (format_hints.Hex(hive.vol.offset),))
yield (0, (format_hints.Hex(hive.vol.offset), ))
def run(self):
return renderers.TreeGrid([("Offset", format_hints.Hex)], self._generator())
@@ -43,10 +43,10 @@ class PrintKey(interfaces.plugins.PluginInterface):
@classmethod
def key_iterator(
cls,
hive: RegistryHive,
node_path: Sequence[objects.StructType] = None,
recurse: bool = False
cls,
hive: RegistryHive,
node_path: Sequence[objects.StructType] = None,
recurse: bool = False
) -> Iterable[Tuple[int, bool, datetime.datetime, str, bool, interfaces.objects.ObjectInterface]]:
"""Walks through a set of nodes from a given node (last one in
node_path). Avoids loops by not traversing into nodes already present
@@ -75,8 +75,7 @@ class SvcScan(interfaces.plugins.PluginInterface):
symbol_filename = "services-win10-15063-x86"
elif versions.is_windows_8_or_later(context = context, symbol_table = symbol_table) and is_64bit:
symbol_filename = "services-win8-x64"
elif versions.is_windows_8_or_later(context = context,
symbol_table = symbol_table) and not is_64bit:
elif versions.is_windows_8_or_later(context = context, symbol_table = symbol_table) and not is_64bit:
symbol_filename = "services-win8-x86"
elif versions.is_vista_or_later(context = context, symbol_table = symbol_table) and is_64bit:
symbol_filename = "services-vista-x64"
@@ -132,7 +132,7 @@ class VadInfo(interfaces.plugins.PluginInterface):
offset = vad_start
while offset < vad_end:
to_read = min(chunk_size, vad_end - offset)
data = proc_layer.read(offset, to_read, pad=True)
data = proc_layer.read(offset, to_read, pad = True)
if not data:
break
filedata.data.write(data)
@@ -109,8 +109,8 @@ class VerInfo(interfaces.plugins.PluginInterface):
session_layer_name = modules.Modules.find_session_layer(self.context, session_layers, mod.DllBase)
(major, minor, product, build) = [
renderers.NotAvailableValue()
] * 4 # type: Tuple[Union[int, interfaces.renderers.BaseAbsentValue],Union[int, interfaces.renderers.BaseAbsentValue],Union[int, interfaces.renderers.BaseAbsentValue],Union[int, interfaces.renderers.BaseAbsentValue]]
renderers.NotAvailableValue()
] * 4 # type: Tuple[Union[int, interfaces.renderers.BaseAbsentValue],Union[int, interfaces.renderers.BaseAbsentValue],Union[int, interfaces.renderers.BaseAbsentValue],Union[int, interfaces.renderers.BaseAbsentValue]]
try:
(major, minor, product, build) = self.get_version_information(self._context, pe_table_name,
session_layer_name, mod.DllBase)
@@ -6,6 +6,7 @@ from typing import Dict, Tuple
from volatility.framework import constants
from volatility.framework import objects, interfaces
class elf(objects.StructType):
'''
Class used to create elf objects. It overrides the typename to `Elf32_` or `Elf64_`,
@@ -16,7 +16,6 @@ from volatility.framework.symbols.windows.extensions import pool
vollog = logging.getLogger(__name__)
# Keep these in a basic module, to prevent import cycles when symbol providers require them
@@ -17,6 +17,7 @@ from typing import Dict, Tuple
vollog = logging.getLogger(__name__)
def inet_ntop(address_family: int, packed_ip: Array) -> str:
def inet_ntop4(packed_ip: Array) -> str:
@@ -68,6 +69,7 @@ def inet_ntop(address_family: int, packed_ip: Array) -> str:
return inet_ntop6(packed_ip)
raise socket.error("[Errno 97] Address family not supported by protocol")
# Python's socket.AF_INET6 is 0x1e but Microsoft defines it
# as a constant value of 0x17 in their source code. Thus we
# need Microsoft's since that's what is found in memory.
@@ -78,6 +80,7 @@ AF_INET6 = 0x17
inaddr_any = inet_ntop(socket.AF_INET, [0] * 4)
inaddr6_any = inet_ntop(socket.AF_INET6, [0] * 16)
class _TCP_LISTENER(objects.StructType):
"""Class for objects found in TcpL pools.
@@ -132,8 +135,9 @@ class _TCP_LISTENER(objects.StructType):
def get_owner_procname(self):
if self.get_owner().is_valid():
if self.get_owner().has_valid_member("ImageFileName"):
return self.get_owner().ImageFileName.cast(
"string", max_length = self.get_owner().ImageFileName.vol.count, errors = "replace")
return self.get_owner().ImageFileName.cast("string",
max_length = self.get_owner().ImageFileName.vol.count,
errors = "replace")
return None
@@ -196,6 +200,7 @@ class _TCP_LISTENER(objects.StructType):
return False
return True
class _TCP_ENDPOINT(_TCP_LISTENER):
"""Class for objects found in TcpE pools"""
@@ -237,7 +242,8 @@ class _TCP_ENDPOINT(_TCP_LISTENER):
vollog.debug("invalid due to invalid address_family {}".format(self.get_address_family()))
return False
if not self.get_local_address() and (not self.get_owner() or self.get_owner().UniqueProcessId == 0 or self.get_owner().UniqueProcessId > 65535):
if not self.get_local_address() and (not self.get_owner() or self.get_owner().UniqueProcessId == 0
or self.get_owner().UniqueProcessId > 65535):
vollog.debug("invalid due to invalid owner data")
return False
@@ -247,21 +253,25 @@ class _TCP_ENDPOINT(_TCP_LISTENER):
return True
class _UDP_ENDPOINT(_TCP_LISTENER):
"""Class for objects found in UdpA pools"""
class _LOCAL_ADDRESS(objects.StructType):
@property
def inaddr(self):
return self.pData.dereference().dereference()
class _LOCAL_ADDRESS_WIN10_UDP(objects.StructType):
@property
def inaddr(self):
return self.pData.dereference()
win10_x64_class_types = {
'_TCP_ENDPOINT': _TCP_ENDPOINT,
'_TCP_LISTENER': _TCP_LISTENER,
@@ -39,11 +39,11 @@ class POOL_HEADER(objects.StructType):
# because symbol_table_name will be different from kernel_symbol_table.
if kernel_symbol_table:
object_header_type = self._context.symbol_space.get_type(kernel_symbol_table + constants.BANG +
"_OBJECT_HEADER")
"_OBJECT_HEADER")
else:
# otherwise symbol_table_name *is* the kernel symbol table, so just use that.
object_header_type = self._context.symbol_space.get_type(symbol_table_name + constants.BANG +
"_OBJECT_HEADER")
"_OBJECT_HEADER")
pool_header_size = self.vol.size
@@ -160,8 +160,8 @@ class POOL_HEADER(objects.StructType):
headers = []
sizes = []
for header in [
'CREATOR_INFO', 'NAME_INFO', 'HANDLE_INFO', 'QUOTA_INFO', 'PROCESS_INFO', 'AUDIT_INFO', 'EXTENDED_INFO',
'HANDLE_REVOCATION_INFO', 'PADDING_INFO'
'CREATOR_INFO', 'NAME_INFO', 'HANDLE_INFO', 'QUOTA_INFO', 'PROCESS_INFO', 'AUDIT_INFO', 'EXTENDED_INFO',
'HANDLE_REVOCATION_INFO', 'PADDING_INFO'
]:
try:
type_name = "{}{}_OBJECT_HEADER_{}".format(symbol_table_name, constants.BANG, header)
+11 -13
View File
@@ -265,7 +265,8 @@ class PdbReader:
if not progress_callback:
progress_callback = lambda x, y: None
self._progress_callback = progress_callback
self.types = [] # type: List[Tuple[interfaces.objects.ObjectInterface, Optional[str], interfaces.objects.ObjectInterface]]
self.types = [
] # type: List[Tuple[interfaces.objects.ObjectInterface, Optional[str], interfaces.objects.ObjectInterface]]
self.bases = {} # type: Dict[str, Any]
self.user_types = {} # type: Dict[str, Any]
self.enumerations = {} # type: Dict[str, Any]
@@ -619,8 +620,8 @@ class PdbReader:
else:
leaf_type, name, value = self.types[index - 0x1000]
if leaf_type in [
leaf_type.LF_UNION, leaf_type.LF_CLASS, leaf_type.LF_CLASS_ST, leaf_type.LF_STRUCTURE,
leaf_type.LF_STRUCTURE_ST, leaf_type.LF_INTERFACE
leaf_type.LF_UNION, leaf_type.LF_CLASS, leaf_type.LF_CLASS_ST, leaf_type.LF_STRUCTURE,
leaf_type.LF_STRUCTURE_ST, leaf_type.LF_INTERFACE
]:
if not value.properties.forward_reference:
result = value.size
@@ -664,8 +665,8 @@ class PdbReader:
self._progress_callback(index * 100 / max_len, "Processing types")
leaf_type, name, value = self.types[index]
if leaf_type in [
leaf_type.LF_CLASS, leaf_type.LF_CLASS_ST, leaf_type.LF_STRUCTURE, leaf_type.LF_STRUCTURE_ST,
leaf_type.LF_INTERFACE
leaf_type.LF_CLASS, leaf_type.LF_CLASS_ST, leaf_type.LF_STRUCTURE, leaf_type.LF_STRUCTURE_ST,
leaf_type.LF_INTERFACE
]:
if not value.properties.forward_reference and name:
self.user_types[name] = {
@@ -692,17 +693,16 @@ class PdbReader:
self.enumerations[name] = {
'base': base['name'],
'size': self.get_size_from_index(value.subtype_index),
'constants':
dict([(name, enum.value) for _, name, enum in constants])
'constants': dict([(name, enum.value) for _, name, enum in constants])
}
# Re-run through for ForwardSizeReferences
self.user_types = self.replace_forward_references(self.user_types, type_references)
def consume_type(
self, module: interfaces.context.ModuleInterface, offset: int, length: int
self, module: interfaces.context.ModuleInterface, offset: int, length: int
) -> Tuple[Tuple[Optional[interfaces.objects.ObjectInterface], Optional[str], Union[
None, List, interfaces.objects.ObjectInterface]], int]:
None, List, interfaces.objects.ObjectInterface]], int]:
"""Returns a (leaf_type, name, object) Tuple for a type, and the number
of bytes consumed."""
result = None, None, None # type: Tuple[Optional[interfaces.objects.ObjectInterface], Optional[str], Optional[Union[List, interfaces.objects.ObjectInterface]]]
@@ -713,8 +713,8 @@ class PdbReader:
remaining = length - consumed
if leaf_type in [
leaf_type.LF_CLASS, leaf_type.LF_CLASS_ST, leaf_type.LF_STRUCTURE, leaf_type.LF_STRUCTURE_ST,
leaf_type.LF_INTERFACE
leaf_type.LF_CLASS, leaf_type.LF_CLASS_ST, leaf_type.LF_STRUCTURE, leaf_type.LF_STRUCTURE_ST,
leaf_type.LF_INTERFACE
]:
structure = module.object(object_type = "LF_STRUCTURE", offset = offset + consumed)
name_offset = structure.name.vol.offset - structure.vol.offset
@@ -914,7 +914,6 @@ class PdbRetreiver:
if __name__ == '__main__':
import argparse
class PrintedProgress(object):
"""A progress handler that prints the progress value and the
description onto the command line."""
@@ -935,7 +934,6 @@ if __name__ == '__main__':
self._max_message_len = max([self._max_message_len, message_len])
print(message, end = (' ' * (self._max_message_len - message_len)) + '\r')
parser = argparse.ArgumentParser(
description = "Read PDB files and convert to Volatility 3 Intermediate Symbol Format")
parser.add_argument("-o", "--output", metavar = "OUTPUT", help = "Filename for data output", required = True)
@@ -31,8 +31,8 @@ class OsDistinguisher:
A function that takes a context and a symbol table name and determines whether that symbol table passes the distinguishing checks
"""
def __init__(self, version_check: Callable[[Tuple[int, ...]], bool],
fallback_checks: List[Tuple[str, Optional[str], bool]]):
def __init__(self, version_check: Callable[[Tuple[int, ...]], bool], fallback_checks: List[Tuple[str, Optional[str],
bool]]):
self._version_check = version_check
self._fallback_checks = fallback_checks
@@ -59,7 +59,7 @@ class OsDistinguisher:
for name, member, response in self._fallback_checks:
if member is None:
if (context.symbol_space.has_symbol(symbol_table + constants.BANG + name)
or context.symbol_space.has_type(symbol_table + constants.BANG + name)) != response:
or context.symbol_space.has_type(symbol_table + constants.BANG + name)) != response:
return False
else:
try:
@@ -80,8 +80,7 @@ is_vista_or_later = OsDistinguisher(version_check = lambda x: x >= (6, 0),
fallback_checks = [("KdCopyDataBlock", None, True)])
is_win10 = OsDistinguisher(version_check = lambda x: (10, 0) <= x,
fallback_checks = [("ObHeaderCookie", None, True),
("_HANDLE_TABLE", "HandleCount", False)])
fallback_checks = [("ObHeaderCookie", None, True), ("_HANDLE_TABLE", "HandleCount", False)])
is_windows_xp = OsDistinguisher(version_check = lambda x: (5, 1) <= x < (5, 2),
fallback_checks = [("KdCopyDataBlock", None, False),
@@ -106,8 +105,7 @@ is_win10_16299_or_later = OsDistinguisher(version_check = lambda x: x >= (10, 0,
fallback_checks = [("ObHeaderCookie", None, True),
("_HANDLE_TABLE", "HandleCount", False),
("_EPROCESS", "KeepAliveCounter", False),
("_EPROCESS", "ControlFlowGuardEnabled",
False)])
("_EPROCESS", "ControlFlowGuardEnabled", False)])
is_windows_10 = OsDistinguisher(version_check = lambda x: x >= (10, 0),
fallback_checks = [("ObHeaderCookie", None, True)])
@@ -40,8 +40,8 @@ class Certificates(interfaces.plugins.PluginInterface):
symbol_table = self.config['nt_symbols']):
for top_key in [
"Microsoft\\SystemCertificates",
"Software\\Microsoft\\SystemCertificates",
"Microsoft\\SystemCertificates",
"Software\\Microsoft\\SystemCertificates",
]:
try:
# Walk it