11. Dez 2023
Lesedauer 6 Min.
Windows-Explorer-History
Ein eigenes Steuerelement für Verlaufsdaten, Teil 8
Auch der Windows Explorer speichert Verlaufsdaten, die man auslesen kann.

Die vorangegangenen Folgen dieser Serie (von [1] bis [2]) haben sich damit befasst, ein eigenes Steuerelement zu entwickeln, das alle Quellen von Verlaufsdaten ausliest, um diese Daten einheitlich präsentieren und verwalten zu können. Nun sollen auch noch die vom Windows Explorer gespeicherten Verlaufsdaten in das benutzerdefinierte Steuerelement aufgenommen werden.Jeder Windows-Anwender ist mit dem Windows Explorer vertraut. Er ist fest ins System integriert und stellt eine Vielzahl an Funktionen und auch Dialogen bereit, die auch Fremdprogramme nutzen können. Viele, aber längst nicht alle Funktionen sind dokumentiert und viele der in der Systemregistrierung (Registry) gespeicherten Daten haben einen direkten Bezug zum Windows Explorer.
Sensible Nutzungsdaten in Shellbags
Die vom Windows Explorer in der Registry abgelegten Daten werden als binäre Datenpakete, sogenannte Shellbags, gespeichert. Offenlegen können Sie diese Daten mithilfe des kostenlosen Programms Shellbag Analyzer & Cleaner [3], siehe Bild 1. Das Programm legt nicht nur die in der Registrierung abgelegten Informationen zu genutzten Ordnern offen, sondern auch die Infos zu externen Laufwerken, Suchergebnissen und Systemsteuerungsmenüs. Dabei spielt es keine Rolle, ob die Ordner noch existieren oder zwischenzeitlich gelöscht wurden. Ferner werden Infos zum letzten Zugriff, zum Pfad, zur Art, zum Daten-Slot, zum Slot-Registrierschlüssel sowie zum Anlagedatum, zum letzten Zugriffdatum und zum letzten Änderungsdatum abgelegt.
Offengelegt: vom Windows Explorer angelegte Shellbags (Bild 1)
Autor
Über diese Daten kann das Nutzungsverhalten von Benutzern nachverfolgt werden. Dementsprechend werden die Informationen häufig für forensische Analysen verwendet. Damit könnten Arbeitgeber beispielsweise überprüfen, ob Arbeitnehmer nur in den für die Arbeit benötigten Verzeichnissen unterwegs waren. Mit dem Tool Shellbag Analyzer & Cleaner [3] können Sie diese Informationen nicht nur auslesen, sondern auch bereinigen und somit unerwünschte Analysen unterbinden. Optional lassen sich die Daten auch in lesbarer Form exportieren. Die exportierte Datei wird im Textformat (CSV-Format) auf dem Desktop angelegt und kann in Datenbanken und/oder Kalkulationsprogramme importiert werden. Die interne Verwaltung erfolgt ähnlich wie die der zuletzt geöffneten Dokumente (Recent Docs), die ebenfalls binär verschlüsselt in der Registry gespeichert werden. Einzelne Einträge werden über MRUListEx-Listen zusammengefasst, die numerische Werte für Schlüsselnamen enthalten, die wiederum alle Daten im Binärformat verwalten (Bild 2).

Shellbag-Informationen im Registrierungseditor (Bild 2)
Autor
Shellbags wurden unter Windows XP in der Datei NTuser
.dat abgelegt und sind seit Windows 7 in der Datei UserClass
.dat zu finden. Alle Daten werden den Hauptknoten HKCU (HKEY_CURRENT_USER) und HKCR (HKEY_CLASSES_ROOT) (seit Windows 7) zugeordnet. Die Registrierzweige:
.dat abgelegt und sind seit Windows 7 in der Datei UserClass
.dat zu finden. Alle Daten werden den Hauptknoten HKCU (HKEY_CURRENT_USER) und HKCR (HKEY_CLASSES_ROOT) (seit Windows 7) zugeordnet. Die Registrierzweige:
NTUSER.DAT:
HKCU\Software\Microsoft\Windows\ShellNoRoam\BagMRU
USRCLASS.DAT:
HKCU\Software\Classes\Local Settings\Software\Microsoft\
Windows\Shell\BagMRU
HKCU\Software\Classes\Local Settings\Software\Microsoft\
Windows\Shell\Bags
Der Aufbau und die Datenverwaltung der Shellbags sind kompliziert. Detaillierte Informationen finden Sie bei Bedarf im PDF-Dokument „Windows Shellbag Forensics in Depth“ unter [4]. Alternative Tools zur Shellbag-Analyse listet die nebenstehende Tabelle 1.
Tabelle 1: Tools für Shellbag-Einträge
|
Im Rahmen des Verlaufsdatensteuerelements sollen die Shellbags nicht berücksichtigt werden. Optional können Sie diese aber später selbst ergänzen.
Windows-URLs ermitteln
An dieser Stelle sollen über Windows-API-Funktionen die im Windows Explorer angewählten URLs ermittelt und ausgegeben werden. Die URLs können Bezüge zu Webseiten und auch zu Dokumenten sein, die generell über URLs verwaltet, automatisch aufgezeichnet und bei Bedarf ausgelesen werden können. Eine Beispielanzeige im benutzerdefinierten Verlaufsdaten-Steuerelement sehen Sie in Bild 3.
Das Steuerelement listet zuletzt besuchte URLs (Bild 3)
Autor
Basis für die Informationsermittlung ist das Interface IUrlHistory, über das Sie die Internet-Explorer-Verlaufsdaten verwalten. Die Schnittstelle ist Bestandteil des Windows-API, in C++ umgesetzt und auf der Microsoft-Webseite unter [5] dokumentiert. Auf CodeProject [6] finden Sie ein C#-Beispiel, welches das Auslesen der Informationen zeigt. Alle API-Deklarationsanweisungen wurden an C# angepasst. Die Funktionalitäten zur Informationsabfrage wurden dabei in die Assembly UrlHistoryLibrary.dll ausgelagert, die sich per Verweis an beliebige .NET-Projekte anbinden lässt. Angebunden an ein eigenes Projekt muss die DLL immer zusammen mit dem eigenen Programm ausgeliefert werden.An dieser Stelle wird das Verlaufssteuerelement in Visual Basic .NET umgesetzt. Eine externe Assembly-DLL soll hier nicht verwendet werden. Folglich ist die API-Funktionalität in VB.NET zu codieren. Basis für die Analyse ist die Klasse win32api.vb, die der Steuerelementbibliothek ExtendedControlsLib hinzugefügt wurde.In der Quelldatei der Klasse befinden sich die Klassen STATURLEnumerator, SortFileTimeAscendingHelper, UrlHistoryWrapperClass und UrlHistoryClass. Teile der Klassen sind verschachtelt. In win32api.vb werden zunächst diverse Namensräume importiert, über die System-, Ein- und Ausgabefunktionen, Kollektionen, Text und Interoperabilitätsfunktionen vereinfacht nutzbar sind. Gegenüber der C#-Klasse des CodeProject-Beispiels wurden diverse Anpassungen vorgenommen, um eine korrekte Verarbeitung in VB.NET sicherzustellen.
Imports System
Imports System.IO
Imports System.Collections
Imports System.Text
Imports System.Runtime.InteropServices
Public Class Win32api
Public Class UrlHistoryClass
...
End Class
End Class
Public Class SortFileTimeAscendingHelper
...
End Class
Public Class UrlHistoryWrapperClass
Public Class STATURLEnumerator
...
End Class
End Class
Das API soll an dieser Stelle nur grundlegend beschrieben werden, ehe dann die praktische Verwendung gezeigt wird. Weiterführende Informationen entnehmen Sie bei Bedarf bitte dem Windows-API. Im ersten Schritt wird die Enumeration STATURL_QUERYFLAGS definiert, über die der Enumerationsdatentyp für die QueryUrl-API-Funktion sowie der Parameter dwFlags bestimmt werden:
Public Enum STATURL_QUERYFLAGS As UInteger
STATURL_QUERYFLAG_ISCACHED = &H10000
STATURL_QUERYFLAG_NOURL = &H20000
STATURL_QUERYFLAG_NOTITLE = &H40000
STATURL_QUERYFLAG_TOPLEVEL = &H80000
End Enum
Die dwFlags-Parameter der Datenstruktur STATURL und die SetFilter-Methode werden über die Enumeration STATURLFLAGS definiert.
Public Enum STATURLFLAGS As UInteger
STATURLFLAG_ISCACHED = &H1
STATURLFLAG_ISTOPLEVEL = &H2
End Enum
Entsprechend werden die Flags für die Methode AddHistoryEntry über die Enumeration ADDURL_FLAG definiert.
Public Enum ADDURL_FLAG As UInteger
ADDURL_ADDTOHISTORYANDCACHE = 0
ADDURL_ADDTOCACHE = 1
End Enum
Alle URL-Statistikinformationen (URL, Titel, Datum zum letzten Besuch, Datum zur letzten Aktualisierung, Verfallsdatum, Flags) werden über die Datenstruktur STATURL zusammengefasst. Die COM-Informationen werden dabei über MarshallAs-Attribute angepasst. Intern verwaltet die Datums- und Zeitinformationen der Typ ComTypes.FILETIME. Alle Daten sind öffentlich deklariert, da öffentliche Eigenschaften den Datenzugriff unter .NET mit .NET-spezifischen Rückgabewerten erleichtern. Über die öffentliche und nur lesbare Eigenschaft URL kann ein URL im Zeichenkettenformat abgefragt werden. Die Eigenschaft Title liefert den Titel, LastVisited das Datum des letzten Besuchs im .NET-Date-Format, LastUpdated das Datum der letzten Aktualisierung (.NET-Date-Format) und die Eigenschaft Expires das Verfallsdatum (.NET-Date-Format), siehe Listing 1.
Listing 1: Datenstruktur für Windows-URL-Informationen
<StructLayout(LayoutKind.Sequential)>
Public Structure STATURL
Public cbSize As Integer
<MarshalAs(UnmanagedType.LPWStr)>
Public pwcsUrl As String
<MarshalAs(UnmanagedType.LPWStr)>
Public pwcsTitle As String
Public ftLastVisited As ComTypes.FILETIME
Public ftLastUpdated As ComTypes.FILETIME
Public ftExpires As ComTypes.FILETIME
Public dwFlags As STATURLFLAGS
Public ReadOnly Property URL As String
Get
Return pwcsUrl
End Get
End Property
Public ReadOnly Property Title As String
Get
If pwcsUrl.StartsWith("file:") Then
Return CannonializeURL(pwcsUrl,
shlwapi_URL.URL_UNESCAPE)
.Substring(8).Replace("/"c, "\"c)
Else
Return pwcsTitle
End If
End Get
End Property
Public ReadOnly Property LastVisited As Date
Get
Return FileTimeToDateTime(
ftLastVisited).ToLocalTime()
End Get
End Property
Public ReadOnly Property LastUpdated As Date
Get
Return FileTimeToDateTime(
ftLastUpdated).ToLocalTime()
End Get
End Property
Public ReadOnly Property Expires As Date
Get
Try
Return FileTimeToDateTime(
ftExpires).ToLocalTime()
Catch __unusedException1__ As Exception
Return Date.Now
End Try
End Get
End Property
End Structure
<StructLayout(LayoutKind.Sequential)>
Public Structure UUID
Public Data1 As Integer
Public Data2 As Short
Public Data3 As Short
Public Data4 As Byte()
End Structure
Um die Verlaufsdaten auszulesen, muss der Zugriff auf diverse COM-Schnittstellen sichergestellt werden. Die hierfür erforderlichen Deklarationen in der Syntax von VB.NET sind in Listing 2 zusammengestellt. Die Anbindung erfolgt über das Attribut ComImport und den Interface-Typ ComInterfaceType.InterfaceIsIUnknown.
Listing 2: Deklarationen zum Anbinden von COM-Schnittstellen
<ComImport>
<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
<Guid("3C374A42-BAE4-11CF-BF7D-00AA006946EE")>
Public Interface IEnumSTATURL
Sub [Next](ByVal celt As Integer,
ByRef rgelt As STATURL,
<Out> ByRef pceltFetched As Integer)
Sub Skip(ByVal celt As Integer)
Sub Reset()
Sub Clone(<Out> ByRef ppenum As IEnumSTATURL)
Sub SetFilter(<MarshalAs(UnmanagedType.LPWStr)>
ByVal poszFilter As String,
ByVal dwFlags As STATURLFLAGS)
End Interface
<ComImport>
<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
<Guid("3C374A41-BAE4-11CF-BF7D-00AA006946EE")>
Public Interface IUrlHistoryStg
Sub AddUrl(ByVal pocsUrl As String,
ByVal pocsTitle As String,
ByVal dwFlags As ADDURL_FLAG)
Sub DeleteUrl(ByVal pocsUrl As String,
ByVal dwFlags As Integer)
Sub QueryUrl(<MarshalAs(UnmanagedType.LPWStr)>
ByVal pocsUrl As String,
ByVal dwFlags As STATURL_QUERYFLAGS,
ByRef lpSTATURL As STATURL)
Sub BindToObject(<[In]> ByVal pocsUrl As String,
<[In]> ByVal riid As UUID, ByVal ppvOut As IntPtr)
ReadOnly Property EnumUrls As Object
End Interface
<ComImport>
<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
<Guid("AFA0DC11-C313-11D0-831A-00C04FD5AE38")>
Public Interface IUrlHistoryStg2
Inherits IUrlHistoryStg
Overloads Sub AddUrl(ByVal pocsUrl As String,
ByVal pocsTitle As String,
ByVal dwFlags As ADDURL_FLAG)
Overloads Sub DeleteUrl(ByVal pocsUrl As String,
ByVal dwFlags As Integer)
Overloads Sub QueryUrl(
<MarshalAs(UnmanagedType.LPWStr)>
ByVal pocsUrl As String,
ByVal dwFlags As STATURL_QUERYFLAGS,
ByRef lpSTATURL As STATURL)
Overloads Sub BindToObject(<[In]>
ByVal pocsUrl As String, <[In]> ByVal riid As
UUID, ByVal ppvOut As IntPtr)
Overloads ReadOnly Property EnumUrls As
Win32api.IEnumSTATURL 'Typ 'Object' durch
' Enumerationsdatentyp ersetzt
Sub AddUrlAndNotify(ByVal pocsUrl As String,
ByVal pocsTitle As String, ByVal dwFlags As
Integer, ByVal fWriteHistory As Integer,
ByVal poctNotify As Object,
ByVal punkISFolder As Object)
Sub ClearHistory()
End Interface
<ComImport>
<Guid("3C374A40-BAE4-11CF-BF7D-00AA006946EE")>
Public Class UrlHistoryClass
End Class
Zusätzlich wird eine eindeutige schnittstellenspezifische GUID angegeben. Jedes Interface wird in einen Public Interface- und End Interface-Block eingefasst, der seinerseits die Methoden des jeweiligen Interfaces mitsamt den zugehörigen Aufrufparametern und deren Datentypen definiert. Das Interface IEnumSTATURL enumeriert die zwischengespeicherten URLs (Cached URLs). Das Interface IUrlHistoryStg verwaltet die URL-Einträge für den jeweils aktiven Benutzer.Das Interface IUrlHistoryStg2 bietet die Grundfunktionen des Interfaces IUrlHistoryStg sowie erweiterte Funktionen für die URL-Verwaltung des aktiven Benutzers (zum Beispiel Verlaufsdaten löschen, URL mit Benachrichtigung ergänzen). Abschließend wird die COM-Klasse UrlHistoryClass unter Angabe der zugehörigen GUID importiert.So viel für diesmal. In der kommenden Folge dieser Serie lernen Sie unter anderem die Klasse SortFileTimeAscendingHelper kennen, welche die Schnittstelle IComparer implementiert und zum Sortieren von Dateilisten nach Datum und Uhrzeit taugt.
Fussnoten
- Andreas Maslo, History Control, dotnetpro 6/2023, Seite 136 ff.,
- Andreas Maslo, MRU-Programme ermitteln, dotnetpro 12/2023, Seite 136 ff.,
- Shellbag Analyzer & Cleaner,
- Windows ShellBag Forensics in Depth,
- MS Learn, IUrlHistory,
- Beispielprojekt auf CodeProject,
- Shellbags Explorer und SBECmd,
- NirSoft ShellBagsView,