Skip to content

Commit

Permalink
Release 3.0 (#11)
Browse files Browse the repository at this point in the history
Complete rewrite with the following new features and fixes:

-  system-wide tracing
-  statistics contain process tree
-  fixed missing paths in the FileIO events
-  added registry handler for recording Windows Registry events (not enabled by default)
-  advanced filtering and an option to use only the selected set of event handlers
  • Loading branch information
lowleveldesign committed Jan 28, 2021
1 parent f6308d9 commit c05ef43
Show file tree
Hide file tree
Showing 71 changed files with 6,351 additions and 3,990 deletions.
16 changes: 4 additions & 12 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,22 @@ jobs:
- uses: actions/checkout@v2

- name: Setup nuget
uses: warrenbuckley/Setup-Nuget@v1
uses: nuget/setup-nuget@v1

- name: Restore packages
run: nuget restore wtrace.sln

- name: Setup MSBuild.exe
uses: microsoft/setup-msbuild@v1.0.0
uses: microsoft/setup-msbuild@v1.0.2

- name: Prepare
run: scripts\Update-AssemblyInfoVersionFiles.ps1
shell: powershell

- name: Build Debug using MSBuild
run: msbuild wtrace.sln -m /p:Configuration=Debug

- name: Build Release using MSBuild
run: msbuild wtrace.sln -m /p:Configuration=Release

- uses: actions/upload-artifact@v2-preview
with:
name: wtrace-debug
path: wtrace\bin\Debug\wtrace.exe

- uses: actions/upload-artifact@v2-preview
- uses: actions/upload-artifact@v2
with:
name: wtrace
path: wtrace\bin\Release\wtrace.exe
path: bin\wtrace\net472\wtrace.exe
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -245,3 +245,5 @@ ModelManifest.xml

# FAKE - F# Make
.fake/

launchSettings.json
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

MIT License

Copyright (c) 2016 Sebastian Solnica
Copyright (c) 2021 Sebastian Solnica

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
121 changes: 77 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,63 +3,96 @@

![.NET](https://github.com/lowleveldesign/wtrace/workflows/.NET/badge.svg)

This application will trace in real-time all File I/O, TCP IP, ALPC and RPC operations performed by a given process. It works on Windows 7+ and requires .NET 4.5.2+. Wtrace stops when the traced process exits, or if you issue Ctrl+C in its command line.
**The project homepage is at <https://wtrace.net>.**

Use pipeline to filter the events, e.g.: `wtrace notepad | findstr "FileIO/Write"`
Wtrace [spelled: *wɪtreɪs*] is a command-line tool for recording trace events from the Operating System or a group of processes. Wtrace may collect, among others, **File I/O** and **Registry** operations, **TPC/IP** connections, and **RPC** calls. Its purpose is to give you some insights into what is happening in the system.

It is possible to use wtrace as a **PowerShell cmdlet**. Please check the [wiki](https://github.com/lowleveldesign/wtrace/wiki/PowerShell-support) for more details.
Additionally, it has various **filtering capabilities** and may also dump statistics at the end of the trace session. As it's just a standard command-line tool, you may pipe its output to another tool for further processing.

The available options are:
It works on Windows 8.1+ and requires .NET 4.7.2+. Wtrace is just one executable, wtrace.exe, and you may download it from the [release page](https://github.com/lowleveldesign/wtrace/releases).

The available options are listed below. Please check the [wtrace documentation page](https://wtrace.net/documentation/wtrace) to learn details about them with some usage examples.

```
Usage: wtrace [OPTIONS] pid|imagename args
Usage: wtrace [OPTIONS] [pid|imagename args]
Options:
-f, --filter=VALUE Display only events which names contain the
given keyword (case insensitive). Does not
impact the summary.
-s, --system Collect system statistics (DPC/ISR) - shown in
the summary.
-c, --children Trace process and all its children.
--newconsole Start the process in a new console window.
--nosummary Prints only ETW events - no summary at the end.
-h, --help Show this message and exit.
-? Show this message and exit.
-f, --filter=FILTER Displays only events which satisfy a given FILTER.
(Does not impact the summary)
--handlers=HANDLERS Displays only events coming from the specified HANDLERS.
-c, --children Collects traces from the selected process and all its
children.
--newconsole Starts the process in a new console window.
-s, --system Collect only system statistics (Processes and DPC/ISR)
- shown in the summary.
--nosummary Prints only ETW events - no summary at the end.
-v, --verbose Shows wtrace diagnostics logs.
-h, --help Shows this message and exits.
```

A sample trace session might look as follows:

```
PS temp> wtrace mspaint
1134,4316 (1072) FileIO/Create 'C:\' (0xFFFFFA801D789CA0) rw-
1135,2725 (1072) FileIO/Create 'C:\Windows\Prefetch\MSPAINT.EXE-B4A5B5E8.pf' (0xFFFFFA8023E185A0) ---
1135,5118 (1072) FileIO/Create 'C:\Windows' (0xFFFFFA8023E185A0) rw-
1135,5514 (1072) FileIO/Create 'C:\Windows\SYSTEM32\wow64.dll' (0xFFFFFA801D789CA0) rw-
1135,8384 (1072) FileIO/Close 'C:\' (0xFFFFFA801D789CA0)
1135,8542 (1072) FileIO/Create 'C:\Windows\SYSTEM32\wow64.dll' (0xFFFFFA801D789CA0) rw-
1135,8956 (1072) FileIO/Create 'C:\Windows\SYSTEM32\' (0xFFFFFA802110BD50) rw-
1135,9198 (1072) FileIO/Close 'C:\Windows\SYSTEM32\' (0xFFFFFA802110BD50)
1136,0825 (1072) FileIO/Close 'C:\' (0xFFFFFA801D789CA0)
1136,1668 (1072) FileIO/Create 'C:\Windows\SYSTEM32\wow64win.dll' (0xFFFFFA801D789CA0) rw-
1136,1873 (1072) FileIO/Close 'C:\' (0xFFFFFA801D789CA0)
1136,2049 (1072) FileIO/Create 'C:\Windows\SYSTEM32\wow64win.dll' (0xFFFFFA801D789CA0) rw-
PS temp> .\wtrace.exe notepad
wtrace v3.0.0 - collects process or system traces
Copyright (C) 2021 Sebastian Solnica (lowleveldesign.org)
Visit https://wtrace.net to learn more
HANDLERS
process, file, rpc, tcp
Preparing the realtime trace session. Please wait...
Tracing session started. Press Ctrl + C to stop it.
19:47:42.9656 notepad (13712.24820) FileIO/Create 'C:\WINDOWS\Prefetch\NOTEPAD.EXE-C5670914.pf' disposition: OPEN_EXISTING, options: 0x20 -> SUCCESS
19:47:42.9704 notepad (13712.24820) FileIO/FSControl 'C:\WINDOWS\Prefetch\NOTEPAD.EXE-C5670914.pf' class info: 0x900EB -> SUCCESS
19:47:42.9713 notepad (13712.24820) FileIO/QueryInfo 'C:\WINDOWS\Prefetch\NOTEPAD.EXE-C5670914.pf' class info: 0x5 -> SUCCESS
19:47:42.9715 notepad (13712.24820) FileIO/Read 'C:\WINDOWS\Prefetch\NOTEPAD.EXE-C5670914.pf' offset: 0, size: 12288 -> SUCCESS
19:47:42.9713 notepad (13712.24820) FileIO/Read 'C:\WINDOWS\Prefetch\NOTEPAD.EXE-C5670914.pf' offset: 0, size: 9947 -> SUCCESS
19:47:42.9794 notepad (13712.24820) FileIO/Create 'D:\temp\' disposition: OPEN_EXISTING, options: 0x21 -> SUCCESS
19:47:42.9808 notepad (13712.24820) FileIO/QueryInfo '<0xFFFFCD064B771CE0>' class info: 0x9 -> SUCCESS
19:47:42.9809 notepad (13712.24820) FileIO/QueryInfo '<0xFFFFCD064B771CE0>' class info: 0x9 -> SUCCESS
19:47:42.9810 notepad (13712.24820) FileIO/QueryInfo '<0xFFFFCD064B9FB700>' class info: 0x9 -> SUCCESS
19:47:42.9823 notepad (13712.27256) Thread/Start
19:47:42.9824 notepad (13712.26824) Thread/Start
19:47:42.9828 notepad (13712.25724) Thread/Start
19:47:42.9838 notepad (13712.24820) FileIO/Create 'C:\WINDOWS\SYSTEM32\notepad.exe.Local\' disposition: OPEN_EXISTING, options: 0x200000 -> OBJECT_NAME_NOT_FOUND
19:47:42.9839 notepad (13712.24820) FileIO/Create 'C:\WINDOWS\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.19041.746_none_ca02b4b61b8320a4' disposition: OPEN_EXISTING, options: 0x21 -> SUCCESS
19:47:42.9840 notepad (13712.25724) FileIO/Create 'C:\WINDOWS\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.19041.746_none_ca02b4b61b8320a4\COMCTL32.dll' disposition: OPEN_EXISTING, options: 0x200000 -> SUCCESS
19:47:42.9840 notepad (13712.25724) FileIO/QueryInfo 'C:\WINDOWS\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.19041.746_none_ca02b4b61b8320a4\COMCTL32.dll' class info: 0x4 -> SUCCESS
19:47:42.9840 notepad (13712.25724) FileIO/Cleanup 'C:\WINDOWS\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.19041.746_none_ca02b4b61b8320a4\COMCTL32.dll' -> SUCCESS
19:47:42.9841 notepad (13712.25724) FileIO/Close 'C:\WINDOWS\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.19041.746_none_ca02b4b61b8320a4\COMCTL32.dll' -> SUCCESS
19:47:42.9841 notepad (13712.25724) FileIO/Create 'C:\WINDOWS\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.19041.746_none_ca02b4b61b8320a4\COMCTL32.dll' disposition: OPEN_EXISTING, options: 0x60 -> SUCCESS
19:47:42.9845 notepad (13712.25724) FileIO/Cleanup 'C:\WINDOWS\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.19041.746_none_ca02b4b61b8320a4\COMCTL32.dll' -> SUCCESS
19:47:42.9845 notepad (13712.25724) FileIO/Close 'C:\WINDOWS\WinSxS\amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.19041.746_none_ca02b4b61b8320a4\COMCTL32.dll' -> SUCCESS
19:47:42.9860 notepad (13712.24820) FileIO/Create 'C:\WINDOWS\system32\IMM32.DLL' disposition: OPEN_EXISTING, options: 0x200000 -> SUCCESS
19:47:42.9860 notepad (13712.24820) FileIO/QueryInfo 'C:\WINDOWS\system32\IMM32.DLL' class info: 0x4 -> SUCCESS
19:47:42.9860 notepad (13712.24820) FileIO/Cleanup 'C:\WINDOWS\system32\IMM32.DLL' -> SUCCESS```
...
1363,8894 (1072) FileIO/Read '' (0xFFFFFA80230F5970) 0x173400 32768b
1364,7208 (1072) FileIO/Read '' (0xFFFFFA80230F5970) 0x117400 32768b
1365,6873 (1072) FileIO/Read '' (0xFFFFFA80230F5970) 0x1CD400 32768b
1375,6284 (1072) FileIO/Create 'C:\Windows\win.ini' (0xFFFFFA801A43F2F0) rw-
1375,6702 (1072) FileIO/Read 'C:\Windows\win.ini' (0xFFFFFA801A43F2F0) 0x0 516b
1375,7369 (1072) FileIO/Create 'C:\Windows\SysWOW64\MAPI32.DLL' (0xFFFFFA8023E50710) rw-
1375,7585 (1072) FileIO/Close 'C:\Windows\SysWOW64\msxml6r.dll' (0xFFFFFA8023E50710)
1384,8796 (1072) FileIO/Read '' (0xFFFFFA801FDBFCD0) 0x58200 16384b
1385,3323 (1072) FileIO/Read '' (0xFFFFFA801FDBFCD0) 0x5C200 16384b
2318,6876 (1072) FileIO/Read '' (0xFFFFFA80230F5970) 0x209400 32768b
2319,3279 (1072) FileIO/Read '' (0xFFFFFA80230F5970) 0x213400 32768b
```

**Please visit the project [wiki](https://github.com/lowleveldesign/wtrace/wiki) to learn more**
Process (13712) exited.
Closing the trace session. Please wait...

--------------------------------
Processes
--------------------------------
├─ notepad [13712]

## Links
--------------------------------
File I/O
--------------------------------
'C:\Windows\System32\config\SOFTWARE' Total: 32768B, Writes: 0B, Reads: 32768B
'C:\WINDOWS\Prefetch\NOTEPAD.EXE-C5670914.pf' Total: 19894B, Writes: 0B, Reads: 19894B
'C:\Windows\Fonts\staticcache.dat' Total: 60B, Writes: 0B, Reads: 60B

- [Releasing wtrace 1.0 and procgov 2.0](https://lowleveldesign.wordpress.com/2016/10/21/releasing-wtrace-1-0-and-procgov-2-0/)
- [Wtrace 2.2](https://lowleveldesign.org/2017/10/25/wtrace-2-2/)
--------------------------------
RPC
--------------------------------
fb8a0729-2d04-4658-be93-27b4ad553fac (lsapolicylookup) [0] calls: 4
fb8a0729-2d04-4658-be93-27b4ad553fac (lsapolicylookup) [1] calls: 4
fb8a0729-2d04-4658-be93-27b4ad553fac (lsapolicylookup) [5] calls: 4
e60c73e6-88f9-11cf-9af1-0020af6e72f4 (epmapper) [0] calls: 2
fb8a0729-2d04-4658-be93-27b4ad553fac (lsapolicylookup) [2] calls: 2
e60c73e6-88f9-11cf-9af1-0020af6e72f4 (epmapper) [6] calls: 2
```
Binary file removed docs/rpcview-screenshot.png
Binary file not shown.
12 changes: 7 additions & 5 deletions scripts/Update-AssemblyInfoVersionFiles.ps1
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
function Update-AssemblyInfoVersionFiles ([string]$versionIdentifier)
{
$local:srcPath = $pwd
$today = [DateTime]::Today
$local:buildNumber = "{0:yy}{1}.{2}" -f $today,$today.DayOfYear,($env:GITHUB_RUN_NUMBER % [int16]::MaxValue)

Write-Host "Executing Update-AssemblyInfoVersionFiles in path $pwd for build $buildNumber"
Write-Host "Executing Update-AssemblyInfoVersionFiles in path $srcPath for build $buildNumber"

foreach ($file in $(Get-ChildItem $pwd AssemblyInfo.cs -recurse))
foreach ($file in $(Get-ChildItem $srcPath *.csproj -recurse))
{
$local:r = [regex]"$versionIdentifier\(""([0-9]+\.[0-9]+)(\.([0-9]+|\*))+""\)"
$local:r = [regex]"<$versionIdentifier>([0-9]+\.[0-9]+)(\.([0-9]+|\*))+"
$local:assemblyVersion = "0.0.0.0"
Write-Host "Processing '$($file.FullName)'"
#version replacements
(Get-Content -Encoding utf8 $file.FullName) | % {
$m = $r.Matches($_)
if ($m -and $m.Success) {
$assemblyVersion = "$($m.Groups[1].Value).$buildNumber"
$local:s = $r.Replace($_, "$versionIdentifier(""`$1.$buildNumber"")")
$local:s = $r.Replace($_, "<$versionIdentifier>`$1.$buildNumber")
Write-Host "Change version to $s"
$s
} else {
Expand All @@ -24,5 +26,5 @@ function Update-AssemblyInfoVersionFiles ([string]$versionIdentifier)
}
}

Update-AssemblyInfoVersionFiles "AssemblyFileVersion" -Verbose
Update-AssemblyInfoVersionFiles "FileVersion" -Verbose
Update-AssemblyInfoVersionFiles "AssemblyVersion" -Verbose
33 changes: 33 additions & 0 deletions wtrace.cmd/Commons/CommandLine.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module LowLevelDesign.WTrace.CommandLine

open System.Text.RegularExpressions

// from http://fssnip.net/8g/title/Yet-another-commandline-parser by Gennady Loskutov
// with my modifications

// parse command using regex
// if matched, return (command name, command value) as a tuple
let (|Command|_|) (s : string) =
let r = new Regex(@"^(?:-{1,2}|\/)(?<command>\?|\w+)[=:]*(?<value>.*)$", RegexOptions.IgnoreCase)
let m = r.Match(s)
if m.Success then Some (m.Groups.["command"].Value.ToLower(), m.Groups.["value"].Value)
else None

let parseArgs (flags : seq<string>) (args : seq<string>) =
args
|> Seq.scan (fun (sn : string, sv) arg ->
match arg with
| Command (n, v) when sn.Length <> 0 ->
// parse the command only if it's a command and we haven't
// passed the first free argument
if v.Length = 0 && flags |> Seq.contains(n) then
(n, "<flag>") // flag
elif n.Length = 0 then (sn, v)
else (n, v)
| v when sn.Length <> 0 && sv.Length <> 0 -> ("", v)
| v -> (sn, v)) ("<empty>", "<empty>")
|> Seq.skip 1
|> Seq.groupBy (fun (n, _) -> n)
|> Seq.map (fun (n, s) -> (n, s |> Seq.map (fun (_, v) -> v) |> Seq.filter (fun i -> i.Length > 0) |> Seq.toList))
|> Map.ofSeq

97 changes: 97 additions & 0 deletions wtrace.cmd/Commons/Globals.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
[<AutoOpen>]
module LowLevelDesign.WTrace.Globals

open System
open System.Diagnostics
open System.Reactive.Linq
open System.Runtime.CompilerServices

[<assembly: InternalsVisibleTo("wtrace.tests")>] do ()

(* Constants *)

// The timeout for buffered observable - maximum amount of time that
// the buffered observable will wait for events
let eventBufferedObservableTimeout = TimeSpan.FromSeconds(0.5)

[<Literal>]
let invalidEventId = Int32.MinValue

(* Type aliases *)

type Debug = System.Diagnostics.Debug
type RxDisposable = System.Reactive.Disposables.Disposable

(* Class extensions *)

type TraceSource with
member this.TraceError (ex : Exception) =
this.TraceEvent(TraceEventType.Error, 0, ex.ToString())

member this.TraceErrorMessage (msg) =
this.TraceEvent(TraceEventType.Error, 0, msg)

member this.TraceErrorWithMessage (msg, ex : Exception) =
this.TraceEvent(TraceEventType.Error, 0, sprintf "%s\nDETAILS: %s" msg (ex.ToString()))

member this.TraceWarning msg =
this.TraceEvent(TraceEventType.Warning, 0, msg)

member this.TraceWarningWithMessage (msg, ex : Exception) =
this.TraceEvent(TraceEventType.Error, 0, sprintf "%s\nDETAILS: %s" msg (ex.ToString()))

member this.TraceVerbose msg =
this.TraceEvent(TraceEventType.Verbose, 0, msg)


type Observable with
/// Creates an observable sequence from the specified Subscribe method implementation.
static member CreateEx (subscribe: IObserver<'T> -> unit -> unit) =
let subscribe o =
let m = subscribe o
Action(m)
Observable.Create(subscribe)

module ObservableEx =

let choose f source =
Observable.Create (fun (o : IObserver<_>) ->
FSharp.Control.Reactive.Observable.subscribeSafeWithCallbacks
(fun x -> ValueOption.iter o.OnNext (try f x with ex -> o.OnError ex; ValueNone))
o.OnError
o.OnCompleted
source)

(* Operators and comp expressions *)

let result = ResultBuilder()

let (|?) lhs rhs = (if lhs = null then rhs else lhs)

let (===) a b = String.Equals(a, b, StringComparison.Ordinal)

let (>=<) a b = String.Equals(a, b, StringComparison.OrdinalIgnoreCase)

(* Global loggers *)

module Logger =

let Main = TraceSource("WTrace")
let Tracing = TraceSource("WTrace.Tracing")
let EtwTracing = TraceSource("WTrace.ETW.Tracing")
let EtwEvents = TraceSource("WTrace.ETW.Events")


module private H =

let all = [| Main; Tracing; EtwTracing; EtwEvents |]

do
// remove the default logger - it's heavy
H.all |> Seq.iter (fun s -> s.Listeners.Remove("Default"))

let initialize (level : SourceLevels, listeners : list<TraceListener>) =
H.all |> Seq.iter (fun s ->
s.Switch.Level <- level
listeners |> Seq.iter (s.Listeners.Add >> ignore))

Loading

0 comments on commit c05ef43

Please sign in to comment.