如何在以前连接的USB设备上获取时间戳?

时间:2017-05-29 22:44:37

标签: c# windows powershell usb-drive computer-forensics

我试图获取一个旧的PowerShell脚本来显示以前连接的USB设备的时间。在阅读了blogs之类的一些取证this后,我从this script找到了this blog。 (杰森沃克的剧本。)

不幸的是,它没有显示任何时间戳或有关设备的任何其他有用的详细信息。所以我希望there should be a way to get that too。只有我没有看到如何融入这一点。

Function Get-USBHistory { 
 [CmdletBinding()] 
Param 
( 
[parameter(ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)] 
    [alias("CN","Computer")] 
    [String[]]$ComputerName=$Env:COMPUTERNAME, 
    [Switch]$Ping     
) 

 Begin { 
     $TempErrorAction = $ErrorActionPreference 
     $ErrorActionPreference = "Stop" 
     $Hive   = "LocalMachine" 
     $Key    = "SYSTEM\CurrentControlSet\Enum\USBSTOR" 
  } 

  Process 
  {             
     $USBDevices      = @() 
     $ComputerCounter = 0         

     ForEach($Computer in $ComputerName) 
     { 
        $USBSTORSubKeys1 = @() 
        $ChildSubkeys    = @() 
        $ChildSubkeys1   = @() 

        $ComputerCounter++         
        $Computer = $Computer.Trim().ToUpper() 
        Write-Progress -Activity "Collecting USB history" -Status "Retrieving USB history from $Computer" -PercentComplete (($ComputerCounter/($ComputerName.Count)*100)) 


        If($Ping) 
        { 
           If(-not (Test-Connection -ComputerName $Computer -Count 1 -Quiet)) 
           { 
              Write-Warning "Ping failed on $Computer" 
              Continue 
           } 
        }#end if ping  

         Try 
         { 
            $Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($Hive,$Computer) 
            $USBSTORKey = $Reg.OpenSubKey($Key) 
            $USBSTORSubKeys1  = $USBSTORKey.GetSubKeyNames() 
         }#end try              
         Catch 
         { 
            Write-Warning "There was an error connecting to the registry on $Computer or USBSTOR key not found. Ensure the remote registry service is running on the remote machine." 
         }#end catch 

         ForEach($SubKey1 in $USBSTORSubKeys1) 
         {     
            $ErrorActionPreference = "Continue" 
            $Key2 = "SYSTEM\CurrentControlSet\Enum\USBSTOR\$SubKey1" 
            $RegSubKey2  = $Reg.OpenSubKey($Key2) 
            $SubkeyName2 = $RegSubKey2.GetSubKeyNames() 

            $ChildSubkeys   += "$Key2\$SubKeyName2" 
            $RegSubKey2.Close()         
         }#end foreach SubKey1 

         ForEach($Child in $ChildSubkeys) 
         { 

            If($Child -match " ") 
            { 
               $BabySubkey = $null 
               $ChildSubkey1 = ($Child.split(" "))[0] 

               $SplitChildSubkey1 = $ChildSubkey1.split("\") 

               0..4 | Foreach{ [String]$BabySubkey += ($SplitChildSubkey1[$_]) + "\"}  

               $ChildSubkeys1 += $BabySubkey + ($Child.split(" ")[-1]) 
               $ChildSubkeys1 += $ChildSubkey1 

            } 
            Else 
            { 
               $ChildSubkeys1 += $Child 
            } 
                $ChildSubKeys1.count 
         }#end foreach ChildSubkeys 

         ForEach($ChildSubkey1 in $ChildSubkeys1) 
         {     
            $USBKey      = $Reg.OpenSubKey($ChildSubkey1) 
            $USBDevice   = $USBKey.GetValue('FriendlyName')  
            If($USBDevice) 
            {     
               $USBDevices += New-Object -TypeName PSObject -Property @{ 
                     USBDevice = $USBDevice 
                     Computer  = $Computer 
                     Serial    = $ChildSubkey1.Split("\")[-1] 
                       } 
             } 
                 $USBKey.Close()                                           
          }#end foreach ChildSubKey2 

                 $USBSTORKey.Close()            
         #Display results         
     $USBDevices | Select Computer,USBDevice,Serial 
     }#end foreach computer  

  }#end process 

  End 
  {         
     #Set error action preference back to original setting         
     $ErrorActionPreference = $TempErrorAction          
  } 

}#end function 

和C#代码:

using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
class Program
{
    static void Main(string[] args)
    {
        string usbStor = @"SYSTEM\ControlSet001\Enum\USBSTOR";
        using (var keyUsbStor = Registry.LocalMachine.OpenSubKey(usbStor))
        {
            var usbDevices = from className in keyUsbStor.GetSubKeyNames()
                             let keyUsbClass = keyUsbStor.OpenSubKey(className)
                             from instanceName in keyUsbClass.GetSubKeyNames()
                             let keyUsbInstance = new RegistryKeyEx(keyUsbClass.OpenSubKey(instanceName))
                             select new
                             {
                                 UsbName = keyUsbInstance.Key.GetValue("FriendlyName"),
                                 ConnectTime = keyUsbInstance.LastWriteTime
                             };
            foreach (var usbDevice in usbDevices.OrderBy(x => x.ConnectTime))
            {
                Console.WriteLine("({0}) -- '{1}'", usbDevice.ConnectTime, usbDevice.UsbName);
            }
        }
    }
}
/// <summary>
/// Wraps a RegistryKey object and corresponding last write time.
/// </summary>
/// <remarks>
/// .NET doesn't expose the last write time for a registry key 
/// in the RegistryKey class, so P/Invoke is required.
/// </remarks>
public class RegistryKeyEx
{
    #region P/Invoke Declarations
    // This declaration is intended to be used for the last write time only. int is used
    // instead of more convenient types so that dummy values of 0 reduce verbosity.
    [DllImport("advapi32.dll", EntryPoint = "RegQueryInfoKey", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
    extern private static int RegQueryInfoKey(
        SafeRegistryHandle hkey,
        int lpClass,
        int lpcbClass,
        int lpReserved,
        int lpcSubKeys,
        int lpcbMaxSubKeyLen,
        int lpcbMaxClassLen,
        int lpcValues,
        int lpcbMaxValueNameLen,
        int lpcbMaxValueLen,
        int lpcbSecurityDescriptor,
        IntPtr lpftLastWriteTime);
    #endregion
    #region Public Poperties
    /// <summary>
    /// Gets the registry key owned by the info object.
    /// </summary>
    public RegistryKey Key { get; private set; }
    /// <summary>
    /// Gets the last write time for the corresponding registry key.
    /// </summary>
    public DateTime LastWriteTime { get; private set; }
    #endregion
    /// <summary>
    /// Creates and initializes a new RegistryKeyInfo object from the provided RegistryKey object.
    /// </summary>
    /// <param name="key">RegistryKey component providing a handle to the key.</param>
    public RegistryKeyEx(RegistryKey key)
    {
        Key = key;
        SetLastWriteTime();
    }
    /// <summary>
    /// Creates and initializes a new RegistryKeyInfo object from a registry key path string.
    /// </summary>
    /// <param name="parent">Parent key for the key being loaded.</param>
    /// <param name="keyName">Path to the registry key.</param>
    public RegistryKeyEx(RegistryKey parent, string keyName)
        : this(parent.OpenSubKey(keyName))
    { }
    /// <summary>
    /// Queries the currently set registry key through P/Invoke for the last write time.
    /// </summary>
    private void SetLastWriteTime()
    {
        Debug.Assert(Key != null, "RegistryKey component must be initialized");
        GCHandle pin = new GCHandle();
        long lastWriteTime = 0;
        try
        {
            pin = GCHandle.Alloc(lastWriteTime, GCHandleType.Pinned);
            if (RegQueryInfoKey(Key.Handle, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pin.AddrOfPinnedObject()) == 0)
            {
                LastWriteTime = DateTime.FromFileTime((long)pin.Target);
            }
            else
            {
                LastWriteTime = DateTime.MinValue;
            }
        }
        finally
        {
            if (pin.IsAllocated)
            {
                pin.Free();
            }
        }
    }
}

(抱歉,我无法正确显示PSH代码。)

如何使用它来改进脚本?

更新:2017-11-06

根据@ iRon的建议,我尝试使用RegEdit直接访问注册表路径HKLM\SYSTEM\CurrentControlSet\Enum\USBSTOR\<drive>\Propertie‌​s,但后来我收到了权限错误,这很奇怪,因为我的用户帐户是Admin。 (这是在Win8.1上)

enter image description here

我发现的其他一些选项是:

  1. 使用Windows内置Event Viewer并制作自定义视图。但是,这需要您启用事件日志。
  2. 同样,将logparser与CMD批script一起使用,如herehere所示。 (需要启用事件日志。)
  3. 按照here所述进行取证,检查各种注册表项和...\Windows\inf\setupapi.dev.log中的日志文件以获取第一个连接日期,但如何获取最后一个连接则更加明确。 (据说通过比较\NTUSER\<username>\Software\Microsoft\Windows\Explorer\MountPoints2数据,但我找不到它。)
  4. 这本书&#34; Windows Registry Forensics: Advanced Digital Forensic Analysis of the Windows Registry&#34;还提供了一些额外的提示(3)从第95页开始。
  5. 可能有用的PS单线程:

    Get-WinEvent -LogName Microsoft-Windows-DriverFrameworks-UserMode/Operational | where {$_.Id -eq "2003" -or $_.Id -eq "2102"} | Format-Table –Property TimeCreated, Id, Message -AutoSize -Wrap
    

    这为事件(2003,2102)提供了可以进一步解析的消息内容的时间戳。

    TimeCreated           Id Message                                                                                                                                                                                                                  
    -----------           -- -------                                                                                                                                                                                                                  
    2017-11-09 13:37:04 2102 Forwarded a finished Pnp or Power operation (27, 2) to the lower driver for device                                                                                                                                       
                             SWD\WPDBUSENUM\_??_USBSTOR#DISK&VEN_KINGSTON&PROD_DATATRAVELER_G2&REV_PMAP#YYYYY&0#{XXXXX} with status 0x0.                                                            
    2017-11-09 13:37:04 2102 Forwarded a finished Pnp or Power operation (27, 23) to the lower driver for device                                                                                                                                      
                             SWD\WPDBUSENUM\_??_USBSTOR#DISK&VEN_KINGSTON&PROD_DATATRAVELER_G2&REV_PMAP#YYYYY&0#{XXXXX} with status 0x0.                                                            
    2017-11-09 13:34:38 2003 The UMDF Host Process ({XXXXX}) has been asked to load drivers for device                                                                                                                 
                             SWD\WPDBUSENUM\_??_USBSTOR#DISK&VEN_KINGSTON&PROD_DATATRAVELER_G2&REV_PMAP#YYYYY&0#{XXXXX}.                                                                            
    2017-11-06 15:18:41 2102 Forwarded a finished Pnp or Power operation (27, 2) to the lower driver for device SWD\WPDBUSENUM\{XXXXX}#0000000000007E00 with status 0x0.                                               
    2017-11-06 15:18:41 2102 Forwarded a finished Pnp or Power operation (27, 23) to the lower driver for device SWD\WPDBUSENUM\{XXXXX}#0000000000007E00 with status 0x0.                                              
    2017-11-06 15:18:13 2003 The UMDF Host Process ({XXXXX}) has been asked to load drivers for device SWD\WPDBUSENUM\{XXXXX}#0000000000007E00.                                         
    

1 个答案:

答案 0 :(得分:1)

这还没有完成但是应该让你入门?

$code = @"
using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;

/// <summary>
/// Wraps a RegistryKey object and corresponding last write time.
/// </summary>
/// <remarks>
/// .NET doesn't expose the last write time for a registry key 
/// in the RegistryKey class, so P/Invoke is required.
/// </remarks>
public class RegistryKeyEx
{
    #region P/Invoke Declarations
    // This declaration is intended to be used for the last write time only. int is used
    // instead of more convenient types so that dummy values of 0 reduce verbosity.
    [DllImport("advapi32.dll", EntryPoint = "RegQueryInfoKey", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
    extern private static int RegQueryInfoKey(
        SafeRegistryHandle hkey,
        int lpClass,
        int lpcbClass,
        int lpReserved,
        int lpcSubKeys,
        int lpcbMaxSubKeyLen,
        int lpcbMaxClassLen,
        int lpcValues,
        int lpcbMaxValueNameLen,
        int lpcbMaxValueLen,
        int lpcbSecurityDescriptor,
        IntPtr lpftLastWriteTime);
    #endregion
    #region Public Poperties
    /// <summary>
    /// Gets the registry key owned by the info object.
    /// </summary>
    public RegistryKey Key { get; private set; }
    /// <summary>
    /// Gets the last write time for the corresponding registry key.
    /// </summary>
    public DateTime LastWriteTime { get; private set; }
    #endregion
    /// <summary>
    /// Creates and initializes a new RegistryKeyInfo object from the provided RegistryKey object.
    /// </summary>
    /// <param name="key">RegistryKey component providing a handle to the key.</param>
    public RegistryKeyEx(RegistryKey key)
    {
        Key = key;
        SetLastWriteTime();
    }
    /// <summary>
    /// Creates and initializes a new RegistryKeyInfo object from a registry key path string.
    /// </summary>
    /// <param name="parent">Parent key for the key being loaded.</param>
    /// <param name="keyName">Path to the registry key.</param>
    public RegistryKeyEx(RegistryKey parent, string keyName)
        : this(parent.OpenSubKey(keyName))
    { }
    /// <summary>
    /// Queries the currently set registry key through P/Invoke for the last write time.
    /// </summary>
    private void SetLastWriteTime()
    {
        Debug.Assert(Key != null, "RegistryKey component must be initialized");
        GCHandle pin = new GCHandle();
        long lastWriteTime = 0;
        try
        {
            pin = GCHandle.Alloc(lastWriteTime, GCHandleType.Pinned);
            if (RegQueryInfoKey(Key.Handle, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pin.AddrOfPinnedObject()) == 0)
            {
                LastWriteTime = DateTime.FromFileTime((long)pin.Target);
            }
            else
            {
                LastWriteTime = DateTime.MinValue;
            }
        }
        finally
        {
            if (pin.IsAllocated)
            {
                pin.Free();
            }
        }
    }
}
"@

$type = Add-Type -TypeDefinition $code -Language CSharp

$devices = Get-Item HKLM:\SYSTEM\ControlSet001\Enum\USBSTOR\*

$result = foreach($device in $devices) {
    Write-Verbose -Verbose "New device: $($device.PSPath)"

    Write-Verbose -Verbose "GetClass"
    foreach($classname in $device.GetSubKeyNames()) {
        $class = $device.OpenSubKey($class)

        if($class -eq $null) { 
            Write-Verbose -Verbose "Class is null" 
            continue
        }

        Write-Verbose -Verbose "GetInstance"
        foreach($instancename in $class.GetSubKeyNames()) {
            $instance = $class.OpenSubKey($instancename)

            if($instance -eq $null) {
                Write-Verbose -Verbose "Instance is null"
                continue
            }

            Write-Verbose -Verbose "RegistryKeyEx"
            $keyEx = New-Object RegistryKeyEx $instance

            [pscustomobject]@{
                FriendlyName = $keyEx.key.GetValue('FriendlyName')
                DevicePath = $device.PSPath
                LastWriteTime = $keyEx.LastWriteTime
            }
        }
    }
}

编辑:(通过not2qubit)

这个脚本是内嵌的C#sharp。当前版本提供以下输出:

VERBOSE: New device: Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USBSTOR\Disk&Ven_Kingston&Prod_DataTraveler_G2&Rev_PMAP
VERBOSE: GetClass
VERBOSE: GetInstance
VERBOSE: RegistryKeyEx
VERBOSE: New device: Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USBSTOR\Disk&Ven_WD&Prod_My_Passport_0730&Rev_1015
VERBOSE: GetClass
VERBOSE: Class is null
VERBOSE: New device: Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USBSTOR\Other&Ven_WD&Prod_SES_Device&Rev_1015
VERBOSE: GetClass
VERBOSE: GetInstance
VERBOSE: RegistryKeyEx

因此缺少时间戳......

编辑:

除非您查看$result变量。

PS C:\> $result

FriendlyName                    DevicePath                                                                                                                           LastWriteTime      
------------                    ----------                                                                                                                           -------------      
Corsair Survivor 3.0 USB Device Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USBSTOR\Disk&Ven_Corsair&Prod_Survivor_3.0&Rev_1.00 2017-11-05 21:08:25

PS C:\> get-date

November 11, 2017 17:02:09

这将为您提供C#代码示例中的内容。这些信息是否足以满足您的需求,我无法说出来。