Last active
May 9, 2023 20:36
-
-
Save mattifestation/d1e7eeb63d2a97a124923ff482592d6d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# These keyword values can be obtained with: logman query providers Microsoft-Windows-Kernel-Registry | |
[Flags()] | |
enum RegistryOptions { | |
CloseKey = 0x00000001 | |
QuerySecurityKey = 0x00000002 | |
SetSecurityKey = 0x00000004 | |
EnumerateValueKey = 0x00000010 | |
QueryMultipleValueKey = 0x00000020 | |
SetInformationKey = 0x00000040 | |
FlushKey = 0x00000080 | |
SetValueKey = 0x00000100 | |
DeleteValueKey = 0x00000200 | |
QueryValueKey = 0x00000400 | |
EnumerateKey = 0x00000800 | |
CreateKey = 0x00001000 | |
OpenKey = 0x00002000 | |
DeleteKey = 0x00004000 | |
QueryKey = 0x00008000 | |
} | |
# These keyword values can be obtained with: logman query providers Microsoft-Windows-Kernel-Network | |
[Flags()] | |
enum NetworkOptions { | |
IPv4 = 0x00000010 | |
IPv6 = 0x00000020 | |
} | |
# These keyword values can be obtained with: logman query providers Microsoft-Windows-Kernel-Process | |
[Flags()] | |
enum ProcessOptions { | |
Process = 0x00000010 | |
Thread = 0x00000020 | |
Image = 0x00000040 | |
Freeze = 0x00000200 | |
} | |
# These keyword values can be obtained with: logman query providers Microsoft-Windows-Kernel-File | |
[Flags()] | |
enum FileOptions { | |
FileName = 0x00000010 | |
FileIO = 0x00000020 | |
Create = 0x00000080 | |
Read = 0x00000100 | |
Write = 0x00000200 | |
DeletePath = 0x00000400 | |
RenameSetlinkPath = 0x00000800 | |
NewFile = 0x00001000 | |
} | |
function Start-OSTraceSession { | |
<# | |
.SYNOPSIS | |
Captures kernel registry, process, and network events in an ETL file. | |
.DESCRIPTION | |
Start-OSTraceSession captures kernel registry, process, and network events in an ETL file. It taps into the Microsoft-Windows-Kernel-Registry, Microsoft-Windows-Kernel-Process, and Microsoft-Windows-Kernel-Network ETW providers in order to capture raw events. To stop the ETW trace session, use the Stop-OSTraceSession function. Stop-OSTraceSession also needs to be used to convert the .ETL file to a more usable format: csv, xml, evtx. | |
Author: Matthew Graeber (@mattifestation) | |
License: BSD 3-Clause | |
.PARAMETER FilePath | |
Specifies the path to the event trace file (.etl) to create. Note: Start-OSTraceSession will overwrite an existing .etl of the same name. | |
.PARAMETER TraceSessionName | |
Specifies the name of the ETW trace session. "OSTrace" is used by default. | |
.PARAMETER RegistryOptions | |
Specifies the registry event types to collect in your trace. If -RegistryOptions is not supplied, registry events will not be collected. | |
.PARAMETER ProcessOptions | |
Specifies the process event types to collect in your trace. If -ProcessOptions is not supplied, process events will not be collected. | |
.PARAMETER FileOptions | |
Specifies the file event types to collect in your trace. If -FileOptions is not supplied, file events will not be collected. | |
.PARAMETER NetworkOptions | |
Specifies the network event types to collect in your trace. If -NetworkOptions is not supplied, network events will not be collected. | |
.EXAMPLE | |
$SessionInfo = Start-OSTraceSession -FilePath ostrace.etl -RegistryOptions QueryKey, QueryValueKey -ProcessOptions Process, Freeze -NetworkOptions IPv4, IPv6 -FileOptions Create, Read, Write | |
Captures an event trace to ostrace.etl (in the current directory) using the specified registry, process, and network trace options. When the trace is complete, pipe $SessionInfo to Stop-OSTraceSession. | |
.OUTPUTS | |
Microsoft.Management.Infrastructure.CimInstance#ROOT/Microsoft/Windows/EventTracingManagement/MSFT_EtwTraceSession | |
Outputs a MSFT_EtwTraceSession WMI instance indicating the ETW trace session options. This output can be piped to Stop-OSTraceSession. | |
#> | |
[CmdletBinding()] | |
[OutputType('Microsoft.Management.Infrastructure.CimInstance#ROOT/Microsoft/Windows/EventTracingManagement/MSFT_EtwTraceSession')] | |
param ( | |
[Parameter(Mandatory, Position = 0)] | |
[String] | |
[ValidateScript({$_.EndsWith('.etl')})] | |
$FilePath, | |
[String] | |
[ValidateNotNullOrEmpty()] | |
$TraceSessionName = 'OSTrace', | |
[RegistryOptions] | |
$RegistryOptions, | |
[ProcessOptions] | |
$ProcessOptions, | |
[FileOptions] | |
$FileOptions, | |
[NetworkOptions] | |
$NetworkOptions | |
) | |
$KernelRegistryGUID = '{70EB4F03-C1DE-4F73-A051-33D13D5413BD}' | |
$KernelNetworkGUID = '{7DD42A49-5329-4832-8DFD-43D979153A88}' | |
$KernelProcessGUID = '{22FB2CD6-0E7B-422B-A0C7-2FAD1FD0E716}' | |
$KernelFileGUID = '{EDD08927-9CC4-4E65-B970-C2560FB5C289}' | |
$EVENT_TRACE_INDEPENDENT_SESSION_MODE = 0x08000000 | |
# To-do: determine why Add-EtwTraceProvider won't actually apply these enable properties | |
# First debugging step, try supplying these to an autologger and see if they persist in the registry. | |
#[UInt32] $EVENT_ENABLE_PROPERTY_STACK_TRACE = 0x00000004 | |
#[UInt32] $EVENT_ENABLE_PROPERTY_PROCESS_START_KEY = 0x00000080 | |
# Resolve the directory to which the .evtx will be written | |
$ParentPath = Split-Path -Path $FilePath -Parent | |
$FileName = Split-Path -Path $FilePath -Leaf | |
if (('' -eq $ParentPath) -or ('\' -eq $ParentPath)) { | |
# Only a file name was supplied. Use the current directory. | |
$FullDirectoryPath = $PWD.Path | |
} else { | |
$FullDirectoryPath = Resolve-Path -Path $ParentPath | Select-Object -ExpandProperty Path | |
} | |
if (-not (Test-Path -Path $FullDirectoryPath)) { | |
Write-Error "The specified directory ($FullDirectoryPath) does not exist. Create the directory and try again." | |
return | |
} | |
$FullFilePath = Join-Path -Path $FullDirectoryPath -ChildPath $FileName | |
Write-Verbose "OS trace will be written to $FullFilePath" | |
$TraceSessionArgs = @{ | |
Name = $TraceSessionName | |
LogFileMode = $EVENT_TRACE_INDEPENDENT_SESSION_MODE | |
LocalFilePath = $FullFilePath | |
ClockType = 'System' | |
ErrorAction = 'Stop' | |
} | |
Write-Verbose "Attempting to start event trace session. Trace session name: $TraceSessionName" | |
$TraceSessionInfo = New-EtwTraceSession @TraceSessionArgs | |
Write-Verbose "Trace session started. Trace session name: $TraceSessionName" | |
if ($RegistryOptions) { | |
Write-Verbose "Attaching the kernel registry provider (GUID: $KernelRegistryGUID) to the trace session." | |
$RegistryProviderInfo = Add-EtwTraceProvider -SessionName $TraceSessionName -Guid $KernelRegistryGUID -Level 0xFF -MatchAnyKeyword ([UInt64] $RegistryOptions) | |
# Add provider instances to the session instance just for reference | |
$TraceSessionInfo = Add-Member -InputObject $TraceSessionInfo -MemberType NoteProperty -Name RegistryProvider -Value $RegistryProviderInfo -PassThru | |
} | |
if ($ProcessOptions) { | |
Write-Verbose "Attaching the kernel process provider (GUID: $KernelProcessGUID) to the trace session." | |
$ProcessProviderInfo = Add-EtwTraceProvider -SessionName $TraceSessionName -Guid $KernelProcessGUID -Level 0xFF -MatchAnyKeyword ([UInt64] $ProcessOptions) | |
# Add provider instances to the session instance just for reference | |
$TraceSessionInfo = Add-Member -InputObject $TraceSessionInfo -MemberType NoteProperty -Name ProcessProvider -Value $ProcessProviderInfo -PassThru | |
} | |
if ($FileOptions) { | |
Write-Verbose "Attaching the kernel file provider (GUID: $KernelFileGUID) to the trace session." | |
$FileProviderInfo = Add-EtwTraceProvider -SessionName $TraceSessionName -Guid $KernelFileGUID -Level 0xFF -MatchAnyKeyword ([UInt64] $FileOptions) | |
# Add provider instances to the session instance just for reference | |
$TraceSessionInfo = Add-Member -InputObject $TraceSessionInfo -MemberType NoteProperty -Name FileProvider -Value $FileProviderInfo -PassThru | |
} | |
if ($NetworkOptions) { | |
Write-Verbose "Attaching the kernel network provider (GUID: $KernelNetworkGUID) to the trace session." | |
$NetworkProviderInfo = Add-EtwTraceProvider -SessionName $TraceSessionName -Guid $KernelNetworkGUID -Level 0xFF -MatchAnyKeyword ([UInt64] $NetworkOptions) | |
# Add provider instances to the session instance just for reference | |
$TraceSessionInfo = Add-Member -InputObject $TraceSessionInfo -MemberType NoteProperty -Name NetworkProvider -Value $NetworkProviderInfo -PassThru | |
} | |
$TraceSessionInfo | |
} | |
function Stop-OSTraceSession { | |
<# | |
.SYNOPSIS | |
Stops a running ETW trace that was launched with Start-OSTraceSession. | |
.DESCRIPTION | |
Stop-OSTraceSession stops a running ETW trace that was launched with Start-OSTraceSession and optionally converts the .ETL file to a more usable format (.evtx, .csv, .xml) using tracerpt.exe. | |
Author: Matthew Graeber (@mattifestation) | |
License: BSD 3-Clause | |
.PARAMETER TraceSession | |
Specifies the MSFT_EtwTraceSession instance that was returned by Start-OSTraceSession. If the instance was not saved, it can be retrieved with Get-EtwTraceSession. | |
.PARAMETER OutputFormat | |
Specifies the desired output format to which the .ETL trace will be converted. For example, converting the .ETL to an .EVTX will result in an event file with properly parsed event fields and messages. | |
.PARAMETER FilePath | |
Specifies the path to where the .evtx, .csv, or .xml file is to be written. | |
.EXAMPLE | |
$SessionInfo | Stop-OSTraceSession | |
Stops a running trace session that was started with Start-OSTraceSession. | |
.EXAMPLE | |
$SessionInfo | Stop-OSTraceSession -OutputFormat EVTX -FilePath ostrace.evtx | |
Stops a running trace session that was started with Start-OSTraceSession and converts the collected .ETL file to an .EVTX file. | |
.INPUTS | |
Microsoft.Management.Infrastructure.CimInstance#ROOT/Microsoft/Windows/EventTracingManagement/MSFT_EtwTraceSession | |
Stop-OSTraceSession can receive the output from Start-OSTraceSession over the pipeline. | |
.OUTPUTS | |
System.IO.FileInfo | |
If the user specifies the -OutputFormat and -FilePath arguments, a FileInfo object is returned indicating that the .ETL file was successfully converted into a more usable format. | |
.NOTES | |
An ETW trace session can also be stopped with the Remove-EtwTraceSession cmdlet. | |
#> | |
[CmdletBinding(DefaultParameterSetName = 'Default')] | |
[OutputType([System.IO.FileInfo], ParameterSetName='OutputFile')] | |
param ( | |
[Parameter(ParameterSetName = 'Default', ValueFromPipeline)] | |
[Parameter(ParameterSetName = 'OutputFile', ValueFromPipeline)] | |
[PSTypeName('Microsoft.Management.Infrastructure.CimInstance#ROOT/Microsoft/Windows/EventTracingManagement/MSFT_EtwTraceSession')] | |
$TraceSession, | |
[Parameter(ParameterSetName = 'OutputFile', Mandatory)] | |
[String] | |
[ValidateSet('CSV', 'EVTX', 'XML')] | |
$OutputFormat, | |
[Parameter(ParameterSetName = 'OutputFile', Mandatory)] | |
[String] | |
[ValidateScript({($_.EndsWith('.csv')) -or ($_.EndsWith('.evtx')) -or ($_.EndsWith('.xml'))})] | |
$FilePath | |
) | |
Write-Verbose "Stopping the following trace session: $($TraceSession.Name)" | |
Stop-EtwTraceSession -InputObject $TraceSession -ErrorAction Stop | |
Write-Verbose "The following trace session was stopped: $($TraceSession.Name)" | |
if ($PSCmdlet.ParameterSetName -eq 'OutputFile') { | |
# Validate that the .etl file exists | |
$null = Resolve-Path -Path $TraceSession.LocalFilePath -ErrorAction Stop | |
# Resolve the directory to which the file will be written | |
$ParentPath = Split-Path -Path $FilePath -Parent | |
$FileName = Split-Path -Path $FilePath -Leaf | |
if (('' -eq $ParentPath) -or ('\' -eq $ParentPath)) { | |
# Only a file name was supplied. Use the current directory. | |
$FullDirectoryPath = $PWD.Path | |
} else { | |
$FullDirectoryPath = Resolve-Path -Path $ParentPath | Select-Object -ExpandProperty Path | |
} | |
if (-not (Test-Path -Path $FullDirectoryPath)) { | |
Write-Error "The specified directory ($FullDirectoryPath) does not exist. Create the directory and try again." -ErrorAction Stop | |
} | |
$FullFilePath = Join-Path -Path $FullDirectoryPath -ChildPath $FileName | |
Write-Verbose "$($TraceSession.LocalFilePath) will be converted to the following file: $FullFilePath" | |
# Validate that tracerpt.exe is somewhere in $PATH | |
# tracerpt.exe is the utility that will convert the .etl file into a more usable format like .evtx. | |
$Tracerpt = Get-Command -Name tracerpt.exe -ErrorAction Stop | |
Write-Verbose "The following command will be executed: `"$($Tracerpt.Path)`" -l $($TraceSession.LocalFilePath) -of $OutputFormat -o $FullFilePath" | |
Start-Process -FilePath $Tracerpt.Path -WorkingDirectory $PWD -Wait -ArgumentList ('-l', $TraceSession.LocalFilePath, '-of', $OutputFormat, '-o', $FullFilePath) | |
Get-Item -Path $FullFilePath | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment