Get Last insert date of MSC Type USB Devices
Scope And Usage:
This script runs on a live machine.
On a live machine, without SYSTEM level access this is the maximum USB timestamp data we can fetch. I know we can also get first connect time but that is easy and is not part of this blog post.
It is not possible to get more USB data from
USBSTOR properties with nt-authority\system privileges. If you have SYSTEM level privileges use the
previous post to retrieve.
the below PowerShell script queries local HKLM hive to get only USB disk data logged under
\\SYSTEM\ControlSet001\Enum\USB\. Only pen drives get logged here, so
you will not see phone history.
So let us begin.....
The first portion of the script is only to create a function that will allow us to get the last write time of any key in the registry. The complete script can be found at [reference] and I did not create it, I am using it as is.
If you can import modules in powershell you can delete the function and import the script directly as a module.
#use import-module "path the script"
My part of the script is an implementation of the research paper published (reference), to query locations we can touch with god-level access on a live machine to get last connect data of USB devices.
A big shout out to the research team who published the article.
Function Get-RegistryKeyTimestamp {
[OutputType('Microsoft.Registry.Timestamp')]
[cmdletbinding(
DefaultParameterSetName = 'ByValue'
)]
Param (
[parameter(ValueFromPipeline=$True, ParameterSetName='ByValue')]
[Microsoft.Win32.RegistryKey]$RegistryKey,
[parameter(ParameterSetName='ByPath')]
[string]$SubKey,
[parameter(ParameterSetName='ByPath')]
[Microsoft.Win32.RegistryHive]$RegistryHive,
[parameter(ParameterSetName='ByPath')]
[string]$Computername
)
Begin {
Try {
[void][advapi32]
} Catch {
$Domain = [AppDomain]::CurrentDomain
$DynAssembly = New-Object System.Reflection.AssemblyName('RegAssembly')
$AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('RegistryTimeStampModule', $False)
$TypeBuilder = $ModuleBuilder.DefineType('advapi32', 'Public, Class')
$PInvokeMethod = $TypeBuilder.DefineMethod(
'RegQueryInfoKey',
[Reflection.MethodAttributes] 'PrivateScope, Public, Static, HideBySig, PinvokeImpl',
[IntPtr],
[Type[]] @(
[Microsoft.Win32.SafeHandles.SafeRegistryHandle],
[System.Text.StringBuilder],
[UInt32 ].MakeByRefType(),
[UInt32],
[UInt32 ].MakeByRefType(),
[UInt32 ].MakeByRefType(),
[UInt32 ].MakeByRefType(),
[UInt32 ].MakeByRefType(),
[UInt32 ].MakeByRefType(),
[UInt32 ].MakeByRefType(),
[UInt32 ].MakeByRefType(),
[long].MakeByRefType()
)
)
$DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String]))
$FieldArray = [Reflection.FieldInfo[]] @(
[Runtime.InteropServices.DllImportAttribute].GetField('EntryPoint'),
[Runtime.InteropServices.DllImportAttribute].GetField('SetLastError')
)
$FieldValueArray = [Object[]] @(
'RegQueryInfoKey',
$True
)
$SetLastErrorCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder(
$DllImportConstructor,
@('advapi32.dll'),
$FieldArray,
$FieldValueArray
)
$PInvokeMethod.SetCustomAttribute($SetLastErrorCustomAttribute)
[void]$TypeBuilder.CreateType()
}
}
Process {
$ClassLength = 255
[long]$TimeStamp = $null
If ($PSCmdlet.ParameterSetName -eq 'ByPath') {
$RegistryKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($RegistryHive, $Computername).OpenSubKey($SubKey)
If ($RegistryKey -isnot [Microsoft.Win32.RegistryKey]) {
Throw "Cannot open or locate $SubKey on $Computername"
}
}
$ClassName = New-Object System.Text.StringBuilder $RegistryKey.Name
$RegistryHandle = $RegistryKey.Handle
$Return = [advapi32]::RegQueryInfoKey(
$RegistryHandle,
$ClassName,
[ref]$ClassLength,
$Null,
[ref]$Null,
[ref]$Null,
[ref]$Null,
[ref]$Null,
[ref]$Null,
[ref]$Null,
[ref]$Null,
[ref]$TimeStamp
)
Switch ($Return) {
0 {
$LastWriteTime = (Get-Date $TimeStamp).AddYears(1600)
$Object = [pscustomobject]@{
FullName = $RegistryKey.Name
Name = $RegistryKey.Name -replace '.*\\(.*)','$1'
LastWriteTime = $LastWriteTime
}
$Object
}
122 {
Throw "ERROR_INSUFFICIENT_BUFFER (0x7a)"
}
Default {
Throw "Error ($return) occurred"
}
}
}
}
$usbstor =Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Enum\USBSTOR\*\*'
function list_msc_devices{
$usbstor =Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Enum\USBSTOR\*\*'
$output=@()
foreach ($x in $usbstor){
$instance_name=$x.PSParentPath.Split("\")[-1]
$serial=''
if($x.PSChildName -match '&0$'){
$serial=$x.PSChildName.Substring(0,$x.PSChildName.Length-2)}
else {$serial=$x.PSChildName}
$friendlyname=$x.FriendlyName
$output += New-Object -TypeName psobject -Property @{Name=$friendlyname;Serial=$serial;instance=$instance_name}
}
return $output
}
function add_Last_in{
$lastin=@()
$output=list_msc_devices
$serial = list_msc_devices | select -Property Serial
foreach($o in $output){
$ss= $o.Serial.tostring()
$path='HKLM:\SYSTEM\ControlSet001\Enum\USB\*\'+ $ss
$u=Get-ItemProperty -Path $path
foreach($usbpath in $u)
{
$path =$usbpath.PSPath.Split(":")[2]
if ($path -ne $null)
{
$instanceid=$path.Split("\")[-2]
$subkey_last="SYSTEM\ControlSet001\Enum\USB\"+$instanceid+"\" +$ss
$last_time=Get-RegistryKeyTimestamp -RegistryHive LocalMachine -SubKey $subkey_last
$o | Add-Member -MemberType NoteProperty "Last_In" -Value $last_time.LastWriteTime.ToString()
$lastin+=$o
}
}
}
return $lastin
}
function add_First_in{
$first_in=@()
$inputobject=add_Last_in
foreach ($row in $inputobject)
{
$keypath='SYSTEM\ControlSet001\Control\DeviceClasses\{53f56307-b6bf-11d0-94f2-00a0c91efb8b}\##?#USBSTOR#'+$row.instance+"#"+$row.Serial +"&0#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}"
$last_time=(Get-RegistryKeyTimestamp -RegistryHive LocalMachine -SubKey $keypath.ToString()).LastWriteTime.ToString()
$row | Add-Member -MemberType NoteProperty "First_In" -Value $last_time
$first_in+=$row
}
return $first_in
}
Function get_msc_usb{
$usb=add_First_in
$usb | select -Property Name,First_In,Last_In,Serial | Export-Csv "C:\Windows\Temp\usbdata.csv"
}
get_msc_usb
References:
https://gallery.technet.microsoft.com/scriptcenter/Get-RegistryKeyLastWriteTim-63f4dd96
https://www.researchgate.net/publication/318514858_USB_Storage_Device_Forensics_for_Windows_10