Skip to content

Instantly share code, notes, and snippets.

@mattifestation
Last active May 9, 2023 20:36
Show Gist options
  • Save mattifestation/d1e7eeb63d2a97a124923ff482592d6d to your computer and use it in GitHub Desktop.
Save mattifestation/d1e7eeb63d2a97a124923ff482592d6d to your computer and use it in GitHub Desktop.
# 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