Rework the way verinfo works.

This commit is contained in:
Mike Auty
2018-09-13 00:24:57 +01:00
parent 6dc8b4d517
commit 00a7f9ce2d
+47 -71
View File
@@ -33,11 +33,11 @@ class VerInfo(interfaces_plugins.PluginInterface):
requirements.SymbolRequirement(name = "nt_symbols", description = "Windows OS"), ]
@classmethod
def get_version_entries(cls,
context: interfaces.context.ContextInterface,
pe_table_name: str,
layer_name: str,
base_address: int) -> typing.Dict[str, typing.Any]:
def get_version_information(cls,
context: interfaces.context.ContextInterface,
pe_table_name: str,
layer_name: str,
base_address: int) -> typing.Optional[typing.Tuple[int]]:
"""Get File and Product version information from PE files
Args:
@@ -46,45 +46,30 @@ class VerInfo(interfaces_plugins.PluginInterface):
base_address: base address of the PE (where MZ is found)
"""
if layer_name is None:
raise ValueError("Layer must be a string not None")
pe_data = io.BytesIO()
entries = {} # type: typing.Dict[str, typing.Any]
dos_header = context.object(pe_table_name + constants.BANG +
"_IMAGE_DOS_HEADER", offset = base_address,
layer_name = layer_name)
try:
for offset, data in dos_header.reconstruct():
pe_data.seek(offset)
pe_data.write(data)
for offset, data in dos_header.reconstruct():
pe_data.seek(offset)
pe_data.write(data)
pe = pefile.PE(data = pe_data.getvalue(), fast_load = True)
pe.parse_data_directories([pefile.DIRECTORY_ENTRY["IMAGE_DIRECTORY_ENTRY_RESOURCE"]])
pe = pefile.PE(data = pe_data.getvalue(), fast_load = True)
pe.parse_data_directories([pefile.DIRECTORY_ENTRY["IMAGE_DIRECTORY_ENTRY_RESOURCE"]])
entries = {}
major = pe.VS_FIXEDFILEINFO.ProductVersionMS >> 16
minor = pe.VS_FIXEDFILEINFO.ProductVersionMS & 0xFFFF
product = pe.VS_FIXEDFILEINFO.ProductVersionLS >> 16
build = pe.VS_FIXEDFILEINFO.ProductVersionLS & 0xFFFF
for finfo in pe.FileInfo:
if finfo.name == "StringFileInfo":
for table in finfo.StringTable:
entries.update(table.entries)
pe_data.close()
except ValueError:
vollog.log(constants.LOGLEVEL_VVV,
"Error parsing PE at {0:#x} in layer {1}".format(base_address, layer_name))
except AttributeError:
vollog.log(constants.LOGLEVEL_VVV,
"Error locating the string resources for PE at {0:#x} in layer {1}".format(base_address,
layer_name))
except exceptions.InvalidAddressException as exp:
vollog.log(constants.LOGLEVEL_VVV,
"Required data at {0:#x} in layer {1} is unavailable".format(exp.invalid_address, layer_name))
finally:
pe_data.close()
return entries
return (major, minor, product, build)
def _generator(self,
procs: typing.Generator[interfaces.objects.ObjectInterface, None, None],
@@ -110,32 +95,24 @@ class VerInfo(interfaces_plugins.PluginInterface):
BaseDllName = renderers.UnreadableValue()
session_layer_name = moddump.ModDump.find_session_layer(self.context, session_layers, mod.DllBase)
if session_layer_name is None:
file_version = renderers.UnreadableValue()
product_version = renderers.UnreadableValue()
else:
entries = self.get_version_entries(self._context,
pe_table_name,
session_layer_name,
mod.DllBase)
try:
file_version = entries[b"FileVersion"].decode()
except KeyError:
file_version = renderers.UnreadableValue()
try:
product_version = entries[b"ProductVersion"].decode()
except KeyError:
product_version = renderers.UnreadableValue()
(major, minor, product, build) = [renderers.NotAvailableValue()] * 4
try:
(major, minor, product, build) = self.get_version_information(self._context,
pe_table_name,
session_layer_name,
mod.DllBase)
except (exceptions.InvalidAddressException, ValueError, AttributeError):
(major, minor, product, build) = [renderers.UnreadableValue()] * 4
# the pid and process are not applicable for kernel modules
yield (0, (renderers.NotApplicableValue(),
renderers.NotApplicableValue(),
format_hints.Hex(mod.DllBase),
BaseDllName,
file_version,
product_version))
major,
minor,
product,
build))
# now go through the process and dll lists
for proc in procs:
@@ -147,20 +124,15 @@ class VerInfo(interfaces_plugins.PluginInterface):
except exceptions.InvalidAddressException:
BaseDllName = renderers.UnreadableValue()
entries = self.get_version_entries(self._context,
pe_table_name,
proc_layer_name,
entry.DllBase)
session_layer_name = moddump.ModDump.find_session_layer(self.context, session_layers, mod.DllBase)
(major, minor, product, build) = [renderers.NotAvailableValue()] * 4
try:
file_version = entries[b"FileVersion"].decode()
except KeyError:
file_version = renderers.UnreadableValue()
try:
product_version = entries[b"ProductVersion"].decode()
except KeyError:
product_version = renderers.UnreadableValue()
(major, minor, product, build) = self.get_version_information(self._context,
pe_table_name,
proc_layer_name,
entry.DllBase)
except (exceptions.InvalidAddressException, ValueError, AttributeError):
(major, minor, product, build) = [renderers.UnreadableValue()] * 4
yield (0, (proc.UniqueProcessId,
proc.ImageFileName.cast("string",
@@ -168,8 +140,10 @@ class VerInfo(interfaces_plugins.PluginInterface):
errors = "replace"),
format_hints.Hex(entry.DllBase),
BaseDllName,
file_version,
product_version))
major,
minor,
product,
build))
def run(self):
procs = pslist.PsList.list_processes(self.context,
@@ -189,6 +163,8 @@ class VerInfo(interfaces_plugins.PluginInterface):
("Process", str),
("Base", format_hints.Hex),
("Name", str),
("File", str),
("Product", str)],
("Major", int),
("Minor", int),
("Product", int),
("Build", int)],
self._generator(procs, mods, session_layers))