Files
Andrew Janke 1a5861dbac Doco: update Google Code references to new locations
Also fix capitalization of "Windows" and "Mach-O" in a couple places.
2015-11-12 00:23:03 -05:00

968 lines
43 KiB
Python

# Volatility
# Copyright (C) 2007-2013 Volatility Foundation
# Copyright (c) 2012 Jamie Levy (Gleeda) <jamie@memoryanalysis.net>
#
# This file is part of Volatility.
#
# Volatility is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Volatility is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Volatility. If not, see <http://www.gnu.org/licenses/>.
#
"""
@author: Jamie Levy (Gleeda)
@license: GNU General Public License 2.0
@contact: jamie@memoryanalysis.net
@organization: Volatility Foundation
"""
import volatility.utils as utils
import volatility.plugins.common as common
import volatility.plugins.registry.registryapi as registryapi
import volatility.obj as obj
import volatility.addrspace as addrspace
import volatility.plugins.overlays.basic as basic
import volatility.timefmt as timefmt
from volatility.renderers import TreeGrid
import struct
import datetime
'''
Some references for further reading, all of which were used for building this plugin:
http://download.polytechnic.edu.na/pub4/download.sourceforge.net/pub/sourceforge/l/project/li/liblnk/Documentation/Windows%20Shell%20Item%20format/Windows%20Shell%20Item%20format.pdf
Windows Shell Item format specification (pdf) by Joachim Metz
http://www.dfrws.org/2009/proceedings/p69-zhu.pdf
Using shellbag information to reconstruct user activities (pdf) by Yuandong Zhu, Pavel Gladyshev and Joshua James
http://www.williballenthin.com/forensics/shellbags/index.html
Windows shellbag forensics by Willi Ballenthin
https://github.com/504ensicsLabs/registrydecoder/blob/master/templates/template_files/ShellBagMRU.py
ShellBagMRU.py from Registry Decoder by Kevin Moore
http://code.google.com/p/regripper/wiki/ShellBags
Shellbags RegRipper plugin by Harlan Carvey
'''
EXT_VERSIONS = {
"0x0003":"Windows XP",
"0x0007":"Windows Vista",
"0x0008":"Windows 7",
}
# http://support.microsoft.com/kb/813711
BAG_KEYS = [
"Software\\Microsoft\\Windows\\Shell",
"Software\\Microsoft\\Windows\\ShellNoRoam",
]
USERDAT_KEYS = [
"Wow6432Node\\Local Settings\\Software\\Microsoft\\Windows\\Shell",
"Wow6432Node\\Local Settings\\Software\\Microsoft\\Windows\\ShellNoRoam",
"Local Settings\\Software\\Microsoft\\Windows\\Shell",
"Local Settings\\Software\\Microsoft\\Windows\\ShellNoRoam",
]
# These are abbreviated only because there can be more than one in output
# so it gets cluttered
FILE_ATTRS = {
0x00000001:"RO", #Is read-Only
0x00000002:"HID", #Is hidden
0x00000004:"SYS", #Is a system file or directory
0x00000008:"VOL", #Is a volume label
0x00000010:"DIR", #Is a directory
0x00000020:"ARC", #Should be archived
0x00000040:"DEV", #Is a device
0x00000080:"NORM", #Is normal None of the other flags should be set
0x00000100:"TEMP", #Is temporary
0x00000200:"SPARSE", #Is a sparse file
0x00000400:"RP", #Is a reparse point or symbolic link
0x00000800:"COM", #Is compressed
0x00001000:"OFFLINE", #Is offline The data of the file is stored on an offline storage.
0x00002000:"NI", #Do not index content The content of the file or directory should not be indexed by the indexing service.
0x00004000:"ENC", #Is encrypted
0x00010000:"VIR", #Is virtual
}
# GUIDs and FOLDER_IDs copied from Will Ballenthin's shellbags parser:
# https://github.com/williballenthin/shellbags
KNOWN_GUIDS = {
"031e4825-7b94-4dc3-b131-e946b44c8dd5": "Libraries",
"1ac14e77-02e7-4e5d-b744-2eb1ae5198b7": "CSIDL_SYSTEM",
"208d2c60-3aea-1069-a2d7-08002b30309d": "My Network Places",
"20d04fe0-3aea-1069-a2d8-08002b30309d": "My Computer",
"21ec2020-3aea-1069-a2dd-08002b30309d": "{Unknown CSIDL}",
"22877a6d-37a1-461a-91b0-dbda5aaebc99": "{Unknown CSIDL}",
"2400183a-6185-49fb-a2d8-4a392a602ba3": "Public Videos",
"2559a1f1-21d7-11d4-bdaf-00c04f60b9f0": "{Unknown CSIDL}",
"2559a1f3-21d7-11d4-bdaf-00c04f60b9f0": "{Unknown CSIDL}",
"26ee0668-a00a-44d7-9371-beb064c98683": "{Unknown CSIDL}",
"3080f90e-d7ad-11d9-bd98-0000947b0257": "{Unknown CSIDL}",
"3214fab5-9757-4298-bb61-92a9deaa44ff": "Public Music",
"33e28130-4e1e-4676-835a-98395c3bc3bb": "Pictures",
"374de290-123f-4565-9164-39c4925e467b": "Downloads",
"4336a54d-038b-4685-ab02-99bb52d3fb8b": "{Unknown CSIDL}",
"450d8fba-ad25-11d0-98a8-0800361b1103": "My Documents",
"4bd8d571-6d19-48d3-be97-422220080e43": "Music",
"5399e694-6ce5-4d6c-8fce-1d8870fdcba0": "Control Panel",
"59031a47-3f72-44a7-89c5-5595fe6b30ee": "Users",
"645ff040-5081-101b-9f08-00aa002f954e": "Recycle Bin",
"724ef170-a42d-4fef-9f26-b60e846fba4f": "Administrative Tools",
"7b0db17d-9cd2-4a93-9733-46cc89022e7c": "Documents Library",
"7c5a40ef-a0fb-4bfc-874a-c0f2e0b9fa8e": "Program Files (x86)",
"871c5380-42a0-1069-a2ea-08002b30309d": "Internet Explorer (Homepage)",
"905e63b6-c1bf-494e-b29c-65b732d3d21a": "Program Files",
"9e52ab10-f80d-49df-acb8-4330f5687855": "Temporary Burn Folder",
"a305ce99-f527-492b-8b1a-7e76fa98d6e4": "Installed Updates",
"b4bfcc3a-db2c-424c-b029-7fe99a87c641": "Desktop",
"b6ebfb86-6907-413c-9af7-4fc2abf07cc5": "Public Pictures",
"c1bae2d0-10df-4334-bedd-7aa20b227a9d": "Common OEM Links",
"cce6191f-13b2-44fa-8d14-324728beef2c": "{Unknown CSIDL}",
"d0384e7d-bac3-4797-8f14-cba229b392b5": "Common Administrative Tools",
"d65231b0-b2f1-4857-a4ce-a8e7c6ea7d27": "System32 (x86)",
"de61d971-5ebc-4f02-a3a9-6c82895e5c04": "Get Programs",
"df7266ac-9274-4867-8d55-3bd661de872d": "Programs and Features",
"dfdf76a2-c82a-4d63-906a-5644ac457385": "Public",
"de974d24-d9c6-4d3e-bf91-f4455120b917": "Common Files",
"ed228fdf-9ea8-4870-83b1-96b02cfe0d52": "My Games",
"f02c1a0d-be21-4350-88b0-7367fc96ef3c": "Network",
"f38bf404-1d43-42f2-9305-67de0b28fc23": "Windows",
"f3ce0f7c-4901-4acc-8648-d5d44b04ef8f": "Users Files",
"fdd39ad0-238f-46af-adb4-6c85480369c7": "Documents",
# Control Panel Items
"d20ea4e1-3957-11d2-a40b-0c5020524153": "Administrative Tools",
"9c60de1e-e5fc-40f4-a487-460851a8d915": "AutoPlay",
"d9ef8727-cac2-4e60-809e-86f80a666c91": "BitLocker Drive Encryption",
"b2c761c6-29bc-4f19-9251-e6195265baf1": "Color Management",
"e2e7934b-dce5-43c4-9576-7fe4f75e7480": "Date and Time",
"17cd9488-1228-4b2f-88ce-4298e93e0966": "Default Programs",
"74246bfc-4c96-11d0-abef-0020af6b0b7a": "Device Manager",
"d555645e-d4f8-4c29-a827-d93c859c4f2a": "Ease of Access Center",
"6dfd7c5c-2451-11d3-a299-00c04f8ef6af": "Folder Options",
"93412589-74d4-4e4e-ad0e-e0cb621440fd": "Fonts",
"259ef4b1-e6c9-4176-b574-481532c9bce8": "Game Controllers",
"15eae92e-f17a-4431-9f28-805e482dafd4": "Get Programs",
"87d66a43-7b11-4a28-9811-c86ee395acf7": "Indexing Options",
"a3dd4f92-658a-410f-84fd-6fbbbef2fffe": "Internet Options",
"a304259d-52b8-4526-8b1a-a1d6cecc8243": "iSCSI Initiator",
"725be8f7-668e-4c7b-8f90-46bdb0936430": "Keyboard",
"6c8eec18-8d75-41b2-a177-8831d59d2d50": "Mouse",
"8e908fc9-becc-40f6-915b-f4ca0e70d03d": "Network and Sharing Center",
"d24f75aa-4f2b-4d07-a3c4-469b3d9030c4": "Offline Files",
"96ae8d84-a250-4520-95a5-a47a7e3c548b": "Parental Controls",
"5224f545-a443-4859-ba23-7b5a95bdc8ef": "People Near Me",
"78f3955e-3b90-4184-bd14-5397c15f1efc": "Performance Information and Tools",
"ed834ed6-4b5a-4bfe-8f11-a626dcb6a921": "Personalization",
"025a5937-a6be-4686-a844-36fe4bec8b6d": "Power Options",
"7b81be6a-ce2b-4676-a29e-eb907a5126c5": "Programs and Features",
"00f2886f-cd64-4fc9-8ec5-30ef6cdbe8c3": "Scanners and Cameras",
"9c73f5e5-7ae7-4e32-a8e8-8d23b85255bf": "Sync Center",
"bb06c0e4-d293-4f75-8a90-cb05b6477eee": "System ",
"80f3f1d5-feca-45f3-bc32-752c152e456e": "Tablet PC Settings",
"0df44eaa-ff21-4412-828e-260a8728e7f1": "Taskbar and Start Menu",
"d17d1d6d-cc3f-4815-8fe3-607e7d5d10b3": "Text to Speech",
"60632754-c523-4b62-b45c-4172da012619": "User Accounts",
"be122a0e-4503-11da-8bde-f66bad1e3f3a": "Windows Anytime Upgrade",
"78cb147a-98ea-4aa6-b0df-c8681f69341c": "Windows CardSpace",
"d8559eb9-20c0-410e-beda-7ed416aecc2a": "Windows Defender",
"4026492f-2f69-46b8-b9bf-5654fc07e423": "Windows Firewall",
"5ea4f148-308c-46d7-98a9-49041b1dd468": "Windows Mobility Center",
"e95a4861-d57a-4be1-ad0f-35267e261739": "Windows SideShow",
"36eef7db-88ad-4e81-ad49-0e313f0c35f8": "Windows Update",
# Vista Control Panel Items
"7a979262-40ce-46ff-aeee-7884ac3b6136": "Add Hardware",
"f2ddfc82-8f12-4cdd-b7dc-d4fe1425aa4d": "Sound",
"b98a2bea-7d42-4558-8bd1-832f41bac6fd": "Backup and Restore Center",
"3e7efb4c-faf1-453d-89eb-56026875ef90": "Windows Marketplace",
"a0275511-0e86-4eca-97c2-ecd8f1221d08": "Infrared",
"f82df8f7-8b9f-442e-a48c-818ea735ff9b": "Pen and Input Devices",
"40419485-c444-4567-851a-2dd7bfa1684d": "Phone and Modem",
"2227a280-3aea-1069-a2de-08002b30309d": "Printers",
"fcfeecae-ee1b-4849-ae50-685dcf7717ec": "Problem Reports and Solutions",
"62d8ed13-c9d0-4ce8-a914-47dd628fb1b0": "Regional and Language Options",
"087da31b-0dd3-4537-8e23-64a18591f88b": "Windows Security Center",
"58e3c745-d971-4081-9034-86e34b30836a": "Speech Recognition Options",
# Windows 7 Control Panel Items
"bb64f8a7-bee7-4e1a-ab8d-7d8273f7fdb6": "Action Center",
"0142e4d0-fb7a-11dc-ba4a-000ffe7ab428": "Biometric Devices",
"1206f5f1-0569-412c-8fec-3204630dfb70": "Credential Manager",
"00c6d95f-329c-409a-81d7-c46c66ea7f33": "Default Location",
"37efd44d-ef8d-41b1-940d-96973a50e9e0": "Desktop Gadgets",
"a8a91a66-3a7d-4424-8d24-04e180695c7a": "Devices and Printers",
"c555438b-3c23-4769-a71f-b6d3d9b6053a": "Display",
"cb1b7f8c-c50a-4176-b604-9e24dee8d4d1": "Getting Started",
"67ca7650-96e6-4fdd-bb43-a8e774f73a57": "HomeGroup",
"e9950154-c418-419e-a90a-20c5287ae24b": "Location and Other Sensors",
"05d7b0f4-2121-4eff-bf6b-ed3f69b894d9": "Notification Area Icons",
"9fe63afd-59cf-4419-9775-abcc3849f861": "Recovery",
"241d7c96-f8bf-4f85-b01f-e2b043341a4b": "RemoteApp and Desktop Connections",
"c58c4893-3be0-4b45-abb5-a63e4b8c8651": "Troubleshooting",
# Folder Types
"0b2baaeb-0042-4dca-aa4d-3ee8648d03e5": "Pictures Library",
"36011842-dccc-40fe-aa3d-6177ea401788": "Documents Search Results",
"3f2a72a7-99fa-4ddb-a5a8-c604edf61d6b": "Music Library",
"4dcafe13-e6a7-4c28-be02-ca8c2126280d": "Pictures Search Results",
"5c4f28b5-f869-4e84-8e60-f11db97c5cc7": "Generic (All folder items)",
"5f4eab9a-6833-4f61-899d-31cf46979d49": "Generic Library",
"5fa96407-7e77-483c-ac93-691d05850de8": "Videos",
"631958a6-ad0f-4035-a745-28ac066dc6ed": "Videos Library",
"71689ac1-cc88-45d0-8a22-2943c3e7dfb3": "Music Search Results",
"7d49d726-3c21-4f05-99aa-fdc2c9474656": "Documents",
"7fde1a1e-8b31-49a5-93b8-6be14cfa4943": "Generic Search Results",
"80213e82-bcfd-4c4f-8817-bb27601267a9": "Compressed Folder (zip folder)",
"94d6ddcc-4a68-4175-a374-bd584a510b78": "Music",
"b3690e58-e961-423b-b687-386ebfd83239": "Pictures",
"ea25fbd7-3bf7-409e-b97f-3352240903f4": "Videos Search Results",
"fbb3477e-c9e4-4b3b-a2ba-d3f5d3cd46f9": "Documents Library",
}
FOLDER_IDS = {
0x00:"EXPLORER",
0x42:"LIBRARIES",
0x44:"USERS",
0x48:"MY_DOCUMENTS",
0x50:"MY_COMPUTER",
0x58:"NETWORK",
0x60:"RECYCLE_BIN",
0x68:"EXPLORER",
0x70:"UKNOWN",
0x78:"RECYCLE_BIN",
0x80:"MY_GAMES",
}
SHELL_ITEM_TYPES = {
0x00:"UNKNOWN_00", #Varied
0x01:"UNKNOWN_01",
0x2e:"UNKNOWN_2E", # DEVICE from ShellBagMRU.py in RegistryDecoder
0x31:"FILE_ENTRY", # Folder
0x32:"FILE_ENTRY", # Zip file
0xb1:"FILE_ENTRY", # Hidden folder
0x1f:"FOLDER_ENTRY", # System folder
0x2f:"VOLUME_NAME",
0x41:"NETWORK_VOLUME_NAME", # Windows Domain
0x42:"NETWORK_VOLUME_NAME", # Computer Name
0x46:"NETWORK_VOLUME_NAME", # MS Windows Network
0x47:"NETWORK_VOLUME_NAME", # Entire Network
0xc3:"NETWORK_SHARE", # Remote Share
0x61:"URI",
0x71:"CONTROL_PANEL",
0x74:"UNKNOWN_74", # System protected folder
}
FLAGS = {
0x02:"has network volume name",
0x80:"has unknown 16-bit value",
}
##### Type overrides for output below #####
# http://msdn.microsoft.com/en-us/library/aa379358%28v=vs.85%29.aspx
# http://msdn.microsoft.com/en-us/library/cc248286%28v=prot.10%29.aspx
'''
'_GUID' : [ 0x10, {
'Data1' : [ 0x0, ['unsigned long']],
'Data2' : [ 0x4, ['unsigned short']],
'Data3' : [ 0x6, ['unsigned short']],
'Data4' : [ 0x8, ['array', 8, ['unsigned char']]],
'''
class _GUID(obj.CType):
def __str__(self):
return "{0:08x}-{1:04x}-{2:04x}-{3:02x}{4:02x}-{5:02x}{6:02x}{7:02x}{8:02x}{9:02x}{10:02x}".format(self.Data1, self.Data2, self.Data3,
self.Data4[0], self.Data4[1], self.Data4[2], self.Data4[3], self.Data4[4], self.Data4[5], self.Data4[6], self.Data4[7])
class ITEMPOS(obj.CType):
def get_file_attrs(self):
fileattrs = ""
if self.Size >= 0x15:
for f in FILE_ATTRS:
if self.Attributes.FileAttrs & f == f:
fileattrs += FILE_ATTRS[f] + ", "
fileattrs = fileattrs.rstrip(", ")
return fileattrs
def body(self, details):
return "0|[{6}SHELLBAGS ITEMPOS] Name: {3}/Attrs: {4}/{5}|0|---------------|0|0|0|{0}|{1}|{2}|{2}\n".format(
self.Attributes.AccessDate.v(),
self.Attributes.ModifiedDate.v(),
self.Attributes.CreatedDate.v(),
str(self.Attributes.UnicodeFilename),
self.get_file_attrs(),
details,
self.obj_vm._config.MACHINE)
def __str__(self):
return "{0:<14} {1:30} {2:30} {3:30} {4:25} {5}".format(self.Attributes.FileName,
str(self.Attributes.ModifiedDate),
str(self.Attributes.CreatedDate),
str(self.Attributes.AccessDate),
self.get_file_attrs(),
str(self.Attributes.UnicodeFilename))
def get_items(self):
items = {}
items["FileName"] = str(self.Attributes.FileName)
items["Modified"] = str(self.Attributes.ModifiedDate)
items["Create"] = str(self.Attributes.CreatedDate)
items["Access"] = str(self.Attributes.AccessDate)
items["Attributes"] = self.get_file_attrs()
items["Unicode"] = str(self.Attributes.UnicodeFilename)
return items
def get_header(self):
return [("File Name", "14s"),
("Modified Date", "30"),
("Create Date", "30"),
("Access Date", "30"),
("File Attr", "25"),
("Unicode Name", ""),
]
class FILE_ENTRY(ITEMPOS):
def get_file_attrs(self):
fileattrs = ""
for f in FILE_ATTRS:
if self.Attributes.FileAttrs & f == f:
fileattrs += FILE_ATTRS[f] + ", "
fileattrs = fileattrs.rstrip(", ")
return fileattrs
def body(self, details):
return "0|[{6}SHELLBAGS FILE_ENTRY] Name: {3}/Attrs: {4}/{5}|0|---------------|0|0|0|{0}|{1}|{2}|{2}\n".format(
self.Attributes.AccessDate.v(),
self.Attributes.ModifiedDate.v(),
self.Attributes.CreatedDate.v(),
str(self.Attributes.UnicodeFilename),
self.get_file_attrs(),
details,
self.obj_vm._config.MACHINE)
def __str__(self):
return "{0:<14} {1:30} {2:30} {3:30} {4:25}".format(self.Attributes.FileName,
str(self.Attributes.ModifiedDate),
str(self.Attributes.CreatedDate),
str(self.Attributes.AccessDate),
self.get_file_attrs())
def get_items(self):
items = {}
items["FileName"] = str(self.Attributes.FileName)
items["Modified"] = str(self.Attributes.ModifiedDate)
items["Create"] = str(self.Attributes.CreatedDate)
items["Access"] = str(self.Attributes.AccessDate)
items["Attributes"] = self.get_file_attrs()
return items
def get_header(self):
return [("File Name", "14s"),
("Modified Date", "30"),
("Create Date", "30"),
("Access Date", "30"),
("File Attr", "25"),
("Path", ""),
]
class FOLDER_ENTRY(obj.CType):
def get_folders(self):
folder_ids = ""
for f in FOLDER_IDS:
if self.Flags & f == f:
folder_ids += FOLDER_IDS[f] + ", "
folder_ids = folder_ids.rstrip(", ")
return folder_ids
def __str__(self):
return "{0:<14} {1:40} {2:20} {3}".format("Folder Entry",
str(self.GUID),
KNOWN_GUIDS.get(str(self.GUID), "Unknown GUID"),
self.get_folders())
def get_header(self):
return [("Entry Type", "14s"),
("GUID", "40"),
("GUID Description", "20"),
("Folder IDs", ""),
]
class _VOLUSER_ASSIST_TYPES(obj.CType):
def get_header(self):
if hasattr(self, "Count") and hasattr(self, "FocusCount"):
return [("Entry Type", "14s"),
("Count", "5"),
("Focus Count", "5"),
("Time Focused", "20"),
("Last Update", ""),
]
else:
return [("Entry Type", "14s"),
("ID", "10"),
("Count", "10"),
("Last Update", ""),
]
def __str__(self):
if hasattr(self, "Count") and hasattr(self, "FocusCount"):
return "{0:<14} {1:5} {2:5} {3:20} {4}".format("UserAssist",
self.Count,
self.FocusCount,
self.FocusTime,
self.LastUpdated)
else:
return "{0:<14} {1:5} {2:5} {3}".format("UserAssist",
self.ID,
self.CountStartingAtFive,
self.LastUpdated)
def body(self, reg, key, subname, lastwrite):
ID = "N/A"
count = "N/A"
fc = "N/A"
tf = "N/A"
if hasattr(self, "ID"):
ID = "{0}".format(self.ID)
if hasattr(self, "Count"):
count = "{0}".format(self.Count)
else:
count = "{0}".format(self.CountStartingAtFive if self.CountStartingAtFive < 5 else self.CountStartingAtFive - 5)
if hasattr(self, "FocusCount"):
seconds = (self.FocusTime + 500) / 1000.0
time = datetime.timedelta(seconds = seconds) if seconds > 0 else self.FocusTime
fc = "{0}".format(self.FocusCount)
tf = "{0}".format(time)
subname = subname.replace("|", "%7c")
return "0|[SHELLBAGS USERASSIST] Registry: {1}/Key: {7}/Value: {2}/LW: {8}/ID: {3}/Count: {4}/FocusCount: {5}/TimeFocused: {6}|0|---------------|0|0|0|{0}|{0}|{0}|{0}\n".format(
self.LastUpdated.v(), reg, subname, ID, count, fc, tf, key, lastwrite)
class CONTROL_PANEL(FOLDER_ENTRY):
def __str__(self):
return "{0:<14} {1:40} {2:20} {3}".format("Control Panel",
str(self.GUID),
KNOWN_GUIDS.get(str(self.GUID), "Unknown GUID"),
self.get_folders())
# taken from http://code.google.com/p/registrydecoder/source/browse/trunk/templates/template_files/ShellBagMRU.py#388
class UNKNOWN_00(FOLDER_ENTRY):
def __str__(self):
if self.DataSize == 0x1a:
return "{0:<14} {1:40} {2:20} {3}".format("Folder",
str(self.GUID),
KNOWN_GUIDS.get(str(self.GUID), "Unknown GUID"),
self.get_folders())
#elif self.DataSize in [0xa4, 0xb4, 0x7a, 0xc4, 0x9a, 0x30]:
# TODO: this is not clear yet
# return "{0:<14} {1:40} {2:20} {3}".format("Device Property",
# str(self.Name), "", "")
# TODO: fix this for other types like "AugM" and 1SPS
else:
return "{0:<14} {1:40} {2:20} {3}".format("Folder (unsupported)",
"This property is not yet supported", "", "")
class VOLUME_NAME(obj.CType):
def __str__(self):
return "{0:14} {1}".format("Volume Name", self.Name)
def get_header(self):
return [("Entry Type", "14s"),
("Path", ""),
]
class NETWORK_VOLUME_NAME(obj.CType):
def get_flags(self):
flags = ""
for f in FLAGS:
if self.Flags & f == f:
flags += FLAGS[f] + ", "
flags = flags.rstrip(", ")
return flags
def __str__(self):
return "{0:25} {1:20} {2} |".format("Network Volume Name", self.Description, self.Name)
def get_header(self):
return [("Entry Type", "25s"),
("Description", "20"),
("Name | Full Path", ""),
]
class NETWORK_SHARE(NETWORK_VOLUME_NAME):
def __str__(self):
return "{0:25} {1:20} {2}".format("Network Volume Share", self.Description, self.Name)
##### End Type Overrides #####
class NullString(basic.String):
def __str__(self):
result = self.obj_vm.zread(self.obj_offset, self.length).split("\x00\x00")[0].replace("\x00", "")
if not result:
result = ""
return result
def v(self):
result = self.obj_vm.zread(self.obj_offset, self.length).split("\x00\x00")[0].replace("\x00", "")
if not result:
return obj.NoneObject("Cannot read string length {0} at {1:#x}".format(self.length, self.obj_offset))
return result
shell_item_types = {
'SHELLITEM': [ None, {
'Size' : [ 0x0, ['unsigned short']],
'Type' : [ 0x2, ['unsigned char']], # SHELL_ITEM_TYPES
} ],
'FOLDER_ENTRY': [ None, {
'ShellItem': [ 0x0, ['SHELLITEM']],
'Flags': [ 0x3, ['unsigned char']], # FOLDER_IDS
'GUID': [ 0x4, ['_GUID']],
} ],
'VOLUME_NAME': [ None, {
'ShellItem': [ 0x0, ['SHELLITEM']],
'Name': [ 0x3, ['String', dict(length = 22)]],
} ],
'NETWORK_VOLUME_NAME': [ None, {
'ShellItem': [ 0x0, ['SHELLITEM']],
'Flags': [ 0x4, ['unsigned char']],
'Name': [ 0x5, ['String', dict(length = 255)]],
'Description': [ lambda x: x.Name.obj_offset + len(x.Name), ['String', dict(length = 4096)]],
} ],
'URI': [ None, {
'Flags': [ 0x3, ['unsigned char']],
'UString': [ 0x8, ['String', dict(length = 4096)]],
# other stuff here not filled in...
} ],
'CONTROL_PANEL': [ None, {
'ShellItem': [ 0x0, ['SHELLITEM']],
'Flags': [ 0x3, ['unsigned char']],
'GUID': [ 0xe, ['_GUID']],
} ],
'NETWORK_SHARE': [ None, {
'ShellItem': [ 0x0, ['SHELLITEM']],
'Flags': [ 0x4, ['unsigned char']],
'Name': [ 0x5, ['String', dict(length = 255)]],
'Description': [ lambda x: x.Name.obj_offset + len(x.Name), ['String', dict(length = 4096)]],
} ],
# These "OTHER" types are really not clear yet...
'UNKNOWN_00': [ None, {
'ShellItem': [ 0x0, ['SHELLITEM']],
'Flags': [ 0x3, ['unsigned char']],
'DataSize': [ 0x4, ['unsigned short']], #size of the following data
'FolderAugM': [ 0x4, ['String', dict(length = 4)]],
'PropertyList': [ 0xa, ['unsigned short']],
'IdentifierSize': [ 0xc, ['unsigned short']],
'GUID': [ 0xe, ['_GUID']],
#'NameLength': [ 0x42, ['unsigned short']], # size of following data
#'Name': [ 0x4a, ['String', dict(length = lambda x: x.NameLength * 2)]],
} ],
'UNKNOWN_01': [ None, {
'ShellItem': [ 0x0, ['SHELLITEM']],
'Flags': [ 0x3, ['unsigned char']],
'Unknown': [ 0x4, ['unsigned int']],
} ],
'UNKNOWN_2E': [ None, {
'ShellItem': [ 0x0, ['SHELLITEM']],
'Flags': [ 0x3, ['unsigned char']],
'GUID': [ 0x4, ['_GUID']],
} ],
'UNKNOWN_74': [ None, {
'ShellItem': [ 0x0, ['SHELLITEM']],
'Flags': [ 0x3, ['unsigned char']],
'Attributes' : [12, ['ATTRIBUTES']],
} ],
}
itempos_types_XP = {
'ATTRIBUTES': [ None, {
'ModifiedDate': [ 0x0, ['DosDate', dict(is_utc = True)]],
'FileAttrs': [ 0x4, ['unsigned short']],
'FileName': [ 0x6, ['String', dict(length = 255)]], # 8.3 File name although sometimes it's longer than 14 chars
'FDataSize': [ lambda x: x.FileName.obj_offset + len(x.FileName) + (1 if len(x.FileName) % 2 == 1 else 2), ['unsigned short']],
'EVersion': [ lambda x: x.FDataSize.obj_offset + 2, ['unsigned short']],
'Unknown1': [ lambda x: x.EVersion.obj_offset + 2, ['unsigned short']],
'Unknown2': [ lambda x: x.Unknown1.obj_offset + 2, ['unsigned short']], # 0xBEEF
'CreatedDate': [ lambda x: x.Unknown2.obj_offset + 2, ['DosDate', dict(is_utc = True)]],
'AccessDate': [ lambda x: x.CreatedDate.obj_offset + 4, ['DosDate', dict(is_utc = True)]],
'Unknown3': [ lambda x: x.AccessDate.obj_offset + 4, ['unsigned int']],
'UnicodeFilename': [ lambda x: x.Unknown3.obj_offset + 4, ['NullString', dict(length = 4096, encoding = 'utf8')]],
} ],
'ITEMPOS' : [ None, {
'Size' : [ 0x0, ['unsigned short']],
'Flags' : [ 0x2, ['unsigned short']],
'FileSize' : [ 0x4, ['short']],
'Attributes' : [ 0x8, ['ATTRIBUTES']],
} ],
'FILE_ENTRY': [ None, {
'ShellItem': [ 0x0, ['SHELLITEM']], # Type: 0x31, 0x32, 0xb1
'Flags': [ 0x3, ['unsigned char']],
'FileSize': [ 0x4, ['int']],
'Attributes' : [ 0x8, ['ATTRIBUTES']],
} ],
}
class ShellBagsTypesXP(obj.ProfileModification):
before = ['WindowsObjectClasses']
conditions = {'os': lambda x: x == 'windows',
'major': lambda x: x == 5}
def modification(self, profile):
profile.object_classes.update({
'NullString': NullString,
'_GUID':_GUID,
'ITEMPOS':ITEMPOS,
'FILE_ENTRY':FILE_ENTRY,
'FOLDER_ENTRY':FOLDER_ENTRY,
'CONTROL_PANEL':CONTROL_PANEL,
'VOLUME_NAME':VOLUME_NAME,
'NETWORK_VOLUME_NAME':NETWORK_VOLUME_NAME,
'NETWORK_SHARE':NETWORK_SHARE,
'UNKNOWN_00':UNKNOWN_00,
'_VOLUSER_ASSIST_TYPES':_VOLUSER_ASSIST_TYPES,
})
profile.vtypes.update(shell_item_types)
profile.vtypes.update(itempos_types_XP)
itempos_types_Vista = {
'ATTRIBUTES' : [ None, {
'ModifiedDate': [ 0x0, ['DosDate', dict(is_utc = True)]],
'FileAttrs': [ 0x4, ['unsigned short']],
'FileName': [ 0x6, ['String', dict(length = 255)]],
'FDataSize': [ lambda x: x.FileName.obj_offset + len(x.FileName) + (1 if len(x.FileName) % 2 == 1 else 2), ['unsigned short']],
'EVersion': [ lambda x: x.FDataSize.obj_offset + 2, ['unsigned short']],
'Unknown1': [ lambda x: x.EVersion.obj_offset + 2, ['unsigned short']],
'Unknown2': [ lambda x: x.Unknown1.obj_offset + 2, ['unsigned short']], # 0xBEEF
'CreatedDate': [ lambda x: x.Unknown2.obj_offset + 2, ['DosDate', dict(is_utc = True)]],
'AccessDate': [ lambda x: x.CreatedDate.obj_offset + 4, ['DosDate', dict(is_utc = True)]],
'Unknown3': [ lambda x: x.AccessDate.obj_offset + 4, ['unsigned int']],
'FileReference': [ lambda x: x.Unknown3.obj_offset + 4, ['unsigned long long']], #MFT entry index 0-6, Sequence number 6-7
'Unknown4': [ lambda x: x.FileReference.obj_offset + 8, ['unsigned long long']],
'LongStringSize': [ lambda x: x.Unknown4.obj_offset + 8, ['unsigned short']],
'UnicodeFilename': [ lambda x: x.LongStringSize.obj_offset + 2, ['NullString', dict(length = 4096, encoding = 'utf8')]],
'AdditionalLongString': [ lambda x: x.UnicodeFilename.obj_offset + len(x.UnicodeFilename), ['NullString', dict(length = (lambda k: k.LongStringSize), encoding = 'utf8')]],
} ],
'ITEMPOS' : [ None, {
'Size' : [ 0x0, ['unsigned short']],
'Flags' : [ 0x2, ['unsigned short']],
'FileSize' : [ 0x4, ['short']],
'Attributes' : [ 0x8, ['ATTRIBUTES']],
} ],
'FILE_ENTRY': [ None, {
'ShellItem': [ 0x0, ['SHELLITEM']], # Type: 0x31, 0x32, 0xb1
'Flags': [ 0x3, ['unsigned char']],
'FileSize': [ 0x4, ['int']],
'Attributes' : [ 0x8, ['ATTRIBUTES']],
} ],
}
class ShellBagsTypesVista(obj.ProfileModification):
before = ['WindowsObjectClasses']
conditions = {'os': lambda x: x == 'windows',
'major': lambda x: x == 6,
'minor': lambda x: x == 0}
def modification(self, profile):
profile.object_classes.update({
'NullString': NullString,
'_GUID':_GUID,
'ITEMPOS':ITEMPOS,
'FILE_ENTRY':FILE_ENTRY,
'FOLDER_ENTRY':FOLDER_ENTRY,
'CONTROL_PANEL':CONTROL_PANEL,
'VOLUME_NAME':VOLUME_NAME,
'NETWORK_VOLUME_NAME':NETWORK_VOLUME_NAME,
'NETWORK_SHARE':NETWORK_SHARE,
'UNKNOWN_00':UNKNOWN_00,
'_VOLUSER_ASSIST_TYPES':_VOLUSER_ASSIST_TYPES,
})
profile.vtypes.update(shell_item_types)
profile.vtypes.update(itempos_types_Vista)
itempos_types_Win7 = {
'ATTRIBUTES': [ None, {
'ModifiedDate': [ 0x0, ['DosDate', dict(is_utc = True)]],
'FileAttrs': [ 0x4, ['unsigned short']],
'FileName': [ 0x6, ['String', dict(length = 255)]],
'FDataSize': [ lambda x: x.FileName.obj_offset + len(x.FileName) + (1 if len(x.FileName) % 2 == 1 else 2), ['unsigned short']],
'EVersion': [ lambda x: x.FDataSize.obj_offset + 2, ['unsigned short']],
'Unknown1': [ lambda x: x.EVersion.obj_offset + 2, ['unsigned short']],
'Unknown2': [ lambda x: x.Unknown1.obj_offset + 2, ['unsigned short']], # 0xBEEF
'CreatedDate': [ lambda x: x.Unknown2.obj_offset + 2, ['DosDate', dict(is_utc = True)]],
'AccessDate': [ lambda x: x.CreatedDate.obj_offset + 4, ['DosDate', dict(is_utc = True)]],
'Unknown3': [ lambda x: x.AccessDate.obj_offset + 4, ['unsigned int']],
'FileReference': [ lambda x: x.Unknown3.obj_offset + 4, ['unsigned long long']], #MFT entry index 0-6, Sequence number 6-7
'Unknown4': [ lambda x: x.FileReference.obj_offset + 8, ['unsigned long long']],
'LongStringSize': [ lambda x: x.Unknown4.obj_offset + 8, ['unsigned short']],
'Unknown5': [ lambda x: x.LongStringSize.obj_offset + 2, ['unsigned int']],
'UnicodeFilename': [ lambda x: x.Unknown5.obj_offset + 4, ['NullString', dict(length = 4096, encoding = 'utf8')]],
'AdditionalLongString': [ lambda x: x.UnicodeFilename.obj_offset + len(x.UnicodeFilename), ['NullString', dict(length = (lambda k: k.LongStringSize), encoding = 'utf8')]],
} ],
'ITEMPOS' : [ None, {
'Size' : [ 0x0, ['unsigned short']],
'Flags' : [ 0x2, ['unsigned short']],
'FileSize' : [ 0x4, ['short']],
'Attributes' : [ 0x8, ['ATTRIBUTES']],
} ],
'FILE_ENTRY': [ None, {
'ShellItem': [ 0x0, ['SHELLITEM']], # Type: 0x31, 0x32, 0xb1
'Flags': [ 0x3, ['unsigned char']],
'FileSize': [ 0x4, ['int']],
'Attributes' : [ 0x8, ['ATTRIBUTES']],
} ],
}
class ShellBagsTypesWin7(obj.ProfileModification):
before = ['WindowsObjectClasses']
conditions = {'os': lambda x: x == 'windows',
'major': lambda x: x == 6,
'minor': lambda x: x >= 1}
def modification(self, profile):
profile.object_classes.update({
'NullString': NullString,
'_GUID':_GUID,
'ITEMPOS':ITEMPOS,
'FILE_ENTRY':FILE_ENTRY,
'FOLDER_ENTRY':FOLDER_ENTRY,
'CONTROL_PANEL':CONTROL_PANEL,
'VOLUME_NAME':VOLUME_NAME,
'NETWORK_VOLUME_NAME':NETWORK_VOLUME_NAME,
'NETWORK_SHARE':NETWORK_SHARE,
'UNKNOWN_00':UNKNOWN_00,
'_VOLUSER_ASSIST_TYPES':_VOLUSER_ASSIST_TYPES,
})
profile.vtypes.update(shell_item_types)
profile.vtypes.update(itempos_types_Win7)
class ShellBags(common.AbstractWindowsCommand):
"""Prints ShellBags info"""
def __init__(self, config, *args, **kwargs):
common.AbstractWindowsCommand.__init__(self, config, *args, **kwargs)
config.add_option("MACHINE", default = "",
help = "Machine name to add to timeline header")
self.supported = ["FILE_ENTRY", "FOLDER_ENTRY", "CONTROL_PANEL", "VOLUME_NAME", "NETWORK_VOLUME_NAME", "NETWORK_SHARE", "UNKNOWN_00"]
self.paths = {}
def rreplace(self, s, old, new, occurrence):
li = s.rsplit(old, occurrence)
return new.join(li)
def parse_key(self, regapi, reg, thekey, given_root = None):
items = {} # a dictionary of shellbag objects indexed by value name
for value, data in regapi.reg_yield_values(None, thekey, thetype = 'REG_BINARY', given_root = given_root):
if data == None or thekey.find("S-") != -1 or str(value).startswith("LastKnownState") or thekey.lower().find("cmi-create") != -1:
continue
if str(value).startswith("ItemPos"):
items[str(value)] = []
bufferas = addrspace.BufferAddressSpace(self._config, data = data)
i = 0x18
while i < len(data) - 0x10:
item = obj.Object("ITEMPOS", offset = i, vm = bufferas)
if item != None and item.Size >= 0x15:
items[str(value)].append(item)
i += item.Size + 0x8
elif str(value).lower().startswith("mrulistex"):
list = {}
bufferas = addrspace.BufferAddressSpace(self._config, data = data)
i = 0
while i < len(data) - 4:
list[obj.Object("int", offset = i, vm = bufferas).v()] = (i / 4)
i += 4
items["MruListEx"] = list
elif len(data) >= 0x10:
bufferas = addrspace.BufferAddressSpace(self._config, data = data)
item = obj.Object("SHELLITEM", offset = 0, vm = bufferas)
thetype = SHELL_ITEM_TYPES.get(int(item.Type), None)
if thetype != None:
if thetype == "UNKNOWN_00" and len(data) == bufferas.profile.get_obj_size("_VOLUSER_ASSIST_TYPES"):
# this is UserAssist Data
item = obj.Object("_VOLUSER_ASSIST_TYPES", offset = 0, vm = bufferas)
try:
value = value.encode('rot_13')
except UnicodeDecodeError:
pass
else:
if bufferas.profile.get_obj_size(thetype) > len(data):
continue
item = obj.Object(thetype, offset = 0, vm = bufferas)
if hasattr(item, "DataSize") and item.DataSize <= 0:
continue
if thetype in self.supported:
temp = ""
if hasattr(item, "Attributes"):
temp = str(item.Attributes.UnicodeFilename)
elif hasattr(item, "Name"):
temp = str(item.Name)
self.paths[reg + ":" + thekey + ":" + str(value)] = temp
items[str(value)] = []
items[str(value)].append(item)
return items
def calculate(self):
addr_space = utils.load_as(self._config)
version = (addr_space.profile.metadata.get('major', 0),
addr_space.profile.metadata.get('minor', 0))
if self._config.MACHINE != "":
self._config.update("MACHINE", "{0} ".format(self._config.MACHINE))
#set our current registry of interest and get its path
regapi = registryapi.RegistryApi(self._config)
regapi.reset_current()
#scan for registries and populate them:
print "Scanning for registries...."
regapi.set_current('ntuser.dat')
shellbag_data = []
print "Gathering shellbag items and building path tree..."
seen = {}
for bk in BAG_KEYS:
for cat, current_path in regapi.reg_yield_key("ntuser.dat", bk):
keys = [(k, bk + "\\" + k.Name) for k in regapi.reg_get_all_subkeys("ntuser.dat", key = None, given_root = cat)]
for key, start in keys:
if key.Name:
if seen.get(start + "\\" + k.Name, None) != None:
continue
seen[start + "\\" + k.Name] = key.obj_offset
subkeys = [k for k in regapi.reg_get_all_subkeys("ntuser.dat", key = None, given_root = key)]
for k in subkeys:
keys.append((k, start + "\\" + k.Name))
items = self.parse_key(regapi, current_path, start, given_root = key)
if len(items) > 0:
shellbag_data.append((start, current_path, key, items))
if version >= (6, 0):
regapi.reset_current()
regapi.set_current("UsrClass.dat")
seen = {}
for bk in USERDAT_KEYS:
for cat, current_path in regapi.reg_yield_key("UsrClass.dat", bk):
keys = [(k, bk + "\\" + k.Name) for k in regapi.reg_get_all_subkeys("UsrClass.dat", key = None, given_root = cat)]
for key, start in keys:
if key.Name:
if seen.get(start + "\\" + k.Name, None) != None:
continue
seen[start + "\\" + k.Name] = key.obj_offset
subkeys = [k for k in regapi.reg_get_all_subkeys("UsrClass.dat", key = None, given_root = key)]
for k in subkeys:
keys.append((k, start + "\\" + k.Name))
items = self.parse_key(regapi, current_path, start, given_root = key)
if len(items) > 0:
shellbag_data.append((start, current_path, key, items))
return shellbag_data
def build_path(self, reg, key, item):
path = ""
if hasattr(item, "Attributes"):
path = str(item.Attributes.UnicodeFilename)
elif hasattr(item, "Name"):
path = str(item.Name)
else:
return path
while key != "":
parent = self.rreplace(key, "\\" + key.split("\\")[-1], "", 1)
prev = self.paths.get(reg + ":" + parent + ":" + key.split("\\")[-1], "")
if prev == "":
break
path = prev + "\\" + path
key = parent
return path
def render_body(self, outfd, data):
for name, reg, key, items in data:
for item in items:
if item == "MruListEx":
continue
for shell in items[item]:
if type(shell) == ITEMPOS or type(shell) == FILE_ENTRY:
full_path = self.build_path(reg, name, shell).replace("\\\\", "\\")
outfd.write("{0}".format(shell.body("FullPath: {0}/Registry: {1}/Key: {2}/LW: {3}".format(full_path, reg, name, str(key.LastWriteTime)))))
elif type(shell) == _VOLUSER_ASSIST_TYPES:
outfd.write("{0}".format(shell.body(reg, name, item, str(key.LastWriteTime))))
def unified_output(self, data):
return TreeGrid([("Registry", str),
("Key", str),
("LastWrite", str),
("FileName", str),
("Create", str),
("Access", str),
("Attributes", str),
("Unicode", str),
("Path", str),
],
self.generator(data))
def generator(self, data):
for name, reg, key, items in data:
if not key:
continue
for item in items:
if item == "MruListEx":
continue
for shell in items[item]:
full_path = ""
if type(shell) == ITEMPOS or type(shell) == FILE_ENTRY:
full_path = self.build_path(reg, name, shell).replace("\\\\", "\\")
things = shell.get_items()
yield (0, [str(reg),
str(name),
str(key.LastWriteTime),
things.get("FileName", ""),
things.get("Create", ""),
things.get("Access", ""),
things.get("Attributes", ""),
things.get("Unicode", ""),
str(full_path)])
def render_text(self, outfd, data):
border = "*" * 75
for name, reg, key, items in data:
if not key:
continue
first = True
mru = items.get("MruListEx", None)
mruheader = [("Value", "7"), ("Mru", "5")] if mru else [("Value", "25")]
for item in items:
if item == "MruListEx":
continue
for shell in items[item]:
full_path = ""
if type(shell) != ITEMPOS and type(shell) != VOLUME_NAME:
full_path = self.build_path(reg, name, shell).replace("\\\\", "\\")
if first:
outfd.write(border + "\n")
outfd.write("Registry: " + reg + "\n")
outfd.write("Key: " + name + "\n")
outfd.write("Last updated: {0}\n".format(key.LastWriteTime))
curheader = shell.get_header()
self.table_header(outfd, mruheader + curheader)
first = False
if curheader != shell.get_header():
curheader = shell.get_header()
outfd.write("\n")
self.table_header(outfd, mruheader + curheader)
if mru:
outfd.write("{0:7} {1:<5} {2} {3}\n".format(item, mru[int(item)], str(shell), full_path))
else:
outfd.write("{0:25} {1} {2}\n".format(item, str(shell), full_path))
if not first:
outfd.write(border + "\n\n")