【问题标题】:How can I get timestamps on previously connected USB devices?如何获取之前连接的 USB 设备的时间戳?
【发布时间】:2017-05-29 22:44:37
【问题描述】:

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

很遗憾,它没有显示任何时间戳或有关设备的任何其他有用详细信息。所以我希望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\&lt;drive&gt;\Propertie‌​s,但随后出现权限错误,这很奇怪,因为我的用户帐户是Admin。 (这是在Win8.1上)

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

  1. 使用 Windows 内置 Event Viewer 并制作自定义视图。但是,这需要您已经启用事件日志。
  2. 类似地使用logparser 和CMD 批处理script,如herehere 所示。 (需要启用事件日志。)
  3. 按照here 的描述进行取证,他们检查各种注册表项和日志文件:...\Windows\inf\setupapi.dev.log 以获取第一个连接日期,但如何获得最后一个连接更不清楚。 (据说是通过比较\NTUSER\&lt;username&gt;\Software\Microsoft\Windows\Explorer\MountPoints2的数据,但我找不到。)
  4. 此外,“Windows Registry Forensics: Advanced Digital Forensic Analysis of the Windows Registry”一书还提供了一些关于第 95 页及以后的 (3) 的额外提示。

一个可能有用的 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.                                         

【问题讨论】:

  • 你是在系统账户下运行的吗?显然,您需要nt authority\system 权限才能更深入地查看:HKLM\SYSTEM\CurrentControlSet\Enum\USBSTOR\&lt;drive&gt;\Properties`. Have you tried to pull your information with e.g. RegEdit.exe`?
  • @iRon 有趣,我无法访问它,即使我是管理员。
  • 试试 PSEXEC -i -s -d PowerShell.exe 然后 RegEdit 或你的脚本。
  • 这也不起作用,因为我得到“句柄无效”。错误。请注意,我已经以Administrator 运行所有shell,那么“系统帐户”是什么意思?
  • 使用PowerShell命令Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Enum\USBSTOR\Disk&amp;Ven_IT1165&amp;Prod_USB_Flash_Disk&amp;Rev_0.00\000000005BE51F59&amp;0\' -Name *透露了很多信息。但是,我没有看到任何有关使用时间采样的信息。

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


【解决方案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# 语言。当前版本给出以下输出:

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# 代码示例中的内容。我不能说这些信息是否足以满足您的需求。

【讨论】:

  • 我没有否决您的答案,但仍然希望了解更多关于您所做的与我已经发布的不同之处的更多信息。看起来也很奇怪,因为您似乎将 PS 与 C# 混合在一起......
  • 您提供的脚本没有给出任何时间戳。我将输出添加到您的答案中。如果不正确,请编辑以显示您得到的结果。
  • 哦,您似乎错过了我将所有内容都放入 $result 的事实。
  • 啊,好多了!但它似乎只获得了第一个设备实例(根据我编辑的内容),第二个是部分空的,因为Class is null 而第三个根本没有显示。
  • 知道为什么切换DevicePath = ...LastWriteTime = ... 的顺序会产生截然不同的结果吗?
猜你喜欢
  • 2011-03-20
  • 2018-04-03
  • 1970-01-01
  • 1970-01-01
  • 2010-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多