From fffb375909ecb7d4116e5d6807b25183c9691da5 Mon Sep 17 00:00:00 2001 From: Jan Date: Thu, 11 Mar 2021 18:21:30 +0100 Subject: [PATCH 1/7] adds netstat symbols to Win8x64 ISF files --- .../windows/netscan/netscan-win8-x64.json | 189 ++++++++++++++++- .../windows/netscan/netscan-win81-x64.json | 191 +++++++++++++++++- 2 files changed, 377 insertions(+), 3 deletions(-) diff --git a/volatility3/framework/symbols/windows/netscan/netscan-win8-x64.json b/volatility3/framework/symbols/windows/netscan/netscan-win8-x64.json index 993c6a129..0bcf0cc6a 100644 --- a/volatility3/framework/symbols/windows/netscan/netscan-win8-x64.json +++ b/volatility3/framework/symbols/windows/netscan/netscan-win8-x64.json @@ -237,6 +237,16 @@ "kind": "base", "name": "unsigned be short" } + }, + "Next": { + "offset": 136, + "type":{ + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_UDP_ENDPOINT" + } + } } }, "kind": "struct", @@ -256,7 +266,7 @@ } }, "CreateTime": { - "offset": 32, + "offset": 224, "type": { "kind": "union", "name": "_LARGE_INTEGER" @@ -290,6 +300,16 @@ "kind": "base", "name": "unsigned be short" } + }, + "Next": { + "offset": 112, + "type":{ + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_TCP_LISTENER" + } + } } }, "kind": "struct", @@ -503,6 +523,173 @@ }, "kind": "union", "size": 8 + }, + "_INET_COMPARTMENT_SET": { + "fields": { + "InetCompartment": { + "offset": 328, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_INET_COMPARTMENT" + } + } + } + }, + "kind": "struct", + "size": 384 + }, + "_INET_COMPARTMENT": { + "fields": { + "ProtocolCompartment": { + "offset": 32, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_PROTOCOL_COMPARTMENT" + } + } + } + }, + "kind": "struct", + "size": 48 + }, + "_PROTOCOL_COMPARTMENT": { + "fields": { + "PortPool": { + "offset": 0, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_INET_PORT_POOL" + } + } + } + }, + "kind": "struct", + "size": 16 + }, + "_PORT_ASSIGNMENT_ENTRY": { + "fields": { + "Entry": { + "offset": 8, + "type": { + "kind": "pointer", + "subtype": { + "kind": "base", + "name": "void" + } + } + } + }, + "kind": "struct", + "size": 16 + }, + "_PORT_ASSIGNMENT_LIST": { + "fields": { + "Assignments": { + "offset": 0, + "type": { + "count": 256, + "kind": "array", + "subtype": { + "kind": "struct", + "name": "_PORT_ASSIGNMENT_ENTRY" + } + } + } + }, + "kind": "struct", + "size": 4096 + }, + "_PORT_ASSIGNMENT": { + "fields": { + "InPaBigPoolBase": { + "offset": 32, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_PORT_ASSIGNMENT_LIST" + } + } + } + }, + "kind": "struct", + "size": 40 + }, + "_INET_PORT_POOL": { + "fields": { + "PortAssignments": { + "offset": 176, + "type": { + "count": 256, + "kind": "array", + "subtype": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_PORT_ASSIGNMENT" + } + } + } + }, + "PortBitMap": { + "offset": 160, + "type": { + "kind": "struct", + "name": "nt_symbols!_RTL_BITMAP" + } + } + }, + "kind": "struct", + "size": 11200 + }, + "_PARTITION": { + "fields": { + "Endpoints" : { + "offset": 8, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "nt_symbols!_RTL_DYNAMIC_HASH_TABLE" + } + } + }, + "UnknownHashTable" : { + "offset": 16, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "nt_symbols!_RTL_DYNAMIC_HASH_TABLE" + } + } + } + }, + "kind": "struct", + "size": 128 + }, + "_PARTITION_TABLE": { + "fields": { + "Partitions": { + "offset": 0, + "type": { + "count": 1, + "kind": "array", + "subtype": { + "kind": "struct", + "name": "_PARTITION" + } + } + } + }, + "kind": "struct", + "size": 128 } }, "enums": { diff --git a/volatility3/framework/symbols/windows/netscan/netscan-win81-x64.json b/volatility3/framework/symbols/windows/netscan/netscan-win81-x64.json index 80bea7838..6a4d1aee7 100644 --- a/volatility3/framework/symbols/windows/netscan/netscan-win81-x64.json +++ b/volatility3/framework/symbols/windows/netscan/netscan-win81-x64.json @@ -232,11 +232,21 @@ } }, "Port": { - "offset": 128, + "offset": 120, "type": { "kind": "base", "name": "unsigned be short" } + }, + "Next": { + "offset": 112, + "type":{ + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_UDP_ENDPOINT" + } + } } }, "kind": "struct", @@ -256,7 +266,7 @@ } }, "CreateTime": { - "offset": 32, + "offset": 224, "type": { "kind": "union", "name": "_LARGE_INTEGER" @@ -290,6 +300,16 @@ "kind": "base", "name": "unsigned be short" } + }, + "Next": { + "offset": 112, + "type":{ + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_TCP_LISTENER" + } + } } }, "kind": "struct", @@ -503,6 +523,173 @@ }, "kind": "union", "size": 8 + }, + "_INET_COMPARTMENT_SET": { + "fields": { + "InetCompartment": { + "offset": 328, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_INET_COMPARTMENT" + } + } + } + }, + "kind": "struct", + "size": 384 + }, + "_INET_COMPARTMENT": { + "fields": { + "ProtocolCompartment": { + "offset": 32, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_PROTOCOL_COMPARTMENT" + } + } + } + }, + "kind": "struct", + "size": 48 + }, + "_PROTOCOL_COMPARTMENT": { + "fields": { + "PortPool": { + "offset": 0, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_INET_PORT_POOL" + } + } + } + }, + "kind": "struct", + "size": 16 + }, + "_PORT_ASSIGNMENT_ENTRY": { + "fields": { + "Entry": { + "offset": 8, + "type": { + "kind": "pointer", + "subtype": { + "kind": "base", + "name": "void" + } + } + } + }, + "kind": "struct", + "size": 24 + }, + "_PORT_ASSIGNMENT_LIST": { + "fields": { + "Assignments": { + "offset": 0, + "type": { + "count": 256, + "kind": "array", + "subtype": { + "kind": "struct", + "name": "_PORT_ASSIGNMENT_ENTRY" + } + } + } + }, + "kind": "struct", + "size": 6144 + }, + "_PORT_ASSIGNMENT": { + "fields": { + "InPaBigPoolBase": { + "offset": 32, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_PORT_ASSIGNMENT_LIST" + } + } + } + }, + "kind": "struct", + "size": 40 + }, + "_INET_PORT_POOL": { + "fields": { + "PortAssignments": { + "offset": 176, + "type": { + "count": 256, + "kind": "array", + "subtype": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_PORT_ASSIGNMENT" + } + } + } + }, + "PortBitMap": { + "offset": 160, + "type": { + "kind": "struct", + "name": "nt_symbols!_RTL_BITMAP" + } + } + }, + "kind": "struct", + "size": 11200 + }, + "_PARTITION": { + "fields": { + "Endpoints" : { + "offset": 8, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "nt_symbols!_RTL_DYNAMIC_HASH_TABLE" + } + } + }, + "UnknownHashTable" : { + "offset": 16, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "nt_symbols!_RTL_DYNAMIC_HASH_TABLE" + } + } + } + }, + "kind": "struct", + "size": 128 + }, + "_PARTITION_TABLE": { + "fields": { + "Partitions": { + "offset": 0, + "type": { + "count": 1, + "kind": "array", + "subtype": { + "kind": "struct", + "name": "_PARTITION" + } + } + } + }, + "kind": "struct", + "size": 128 } }, "enums": { From 90ad7b1609bd6017cd44a2d11c214bbe5014d407 Mon Sep 17 00:00:00 2001 From: Jan Date: Thu, 11 Mar 2021 19:05:48 +0100 Subject: [PATCH 2/7] reverts pointless createtime offset change --- .../framework/symbols/windows/netscan/netscan-win8-x64.json | 2 +- .../framework/symbols/windows/netscan/netscan-win81-x64.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/volatility3/framework/symbols/windows/netscan/netscan-win8-x64.json b/volatility3/framework/symbols/windows/netscan/netscan-win8-x64.json index 0bcf0cc6a..24873b078 100644 --- a/volatility3/framework/symbols/windows/netscan/netscan-win8-x64.json +++ b/volatility3/framework/symbols/windows/netscan/netscan-win8-x64.json @@ -266,7 +266,7 @@ } }, "CreateTime": { - "offset": 224, + "offset": 64, "type": { "kind": "union", "name": "_LARGE_INTEGER" diff --git a/volatility3/framework/symbols/windows/netscan/netscan-win81-x64.json b/volatility3/framework/symbols/windows/netscan/netscan-win81-x64.json index 6a4d1aee7..d6c51d2db 100644 --- a/volatility3/framework/symbols/windows/netscan/netscan-win81-x64.json +++ b/volatility3/framework/symbols/windows/netscan/netscan-win81-x64.json @@ -266,7 +266,7 @@ } }, "CreateTime": { - "offset": 224, + "offset": 64, "type": { "kind": "union", "name": "_LARGE_INTEGER" From ee65793fd85469b6e969cc42f76959dd4f208f27 Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 17 Mar 2021 19:24:20 +0100 Subject: [PATCH 3/7] adds new ISF for tcpip.sys 6.3.9600.19935 + distinguisher --- .../framework/plugins/windows/netscan.py | 102 ++- .../windows/netscan-win81-19935-x64.json | 723 ++++++++++++++++++ 2 files changed, 784 insertions(+), 41 deletions(-) create mode 100644 volatility3/framework/symbols/windows/netscan-win81-19935-x64.json diff --git a/volatility3/framework/plugins/windows/netscan.py b/volatility3/framework/plugins/windows/netscan.py index 33b5a7fbc..a6eadd505 100644 --- a/volatility3/framework/plugins/windows/netscan.py +++ b/volatility3/framework/plugins/windows/netscan.py @@ -14,7 +14,7 @@ from volatility3.framework.symbols import intermed from volatility3.framework.symbols.windows import versions from volatility3.framework.symbols.windows.extensions import network from volatility3.plugins import timeliner -from volatility3.plugins.windows import info, poolscanner +from volatility3.plugins.windows import info, poolscanner, verinfo vollog = logging.getLogger(__name__) @@ -141,49 +141,55 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface): # furthermore, it is easy to append new versions. if arch == "x86": version_dict = { - (6, 0, 6000): "netscan-vista-x86", - (6, 0, 6001): "netscan-vista-x86", - (6, 0, 6002): "netscan-vista-x86", - (6, 0, 6003): "netscan-vista-x86", - (6, 1, 7600): "netscan-win7-x86", - (6, 1, 7601): "netscan-win7-x86", - (6, 1, 8400): "netscan-win7-x86", - (6, 2, 9200): "netscan-win8-x86", - (6, 3, 9600): "netscan-win81-x86", - (10, 0, 10240): "netscan-win10-10240-x86", - (10, 0, 10586): "netscan-win10-10586-x86", - (10, 0, 14393): "netscan-win10-14393-x86", - (10, 0, 15063): "netscan-win10-15063-x86", - (10, 0, 16299): "netscan-win10-15063-x86", - (10, 0, 17134): "netscan-win10-17134-x86", - (10, 0, 17763): "netscan-win10-17134-x86", - (10, 0, 18362): "netscan-win10-17134-x86", - (10, 0, 18363): "netscan-win10-17134-x86" + (6, 0, 6000, 0): "netscan-vista-x86", + (6, 0, 6001, 0): "netscan-vista-x86", + (6, 0, 6002, 0): "netscan-vista-x86", + (6, 0, 6003, 0): "netscan-vista-x86", + (6, 1, 7600, 0): "netscan-win7-x86", + (6, 1, 7601, 0): "netscan-win7-x86", + (6, 1, 8400, 0): "netscan-win7-x86", + (6, 2, 9200, 0): "netscan-win8-x86", + (6, 3, 9600, 0): "netscan-win81-x86", + (10, 0, 10240, 0): "netscan-win10-10240-x86", + (10, 0, 10586, 0): "netscan-win10-10586-x86", + (10, 0, 14393, 0): "netscan-win10-14393-x86", + (10, 0, 15063, 0): "netscan-win10-15063-x86", + (10, 0, 16299, 0): "netscan-win10-15063-x86", + (10, 0, 17134, 0): "netscan-win10-17134-x86", + (10, 0, 17763, 0): "netscan-win10-17134-x86", + (10, 0, 18362, 0): "netscan-win10-17134-x86", + (10, 0, 18363, 0): "netscan-win10-17134-x86" } else: version_dict = { - (6, 0, 6000): "netscan-vista-x64", - (6, 0, 6001): "netscan-vista-sp12-x64", - (6, 0, 6002): "netscan-vista-sp12-x64", - (6, 0, 6003): "netscan-vista-sp12-x64", - (6, 1, 7600): "netscan-win7-x64", - (6, 1, 7601): "netscan-win7-x64", - (6, 1, 8400): "netscan-win7-x64", - (6, 2, 9200): "netscan-win8-x64", - (6, 3, 9600): "netscan-win81-x64", - (10, 0, 10240): "netscan-win10-x64", - (10, 0, 10586): "netscan-win10-x64", - (10, 0, 14393): "netscan-win10-x64", - (10, 0, 15063): "netscan-win10-15063-x64", - (10, 0, 16299): "netscan-win10-16299-x64", - (10, 0, 17134): "netscan-win10-17134-x64", - (10, 0, 17763): "netscan-win10-17763-x64", - (10, 0, 18362): "netscan-win10-18362-x64", - (10, 0, 18363): "netscan-win10-18363-x64", - (10, 0, 19041): "netscan-win10-19041-x64" + (6, 0, 6000, 0): "netscan-vista-x64", + (6, 0, 6001, 0): "netscan-vista-sp12-x64", + (6, 0, 6002, 0): "netscan-vista-sp12-x64", + (6, 0, 6003, 0): "netscan-vista-sp12-x64", + (6, 1, 7600, 0): "netscan-win7-x64", + (6, 1, 7601, 0): "netscan-win7-x64", + (6, 1, 8400, 0): "netscan-win7-x64", + (6, 2, 9200, 0): "netscan-win8-x64", + (6, 3, 9600, 0): "netscan-win81-x64", + (6, 3, 9600, 19935): "netscan-win81-19935-x64", + (10, 0, 10240, 0): "netscan-win10-x64", + (10, 0, 10586, 0): "netscan-win10-x64", + (10, 0, 14393, 0): "netscan-win10-x64", + (10, 0, 15063, 0): "netscan-win10-15063-x64", + (10, 0, 16299, 0): "netscan-win10-16299-x64", + (10, 0, 17134, 0): "netscan-win10-17134-x64", + (10, 0, 17763, 0): "netscan-win10-17763-x64", + (10, 0, 18362, 0): "netscan-win10-18362-x64", + (10, 0, 18363, 0): "netscan-win10-18363-x64", + (10, 0, 19041, 0): "netscan-win10-19041-x64" } - # special use case: Win10_18363 is not recognized by windows.info as 18363 + # we do not need to check for tcpip's specific FileVersion in every case + tcpip_mod_version = 0 # keep it 0 as a default + + # special use cases + + # Win10_18363 is not recognized by windows.info as 18363 # because all kernel file headers and debug structures report 18363 as # "10.0.18362.1198" with the last part being incremented. However, we can use # os_distinguisher to differentiate between 18362 and 18363 @@ -191,18 +197,30 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface): vollog.debug("Detected 18363 data structures: working with 18363 symbol table.") vers_minor_version = 18363 + # Win 8 SP 1 also may have different structures based on specific tcpip.sys version + if (nt_major_version, nt_minor_version, vers_minor_version) == (6, 3, 9600): + vollog.debug("Requiring further version inspection due to OS version by checking tcpip.sys's FileVersion header") + physical_layer_name = context.layers[layer_name].config.get('memory_layer', None) + ver = verinfo.VerInfo.find_version_info(context, physical_layer_name, "tcpip.sys") + if ver: + tcpip_mod_version = ver[3] + vollog.debug("Determined tcpip.sys's FileVersion: {}".format(tcpip_mod_version)) + else: + vollog.debug("Could not determine tcpip.sys's FileVersion.") + # when determining the symbol file we have to consider the following cases: # the determined version's symbol file is found by intermed.create -> proceed # the determined version's symbol file is not found by intermed -> intermed will throw an exc and abort # the determined version has no mapped symbol file -> if win10 use latest, otherwise throw exc # windows version cannot be determined -> throw exc - filename = version_dict.get((nt_major_version, nt_minor_version, vers_minor_version)) + + filename = version_dict.get((nt_major_version, nt_minor_version, vers_minor_version, tcpip_mod_version)) if not filename: # no match on filename means that we possibly have a version newer than those listed here. # try to grab the latest supported version of the current image NT version. If that symbol # version does not work, support has to be added manually. current_versions = [ - key for key in list(version_dict.keys()) if key[0] == nt_major_version and key[1] == nt_minor_version + (nt_maj, nt_min, vers_min, tcpip_ver) for nt_maj, nt_min, vers_min, tcpip_ver in version_dict if nt_maj == nt_major_version and nt_min == nt_minor_version and tcpip_ver <= tcpip_mod_version ] current_versions.sort() @@ -210,7 +228,9 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface): latest_version = current_versions[-1] filename = version_dict.get(latest_version) + vollog.debug(f"Unable to find exact matching symbol file, going with latest: {filename}") + else: raise NotImplementedError("This version of Windows is not supported: {}.{} {}.{}!".format( nt_major_version, nt_minor_version, vers.MajorVersion, vers_minor_version)) diff --git a/volatility3/framework/symbols/windows/netscan-win81-19935-x64.json b/volatility3/framework/symbols/windows/netscan-win81-19935-x64.json new file mode 100644 index 000000000..f75428613 --- /dev/null +++ b/volatility3/framework/symbols/windows/netscan-win81-19935-x64.json @@ -0,0 +1,723 @@ +{ + "base_types": { + "unsigned long": { + "kind": "int", + "size": 4, + "signed": false, + "endian": "little" + }, + "unsigned char": { + "kind": "char", + "size": 1, + "signed": false, + "endian": "little" + }, + "pointer": { + "kind": "int", + "size": 8, + "signed": false, + "endian": "little" + }, + "unsigned int": { + "kind": "int", + "size": 4, + "signed": false, + "endian": "little" + }, + "unsigned short": { + "kind": "int", + "size": 2, + "signed": false, + "endian": "little" + }, + "unsigned be short": { + "kind": "int", + "size": 2, + "signed": false, + "endian": "big" + }, + "long long": { + "endian": "little", + "kind": "int", + "signed": true, + "size": 8 + }, + "long": { + "kind": "int", + "size": 4, + "signed": false, + "endian": "little" + } + }, + "symbols": {}, + "user_types": { + "_TCP_SYN_ENDPOINT": { + "fields": { + "Owner": { + "offset": 64, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_SYN_OWNER" + } + } + }, + "CreateTime": { + "offset": 0, + "type": { + "kind": "union", + "name": "_LARGE_INTEGER" + } + }, + "ListEntry": { + "offset": 16, + "type": { + "kind": "union", + "name": "nt_symbols!_LIST_ENTRY" + } + }, + "InetAF": { + "offset": 48, + "type":{ + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_INETAF" + } + + } + }, + "LocalPort": { + "offset": 100, + "type": { + "kind": "base", + "name": "unsigned be short" + } + }, + "RemotePort": { + "offset": 102, + "type": { + "kind": "base", + "name": "unsigned be short" + } + }, + "LocalAddr": { + "offset": 56, + "type":{ + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_LOCAL_ADDRESS" + } + } + }, + "RemoteAddress": { + "offset": 80, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_IN_ADDR" + } + } + } + }, + "kind": "struct", + "size": 104 + }, + "_TCP_TIMEWAIT_ENDPOINT": { + "fields": { + "CreateTime": { + "offset": 0, + "type": { + "kind": "union", + "name": "_LARGE_INTEGER" + } + }, + "ListEntry": { + "offset": 0, + "type": { + "kind": "union", + "name": "nt_symbols!_LIST_ENTRY" + } + }, + "InetAF": { + "offset": 24, + "type":{ + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_INETAF" + } + } + }, + "LocalPort": { + "offset": 48, + "type": { + "kind": "base", + "name": "unsigned be short" + } + }, + "RemotePort": { + "offset": 50, + "type": { + "kind": "base", + "name": "unsigned be short" + } + }, + "LocalAddr": { + "offset": 56, + "type":{ + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_LOCAL_ADDRESS" + } + } + }, + "RemoteAddress": { + "offset": 64, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_IN_ADDR" + } + } + } + }, + "kind": "struct", + "size": 72 + }, + "_UDP_ENDPOINT": { + "fields": { + "Owner": { + "offset": 40, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "nt_symbols!_EPROCESS" + } + + } + }, + "CreateTime": { + "offset": 88, + "type": { + "kind": "union", + "name": "_LARGE_INTEGER" + } + }, + "LocalAddr": { + "offset": 96, + "type":{ + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_LOCAL_ADDRESS" + } + } + }, + "InetAF": { + "offset": 32, + "type":{ + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_INETAF" + } + + } + }, + "Port": { + "offset": 120, + "type": { + "kind": "base", + "name": "unsigned be short" + } + }, + "Next": { + "offset": 112, + "type":{ + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_UDP_ENDPOINT" + } + } + } + }, + "kind": "struct", + "size": 130 + }, + "_TCP_LISTENER": { + "fields": { + "Owner": { + "offset": 40, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "nt_symbols!_EPROCESS" + } + + } + }, + "CreateTime": { + "offset": 64, + "type": { + "kind": "union", + "name": "_LARGE_INTEGER" + } + }, + "LocalAddr": { + "offset": 88, + "type":{ + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_LOCAL_ADDRESS" + } + + } + }, + "InetAF": { + "offset": 96, + "type":{ + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_INETAF" + } + + } + }, + "Port": { + "offset": 106, + "type": { + "kind": "base", + "name": "unsigned be short" + } + }, + "Next": { + "offset": 112, + "type":{ + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_TCP_LISTENER" + } + } + } + }, + "kind": "struct", + "size": 108 + }, + "_TCP_ENDPOINT": { + "fields": { + "Owner": { + "offset": 608, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "nt_symbols!_EPROCESS" + } + + } + }, + "CreateTime": { + "offset": 624, + "type": { + "kind": "union", + "name": "_LARGE_INTEGER" + } + }, + "ListEntry": { + "offset": 40, + "type": { + "kind": "union", + "name": "nt_symbols!_LIST_ENTRY" + } + }, + "AddrInfo": { + "offset": 24, + "type":{ + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_ADDRINFO" + } + } + }, + "InetAF": { + "offset": 16, + "type":{ + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_INETAF" + } + + } + }, + "LocalPort": { + "offset": 112, + "type": { + "kind": "base", + "name": "unsigned be short" + } + }, + "RemotePort": { + "offset": 114, + "type": { + "kind": "base", + "name": "unsigned be short" + } + }, + "State": { + "offset": 108, + "type": { + "kind": "enum", + "name": "TCPStateEnum" + } + } + }, + "kind": "struct", + "size": 608 + }, + "_LOCAL_ADDRESS": { + "fields": { + "pData": { + "offset": 16, + "type": { + "kind": "pointer", + "subtype": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_IN_ADDR" + } + } + } + } + }, + "kind": "struct", + "size": 24 + }, + "_ADDRINFO": { + "fields": { + "Local": { + "offset": 0, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_LOCAL_ADDRESS" + } + } + }, + "Remote": { + "offset": 16, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_IN_ADDR" + } + } + } + }, + "kind": "struct", + "size": 24 + }, + "_IN_ADDR": { + "fields": { + "addr4": { + "offset": 0, + "type": { + "count": 4, + "subtype": { + "kind": "base", + "name": "unsigned char" + }, + "kind": "array" + } + }, + "addr6": { + "offset": 0, + "type": { + "count": 16, + "subtype": { + "kind": "base", + "name": "unsigned char" + }, + "kind": "array" + } + } + }, + "kind": "struct", + "size": 6 + }, + "_INETAF": { + "fields": { + "AddressFamily": { + "offset": 24, + "type": { + "kind": "base", + "name": "unsigned short" + } + } + }, + "kind": "struct", + "size": 26 + }, + "_SYN_OWNER": { + "fields": { + "Process": { + "offset": 40, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "nt_symbols!_EPROCESS" + } + } + } + }, + "kind": "struct", + "size": 48 + }, + "_LARGE_INTEGER": { + "fields": { + "HighPart": { + "offset": 4, + "type": { + "kind": "base", + "name": "long" + } + }, + "LowPart": { + "offset": 0, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "QuadPart": { + "offset": 0, + "type": { + "kind": "base", + "name": "long long" + } + }, + "u": { + "offset": 0, + "type": { + "kind": "struct", + "name": "__unnamed_2" + } + } + }, + "kind": "union", + "size": 8 + }, + "_INET_COMPARTMENT_SET": { + "fields": { + "InetCompartment": { + "offset": 328, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_INET_COMPARTMENT" + } + } + } + }, + "kind": "struct", + "size": 384 + }, + "_INET_COMPARTMENT": { + "fields": { + "ProtocolCompartment": { + "offset": 32, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_PROTOCOL_COMPARTMENT" + } + } + } + }, + "kind": "struct", + "size": 48 + }, + "_PROTOCOL_COMPARTMENT": { + "fields": { + "PortPool": { + "offset": 0, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_INET_PORT_POOL" + } + } + } + }, + "kind": "struct", + "size": 16 + }, + "_PORT_ASSIGNMENT_ENTRY": { + "fields": { + "Entry": { + "offset": 8, + "type": { + "kind": "pointer", + "subtype": { + "kind": "base", + "name": "void" + } + } + } + }, + "kind": "struct", + "size": 24 + }, + "_PORT_ASSIGNMENT_LIST": { + "fields": { + "Assignments": { + "offset": 0, + "type": { + "count": 256, + "kind": "array", + "subtype": { + "kind": "struct", + "name": "_PORT_ASSIGNMENT_ENTRY" + } + } + } + }, + "kind": "struct", + "size": 6144 + }, + "_PORT_ASSIGNMENT": { + "fields": { + "InPaBigPoolBase": { + "offset": 24, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_PORT_ASSIGNMENT_LIST" + } + } + } + }, + "kind": "struct", + "size": 32 + }, + "_INET_PORT_POOL": { + "fields": { + "PortAssignments": { + "offset": 216, + "type": { + "count": 256, + "kind": "array", + "subtype": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "_PORT_ASSIGNMENT" + } + } + } + }, + "PortBitMap": { + "offset": 200, + "type": { + "kind": "struct", + "name": "nt_symbols!_RTL_BITMAP" + } + } + }, + "kind": "struct", + "size": 11200 + }, + "_PARTITION": { + "fields": { + "Endpoints" : { + "offset": 8, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "nt_symbols!_RTL_DYNAMIC_HASH_TABLE" + } + } + }, + "UnknownHashTable" : { + "offset": 16, + "type": { + "kind": "pointer", + "subtype": { + "kind": "struct", + "name": "nt_symbols!_RTL_DYNAMIC_HASH_TABLE" + } + } + } + }, + "kind": "struct", + "size": 128 + }, + "_PARTITION_TABLE": { + "fields": { + "Partitions": { + "offset": 0, + "type": { + "count": 1, + "kind": "array", + "subtype": { + "kind": "struct", + "name": "_PARTITION" + } + } + } + }, + "kind": "struct", + "size": 128 + } + }, + "enums": { + "TCPStateEnum": { + "base": "long", + "constants": { + "CLOSED": 0, + "LISTENING": 1, + "SYN_SENT": 2, + "SYN_RCVD": 3, + "ESTABLISHED": 4, + "FIN_WAIT1": 5, + "FIN_WAIT2": 6, + "CLOSE_WAIT": 7, + "CLOSING": 8, + "LAST_ACK": 9, + "TIME_WAIT": 12, + "DELETE_TCB": 13 + }, + "size": 4 + } + }, + "metadata": { + "producer": { + "version": "0.0.1", + "name": "japhlange-by-hand", + "datetime": "2020-06-12T14:00:00" + }, + "format": "6.0.0" + } +} From 3aac7b228e5c3cf11a0ee17f11e07cda8f365d75 Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 17 Mar 2021 21:57:41 +0100 Subject: [PATCH 4/7] adds a few clarifying comments and handles errors better --- volatility3/framework/plugins/windows/netscan.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/volatility3/framework/plugins/windows/netscan.py b/volatility3/framework/plugins/windows/netscan.py index a6eadd505..88f2235dd 100644 --- a/volatility3/framework/plugins/windows/netscan.py +++ b/volatility3/framework/plugins/windows/netscan.py @@ -198,15 +198,19 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface): vers_minor_version = 18363 # Win 8 SP 1 also may have different structures based on specific tcpip.sys version + # the following is IntelLayer specific and might need to be adapted to other architectures. if (nt_major_version, nt_minor_version, vers_minor_version) == (6, 3, 9600): vollog.debug("Requiring further version inspection due to OS version by checking tcpip.sys's FileVersion header") physical_layer_name = context.layers[layer_name].config.get('memory_layer', None) - ver = verinfo.VerInfo.find_version_info(context, physical_layer_name, "tcpip.sys") - if ver: - tcpip_mod_version = ver[3] - vollog.debug("Determined tcpip.sys's FileVersion: {}".format(tcpip_mod_version)) + if physical_layer_name: + ver = verinfo.VerInfo.find_version_info(context, physical_layer_name, "tcpip.sys") + if ver: + tcpip_mod_version = ver[3] + vollog.debug("Determined tcpip.sys's FileVersion: {}".format(tcpip_mod_version)) + else: + vollog.debug("Could not determine tcpip.sys's FileVersion.") else: - vollog.debug("Could not determine tcpip.sys's FileVersion.") + vollog.debug("Unable to retrieve physical memory layer, skipping FileVersion check.") # when determining the symbol file we have to consider the following cases: # the determined version's symbol file is found by intermed.create -> proceed From 6cd2d940f3b5c8cddca25b6a080623932cadc646 Mon Sep 17 00:00:00 2001 From: Jan Date: Thu, 18 Mar 2021 14:21:48 +0100 Subject: [PATCH 5/7] adds proper version requirement for verinfo --- .../framework/plugins/windows/netscan.py | 1 + .../framework/plugins/windows/netstat.py | 4 +- .../framework/plugins/windows/verinfo.py | 204 ------------------ 3 files changed, 4 insertions(+), 205 deletions(-) delete mode 100644 volatility3/framework/plugins/windows/verinfo.py diff --git a/volatility3/framework/plugins/windows/netscan.py b/volatility3/framework/plugins/windows/netscan.py index 88f2235dd..ea66a6b64 100644 --- a/volatility3/framework/plugins/windows/netscan.py +++ b/volatility3/framework/plugins/windows/netscan.py @@ -34,6 +34,7 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface): component = poolscanner.PoolScanner, version = (1, 0, 0)), requirements.VersionRequirement(name = 'info', component = info.Info, version = (1, 0, 0)), + requirements.VersionRequirement(name = 'verinfo', component = verinfo.VerInfo, version = (1, 0, 0)), requirements.BooleanRequirement( name = 'include-corrupt', description = diff --git a/volatility3/framework/plugins/windows/netstat.py b/volatility3/framework/plugins/windows/netstat.py index e71683c10..486957565 100644 --- a/volatility3/framework/plugins/windows/netstat.py +++ b/volatility3/framework/plugins/windows/netstat.py @@ -12,7 +12,7 @@ from volatility3.framework.renderers import format_hints from volatility3.framework.symbols.windows import pdbutil from volatility3.framework.symbols.windows.extensions import network from volatility3.plugins import timeliner -from volatility3.plugins.windows import netscan, modules +from volatility3.plugins.windows import netscan, modules, info, verinfo vollog = logging.getLogger(__name__) @@ -31,6 +31,8 @@ class NetStat(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface): requirements.VersionRequirement(name = 'netscan', component = netscan.NetScan, version = (1, 0, 0)), requirements.VersionRequirement(name = 'modules', component = modules.Modules, version = (1, 0, 0)), requirements.VersionRequirement(name = 'pdbutil', component = pdbutil.PDBUtility, version = (1, 0, 0)), + requirements.VersionRequirement(name = 'info', component = info.Info, version = (1, 0, 0)), + requirements.VersionRequirement(name = 'verinfo', component = verinfo.VerInfo, version = (1, 0, 0)), requirements.BooleanRequirement( name = 'include-corrupt', description = diff --git a/volatility3/framework/plugins/windows/verinfo.py b/volatility3/framework/plugins/windows/verinfo.py deleted file mode 100644 index 762832e39..000000000 --- a/volatility3/framework/plugins/windows/verinfo.py +++ /dev/null @@ -1,204 +0,0 @@ -# This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0 -# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 -# - -import io -import logging -import struct -from typing import Generator, List, Tuple, Optional - -from volatility3.framework import exceptions, renderers, constants, interfaces -from volatility3.framework.configuration import requirements -from volatility3.framework.layers import scanners -from volatility3.framework.renderers import format_hints -from volatility3.framework.symbols import intermed -from volatility3.framework.symbols.windows.extensions import pe -from volatility3.plugins.windows import pslist, modules, dlllist - -vollog = logging.getLogger(__name__) - -try: - import pefile -except ImportError: - vollog.info("Python pefile module not found, plugin (and dependent plugins) not available") - raise - - -class VerInfo(interfaces.plugins.PluginInterface): - """Lists version information from PE files.""" - - _version = (1, 0, 0) - _required_framework_version = (2, 0, 0) - - @classmethod - def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: - ## TODO: we might add a regex option on the name later, but otherwise we're good - ## TODO: and we don't want any CLI options from pslist, modules, or moddump - return [ - requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel', - architectures = ["Intel32", "Intel64"]), - requirements.PluginRequirement(name = 'pslist', plugin = pslist.PsList, version = (2, 0, 0)), - requirements.PluginRequirement(name = 'modules', plugin = modules.Modules, version = (1, 0, 0)), - requirements.VersionRequirement(name = 'dlllist', component = dlllist.DllList, version = (2, 0, 0)), - requirements.BooleanRequirement(name = "extensive", - description = "Search physical layer for version information", - optional = True, - default = False), - ] - - @classmethod - def find_version_info(cls, context: interfaces.context.ContextInterface, layer_name: str, - filename: str) -> Optional[Tuple[int, int, int, int]]: - """Searches for an original filename, then tracks back to find the VS_VERSION_INFO and read the fixed - version information structure""" - premable_max_distance = 0x500 - filename = "OriginalFilename\x00" + filename - iterator = context.layers[layer_name].scan(context = context, - scanner = scanners.BytesScanner(bytes(filename, 'utf-16be'))) - for offset in iterator: - data = context.layers[layer_name].read(offset - premable_max_distance, premable_max_distance) - vs_ver_info = b"\xbd\x04\xef\xfe" - verinfo_offset = data.find(vs_ver_info) + len(vs_ver_info) - if verinfo_offset >= 0: - structure = ' Tuple[int, int, int, int]: - """Get File and Product version information from PE files. - - Args: - context: volatility context on which to operate - pe_table_name: name of the PE table - layer_name: name of the layer containing the PE file - base_address: base address of the PE (where MZ is found) - """ - - if layer_name is None: - raise TypeError("Layer must be a string not None") - - pe_data = io.BytesIO() - - dos_header = context.object(pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER", - offset = base_address, - layer_name = layer_name) - - 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"]]) - - if isinstance(pe.VS_FIXEDFILEINFO, list): - # pefile >= 2018.8.8 (estimated) - version_struct = pe.VS_FIXEDFILEINFO[0] - else: - # pefile <= 2017.11.5 (estimated) - version_struct = pe.VS_FIXEDFILEINFO - - major = version_struct.ProductVersionMS >> 16 - minor = version_struct.ProductVersionMS & 0xFFFF - product = version_struct.ProductVersionLS >> 16 - build = version_struct.ProductVersionLS & 0xFFFF - - pe_data.close() - - return major, minor, product, build - - def _generator(self, procs: Generator[interfaces.objects.ObjectInterface, None, None], - mods: Generator[interfaces.objects.ObjectInterface, None, None], session_layers: Generator[str, None, - None]): - """Generates a list of PE file version info for processes, dlls, and - modules. - - Args: - procs: of processes - mods: of modules - session_layers: of layers in the session to be checked - """ - kernel = self.context.modules[self.config['kernel']] - - pe_table_name = intermed.IntermediateSymbolTable.create(self.context, - self.config_path, - "windows", - "pe", - class_types = pe.class_types) - - # TODO: Fix this so it works with more than just intel layers - physical_layer_name = self.context.layers[kernel.layer_name].config.get('memory_layer', None) - - for mod in mods: - try: - BaseDllName = mod.BaseDllName.get_string() - except exceptions.InvalidAddressException: - BaseDllName = renderers.UnreadableValue() - - session_layer_name = modules.Modules.find_session_layer(self.context, session_layers, mod.DllBase) - try: - (major, minor, product, build) = self.get_version_information(self._context, pe_table_name, - session_layer_name, mod.DllBase) - except (exceptions.InvalidAddressException, TypeError, AttributeError): - (major, minor, product, build) = [renderers.UnreadableValue()] * 4 - if (not isinstance(BaseDllName, renderers.UnreadableValue) and physical_layer_name is not None - and self.config['extensive']): - result = self.find_version_info(self._context, physical_layer_name, BaseDllName) - if result is not None: - (major, minor, product, build) = result - - # the pid and process are not applicable for kernel modules - yield (0, (renderers.NotApplicableValue(), renderers.NotApplicableValue(), format_hints.Hex(mod.DllBase), - BaseDllName, major, minor, product, build)) - - # now go through the process and dll lists - for proc in procs: - proc_id = "Unknown" - try: - proc_id = proc.UniqueProcessId - proc_layer_name = proc.add_process_layer() - except exceptions.InvalidAddressException as excp: - vollog.debug("Process {}: invalid address {} in layer {}".format(proc_id, excp.invalid_address, - excp.layer_name)) - continue - - for entry in proc.load_order_modules(): - - try: - BaseDllName = entry.BaseDllName.get_string() - except exceptions.InvalidAddressException: - BaseDllName = renderers.UnreadableValue() - - try: - DllBase = format_hints.Hex(entry.DllBase) - except exceptions.InvalidAddressException: - DllBase = renderers.UnreadableValue() - - try: - (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", - max_length = proc.ImageFileName.vol.count, - errors = "replace"), DllBase, BaseDllName, major, minor, product, - build)) - - def run(self): - kernel = self.context.modules[self.config['kernel']] - - procs = pslist.PsList.list_processes(self.context, kernel.layer_name, kernel.symbol_table_name) - - mods = modules.Modules.list_modules(self.context, kernel.layer_name, kernel.symbol_table_name) - - # populate the session layers for kernel modules - session_layers = modules.Modules.get_session_layers(self.context, kernel.layer_name, kernel.symbol_table_name) - - return renderers.TreeGrid([("PID", int), ("Process", str), ("Base", format_hints.Hex), ("Name", str), - ("Major", int), ("Minor", int), ("Product", int), ("Build", int)], - self._generator(procs, mods, session_layers)) From be4d014f1a9ca0293784da542bcfef6c7de18161 Mon Sep 17 00:00:00 2001 From: Jan Date: Thu, 18 Mar 2021 18:35:06 +0100 Subject: [PATCH 6/7] improves decision making when to inspect driver pe header based on version_dict --- volatility3/framework/plugins/windows/netscan.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/volatility3/framework/plugins/windows/netscan.py b/volatility3/framework/plugins/windows/netscan.py index ea66a6b64..16301bdd8 100644 --- a/volatility3/framework/plugins/windows/netscan.py +++ b/volatility3/framework/plugins/windows/netscan.py @@ -198,10 +198,12 @@ class NetScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface): vollog.debug("Detected 18363 data structures: working with 18363 symbol table.") vers_minor_version = 18363 - # Win 8 SP 1 also may have different structures based on specific tcpip.sys version - # the following is IntelLayer specific and might need to be adapted to other architectures. - if (nt_major_version, nt_minor_version, vers_minor_version) == (6, 3, 9600): + # we need to define additional version numbers (which are then found via tcpip.sys's FileVersion header) in case there is + # ambiguity _within_ an OS version. If such a version number (last number of the tuple) is defined for the current OS + # we need to inspect tcpip.sys's headers to see if we can grab the precise version + if [ (a,b,c,d) for a, b, c, d in version_dict if (a,b,c) == (nt_major_version, nt_minor_version, vers_minor_version) and d != 0]: vollog.debug("Requiring further version inspection due to OS version by checking tcpip.sys's FileVersion header") + # the following is IntelLayer specific and might need to be adapted to other architectures. physical_layer_name = context.layers[layer_name].config.get('memory_layer', None) if physical_layer_name: ver = verinfo.VerInfo.find_version_info(context, physical_layer_name, "tcpip.sys") From 125658ee0da64716d7e4f1d0b24bbac237f78ef7 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 6 Dec 2021 21:09:39 +0100 Subject: [PATCH 7/7] re-adds accidentally deleted file --- .../framework/plugins/windows/verinfo.py | 205 ++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 volatility3/framework/plugins/windows/verinfo.py diff --git a/volatility3/framework/plugins/windows/verinfo.py b/volatility3/framework/plugins/windows/verinfo.py new file mode 100644 index 000000000..70d473d2e --- /dev/null +++ b/volatility3/framework/plugins/windows/verinfo.py @@ -0,0 +1,205 @@ +# This file is Copyright 2019 Volatility Foundation and licensed under the Volatility Software License 1.0 +# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 +# + +import io +import logging +import struct +from typing import Generator, List, Tuple, Optional + +from volatility3.framework import exceptions, renderers, constants, interfaces +from volatility3.framework.configuration import requirements +from volatility3.framework.layers import scanners +from volatility3.framework.renderers import format_hints +from volatility3.framework.symbols import intermed +from volatility3.framework.symbols.windows.extensions import pe +from volatility3.plugins.windows import pslist, modules, dlllist + +vollog = logging.getLogger(__name__) + +try: + import pefile +except ImportError: + vollog.info("Python pefile module not found, plugin (and dependent plugins) not available") + raise + + +class VerInfo(interfaces.plugins.PluginInterface): + """Lists version information from PE files.""" + + _version = (1, 0, 0) + _required_framework_version = (2, 0, 0) + + @classmethod + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: + ## TODO: we might add a regex option on the name later, but otherwise we're good + ## TODO: and we don't want any CLI options from pslist, modules, or moddump + return [ + requirements.ModuleRequirement(name = 'kernel', description = 'Windows kernel', + architectures = ["Intel32", "Intel64"]), + requirements.PluginRequirement(name = 'pslist', plugin = pslist.PsList, version = (2, 0, 0)), + requirements.PluginRequirement(name = 'modules', plugin = modules.Modules, version = (1, 0, 0)), + requirements.VersionRequirement(name = 'dlllist', component = dlllist.DllList, version = (2, 0, 0)), + requirements.BooleanRequirement(name = "extensive", + description = "Search physical layer for version information", + optional = True, + default = False), + ] + + @classmethod + def find_version_info(cls, context: interfaces.context.ContextInterface, layer_name: str, + filename: str) -> Optional[Tuple[int, int, int, int]]: + """Searches for an original filename, then tracks back to find the VS_VERSION_INFO and read the fixed + version information structure""" + premable_max_distance = 0x500 + filename = "OriginalFilename\x00" + filename + iterator = context.layers[layer_name].scan(context = context, + scanner = scanners.BytesScanner(bytes(filename, 'utf-16be'))) + for offset in iterator: + data = context.layers[layer_name].read(offset - premable_max_distance, premable_max_distance) + vs_ver_info = b"\xbd\x04\xef\xfe" + verinfo_offset = data.find(vs_ver_info) + len(vs_ver_info) + if verinfo_offset >= 0: + structure = ' Tuple[int, int, int, int]: + """Get File and Product version information from PE files. + + Args: + context: volatility context on which to operate + pe_table_name: name of the PE table + layer_name: name of the layer containing the PE file + base_address: base address of the PE (where MZ is found) + """ + + if layer_name is None: + raise TypeError("Layer must be a string not None") + + pe_data = io.BytesIO() + + dos_header = context.object(pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER", + offset = base_address, + layer_name = layer_name) + + 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"]]) + + if isinstance(pe.VS_FIXEDFILEINFO, list): + # pefile >= 2018.8.8 (estimated) + version_struct = pe.VS_FIXEDFILEINFO[0] + else: + # pefile <= 2017.11.5 (estimated) + version_struct = pe.VS_FIXEDFILEINFO + + major = version_struct.ProductVersionMS >> 16 + minor = version_struct.ProductVersionMS & 0xFFFF + product = version_struct.ProductVersionLS >> 16 + build = version_struct.ProductVersionLS & 0xFFFF + + pe_data.close() + + return major, minor, product, build + + def _generator(self, procs: Generator[interfaces.objects.ObjectInterface, None, None], + mods: Generator[interfaces.objects.ObjectInterface, None, None], session_layers: Generator[str, None, + None]): + """Generates a list of PE file version info for processes, dlls, and + modules. + + Args: + procs: of processes + mods: of modules + session_layers: of layers in the session to be checked + """ + kernel = self.context.modules[self.config['kernel']] + + pe_table_name = intermed.IntermediateSymbolTable.create(self.context, + self.config_path, + "windows", + "pe", + class_types = pe.class_types) + + # TODO: Fix this so it works with more than just intel layers + physical_layer_name = self.context.layers[kernel.layer_name].config.get('memory_layer', None) + + for mod in mods: + try: + BaseDllName = mod.BaseDllName.get_string() + except exceptions.InvalidAddressException: + BaseDllName = renderers.UnreadableValue() + + session_layer_name = modules.Modules.find_session_layer(self.context, session_layers, mod.DllBase) + try: + (major, minor, product, build) = self.get_version_information(self._context, pe_table_name, + session_layer_name, mod.DllBase) + except (exceptions.InvalidAddressException, TypeError, AttributeError): + (major, minor, product, build) = [renderers.UnreadableValue()] * 4 + if (not isinstance(BaseDllName, renderers.UnreadableValue) and physical_layer_name is not None + and self.config['extensive']): + result = self.find_version_info(self._context, physical_layer_name, BaseDllName) + if result is not None: + (major, minor, product, build) = result + + # the pid and process are not applicable for kernel modules + yield (0, (renderers.NotApplicableValue(), renderers.NotApplicableValue(), format_hints.Hex(mod.DllBase), + BaseDllName, major, minor, product, build)) + + # now go through the process and dll lists + for proc in procs: + proc_id = "Unknown" + try: + proc_id = proc.UniqueProcessId + proc_layer_name = proc.add_process_layer() + except exceptions.InvalidAddressException as excp: + vollog.debug("Process {}: invalid address {} in layer {}".format(proc_id, excp.invalid_address, + excp.layer_name)) + continue + + for entry in proc.load_order_modules(): + + try: + BaseDllName = entry.BaseDllName.get_string() + except exceptions.InvalidAddressException: + BaseDllName = renderers.UnreadableValue() + + try: + DllBase = format_hints.Hex(entry.DllBase) + except exceptions.InvalidAddressException: + DllBase = renderers.UnreadableValue() + + try: + (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", + max_length = proc.ImageFileName.vol.count, + errors = "replace"), DllBase, BaseDllName, major, minor, product, + build)) + + def run(self): + kernel = self.context.modules[self.config['kernel']] + + procs = pslist.PsList.list_processes(self.context, kernel.layer_name, kernel.symbol_table_name) + + mods = modules.Modules.list_modules(self.context, kernel.layer_name, kernel.symbol_table_name) + + # populate the session layers for kernel modules + session_layers = modules.Modules.get_session_layers(self.context, kernel.layer_name, kernel.symbol_table_name) + + return renderers.TreeGrid([("PID", int), ("Process", str), ("Base", format_hints.Hex), ("Name", str), + ("Major", int), ("Minor", int), ("Product", int), ("Build", int)], + self._generator(procs, mods, session_layers)) +