public static void Run()
        {
            int monitoringTimeSec = 10;

            if (Environment.OSVersion.Version.Major * 10 + Environment.OSVersion.Version.Minor < 62)
            {
                Out.WriteLine("This demo only works on Win8 / Win 2012 an above)");
                return;
            }

            // Today you have to be Admin to turn on ETW events (anyone can write ETW events).
            if (!(TraceEventSession.IsElevated() ?? false))
            {
                Out.WriteLine("To turn on ETW events you need to be Administrator, please run from an Admin process.");
                Debugger.Break();
                return;
            }

            string outputFileName = "ReloggerMonitorOutput.etl";

            if (File.Exists(outputFileName))
            {
                File.Delete(outputFileName);
            }

            Out.WriteLine("******************** Simple Relogger DEMO ********************");
            Out.WriteLine("This program shows how you can monitor an ETW stream in real time.");
            Out.WriteLine("And conditionally pass the events on to a ETL file");
            Out.WriteLine("Ctrl-C will end earlier");
            Out.WriteLine();
            Out.WriteLine("Please run some managed code while collection is happening...");
            Out.WriteLine();

            // To listen to ETW events you need a session, which allows you to control which events will be produced
            // Note that it is the session and not the source that buffers events, and by default sessions will buffer
            // 64MB of events before dropping events.  Thus even if you don't immediately connect up the source and
            // read the events you should not lose them.
            //
            // As mentioned below, sessions can outlive the process that created them.  Thus you may need a way of
            // naming the session so that you can 'reconnect' to it from another process.   This is what the name
            // is for.  It can be anything, but it should be descriptive and unique.   If you expect multiple versions
            // of your program to run simultaneously, you need to generate unique names (e.g. add a process ID suffix)
            // however this is dangerous because you can leave data collection on if the program ends unexpectedly.
            var sessionName = "SimpleMontitorSession";

            Out.WriteLine("Creating a '{0}' session", sessionName);
            using (var session = new TraceEventSession(sessionName))
            {
                // Enable the events we care about for the kernel in the kernel session
                // For this instant the session will buffer any incoming events.
                // This has to be first, and it will fail if you are not on Win8.
                session.EnableKernelProvider(
                    KernelTraceEventParser.Keywords.ImageLoad |
                    KernelTraceEventParser.Keywords.Process |
                    KernelTraceEventParser.Keywords.Thread);

                // A relogger is a TraceEventSource and acts much like an ETWTraceEventSource, with extra Write APIS.
                // Thus you get a callback on any event you want.
                // Only things that you call 'WriteEvent' on will end up in the output file.
                var relogger = new ETWReloggerTraceEventSource(sessionName, TraceEventSourceType.Session, outputFileName);

                // Here we set up the callbacks we want in the output file.   In this case all GC allocation Tick
                // events for 'String' as well as any ExceptionStart events.
                relogger.Clr.GCAllocationTick += delegate(GCAllocationTickTraceData data)
                {
                    if (data.TypeName == "System.String")
                    {
                        relogger.WriteEvent(data);
                    }
                };
                relogger.Clr.ExceptionStart += delegate(ExceptionTraceData data)
                {
                    relogger.WriteEvent(data);
                };

                // We also keep the image load events for DLL with 'clr' in their name.
                relogger.Kernel.ImageGroup += delegate(ImageLoadTraceData data)
                {
                    if (0 <= data.FileName.IndexOf("clr", StringComparison.OrdinalIgnoreCase))
                    {
                        relogger.WriteEvent(data);
                    }
                };

#if false       // Turn on to get debugging on unhandled events.
                relogger.UnhandledEvents += delegate(TraceEvent data)
                {
                    Console.WriteLine("Unknown Event " + data);
                };
#endif
                // Allow the test to be terminated with Ctrl-C cleanly.
                Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { session.Dispose(); };

                // Set up a timer to stop processing after monitoringTimeSec
                var timer = new Timer(delegate(object state)
                {
                    Out.WriteLine("Stopped after {0} sec", monitoringTimeSec);
                    session.Dispose();
                }, null, monitoringTimeSec * 1000, Timeout.Infinite);

                // Turn on the events to the provider.  In this case most CLR events

                Out.WriteLine("**** Turn on CLR Etw Providers.  Run managed code to see events.");
                session.EnableProvider(ClrTraceEventParser.ProviderGuid, TraceEventLevel.Verbose, (ulong)ClrTraceEventParser.Keywords.Default);

                // go into a loop processing events can calling the callbacks.  Because this is live data (not from a file)
                // processing never completes by itself, but only because someone called 'source.Dispose()'.
                Out.WriteLine("**** Start listening for events from the Microsoft-Demos-SimpleMonitor provider.");
                Out.WriteLine("The monitor will run for a maximum of {0} seconds.  Run managed code for more output.", monitoringTimeSec);
                relogger.Process();
                Out.WriteLine();
                Out.WriteLine("Stopping the collection of events.");
                timer.Dispose();    // Turn off the timer.
            }

            Out.WriteLine("Monitoring complete, only certain CLR events put in the output file.");
            Out.WriteLine("The output ETL file: {0}", Path.GetFullPath(outputFileName));
            Out.WriteLine();

            if (!File.Exists(outputFileName))
            {
                Out.WriteLine("Error: No output file was generated (did you run anything during the collection?");
                return;
            }

            // Show what was actually produced in the filtered file.
            DataProcessing(outputFileName);
        }
Esempio n. 2
0
        /// <summary>
        /// This is a demo of using TraceEvent to activate a 'real time' provider that is listening to
        /// the MyEventSource above.   Normally this event source would be in a different process,  but
        /// it also works if this process generate the events and I do that here for simplicity.
        /// </summary>
        public static int Run()
        {
            // Today you have to be Admin to turn on ETW events (anyone can write ETW events).
            if (!(TraceEventSession.IsElevated() ?? false))
            {
                Console.WriteLine("To turn on ETW events you need to be Administrator, please run from an Admin process.");
                Debugger.Break();
                return(-1);
            }

            // To listen to ETW events you need a session, which allows you to control which events will be produced
            // Note that it is the session and not the source that buffers events, and by default sessions will buffer
            // 64MB of events before dropping events.  Thus even if you don't immediately connect up the source and
            // read the events you should not lose them.
            //
            // As mentioned below, sessions can outlive the process that created them.  Thus you may need a way of
            // naming the session so that you can 'reconnect' to it from another process.   This is what the name
            // is for.  It can be anything, but it should be descriptive and unique.   If you expect multiple versions
            // of your program to run simultaneously, you need to generate unique names (e.g. add a process ID suffix)
            // however this is dangerous because you can leave data collection on if the program ends unexpectedly.
            var sessionName = "SimpleMontitorSession";

            using (var session = new TraceEventSession(sessionName))
            {
                /* BY DEFAULT ETW SESSIONS SURVIVE THE DEATH OF THE PROESS THAT CREATES THEM! */
                // Unlike most other resources on the system, ETW session live beyond the lifetime of the
                // process that created them.   This is very useful in some scenarios, but also creates the
                // very real possibility of leaving 'orphan' sessions running.
                //
                // To help avoid this by default TraceEventSession sets 'StopOnDispose' so that it will stop
                // the ETW session if the TraceEventSession dies.   Thus executions that 'clean up' the TraceEventSession
                // will clean up the ETW session.   This covers many cases (including throwing exceptions)
                //
                // However if the process is killed manually (including control C) this cleanup will not happen.
                // Thus best practices include
                //
                //     * Add a Control C handler that calls session.Dispose() so it gets cleaned up in this common case
                //     * use the same session name (say your program name) run-to-run so you don't create many orphans.
                //
                // By default TraceEventSessions are in 'create' mode where it assumes you want to create a new session.
                // In this mode if a session already exists, it is stopped and the new one is created.
                //
                // Here we install the Control C handler.   It is OK if Dispose is called more than once.
                Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { session.Dispose(); };

                /*****************************************************************************************************/
                // Hook up events.   To so this first we need a 'Parser. which knows how to part the events of a particular Event Provider.
                // In this case we get a DynamicTraceEventSource, which knows how to parse any EventSource provider.    This parser
                // is so common, that TraceEventSource as a shortcut property called 'Dynamic' that fetches this parsers.

                // For debugging, and demo purposes, hook up a callback for every event that 'Dynamic' knows about (this is not EVERY
                // event only those know about by RegisteredTraceEventParser).   However the 'UnhandledEvents' handler below will catch
                // the other ones.
                Dictionary <int, DownloadSession> data = new Dictionary <int, DownloadSession>();
                session.Source.Dynamic.All += delegate(TraceEvent e)
                {
                    // ETW buffers events and only delivers them after buffering up for some amount of time.  Thus
                    // there is a small delay of about 2-4 seconds between the timestamp on the event (which is very
                    // accurate), and the time we actually get the event.  We measure that delay here.
                    int sizeIndex = e.PayloadIndex("size");
                    if (sizeIndex >= 0)
                    {
                        try
                        {
                            int pidIndex = e.PayloadIndex("PID");
                            int pid      = (int)e.PayloadValue(pidIndex);
                            int bytes    = (int)e.PayloadValue(sizeIndex);
                            lock (data)
                            {
                                if (data.TryGetValue(pid, out DownloadSession info))
                                {
                                    info.AddTotal(bytes);
                                }
                                else
                                {
                                    data[pid] = new DownloadSession(pid, (int)e.PayloadValue(sizeIndex));
                                }
                            }
                        }
                        catch { }
                    }
                };

                bool running = true;
                Task.Run(async() =>
                {
                    while (running)
                    {
                        try
                        {
                            await Task.Delay(1000);
                            lock (data)
                            {
                                Console.Clear();
                                Console.SetCursorPosition(0, 0);
                                Console.WriteLine("{0,-6} {1,11} {2,11} {3,-30}", "PID", "Total Bytes", "Bytes/sec", "Name");

                                foreach (var datum in data.OrderByDescending(x => x.Value.Difference).Take(5))
                                {
                                    Console.WriteLine("{0,-6} {1,11} {2,11} {3,-30}", datum.Value.PID, DownloadSession.FormatBytes(datum.Value.Total), DownloadSession.FormatBytes(datum.Value.Difference, 1, "/s"), datum.Value.ProcessName);
                                    datum.Value.Update();
                                }
                            }
                        }
                        catch { }
                    }
                });

                // At this point we have created a TraceEventSession, hooked it up to a TraceEventSource, and hooked the
                // TraceEventSource to a TraceEventParser (you can do several of these), and then hooked up callbacks
                // up to the TraceEventParser (again you can have several).  However we have NOT actually told any
                // provider (EventSources) to actually send any events to our TraceEventSession.
                // We do that now.

                // Enable my provider, you can call many of these on the same session to get events from other providers.
                // Because this EventSource did not define any keywords, I can only turn on all events or none.
                var restarted = session.EnableProvider("Microsoft-Windows-Kernel-Network");
                if (restarted)      // Generally you don't bother with this warning, but for the demo we do.
                {
                    Console.WriteLine("The session {0} was already active, it has been restarted.", sessionName);
                }

                Console.Clear();
                Console.SetCursorPosition(0, 0);
                Console.WriteLine("{0,-6} {1,11} {2,11} {3,-30}", "PID", "Total Bytes", "Bytes/sec", "Name");

                // go into a loop processing events can calling the callbacks.  Because this is live data (not from a file)
                // processing never completes by itself, but only because someone called 'source.Dispose()'.
                session.Source.Process();

                running = false;
                Console.WriteLine();
                Console.WriteLine("Stopping the collection of events.");
                Console.ReadLine();
            }
            return(0);
        }
Esempio n. 3
0
        /// <summary>
        /// CollectData doe will turn on logging of data from 'eventSourceName' to the file 'dataFileName'.
        /// It will then call EventGenerator.CreateEvents and wait 12 seconds for it to generate some data.
        /// </summary>
        static void CollectData(string eventSourceName, string dataFileName)
        {
            // Today you have to be Admin to turn on ETW events (anyone can write ETW events).
            if (!(TraceEventSession.IsElevated() ?? false))
            {
                Out.WriteLine("To turn on ETW events you need to be Administrator, please run from an Admin process.");
                Debugger.Break();
                return;
            }

            // As mentioned below, sessions can outlive the process that created them.  Thus you need a way of
            // naming the session so that you can 'reconnect' to it from another process.   This is what the name
            // is for.  It can be anything, but it should be descriptive and unique.   If you expect multiple versions
            // of your program to run simultaneously, you need to generate unique names (e.g. add a process ID suffix)
            // however this is dangerous because you can leave data collection on if the program ends unexpectedly.
            //
            // In this case we tell the session to place the data in MonitorToFileData.etl.
            var sessionName = "SimpleTraceLogSession";

            Out.WriteLine("Creating a '{0}' session writing to {1}", sessionName, dataFileName);
            Out.WriteLine("Use 'logman query -ets' to see active sessions.");
            Out.WriteLine("Use 'logman stop {0} -ets' to manually stop orphans.", sessionName);
            using (var session = new TraceEventSession(sessionName, dataFileName))      // Since we give it a file name, the data goes there.
                using (var kernelSession = new TraceEventSession(KernelTraceEventParser.KernelSessionName, Path.ChangeExtension(dataFileName, ".kernel.etl")))
                {
                    /* BY DEFAULT ETW SESSIONS SURVIVE THE DEATH OF THE PROESS THAT CREATES THEM! */
                    // Unlike most other resources on the system, ETW session live beyond the lifetime of the
                    // process that created them.   This is very useful in some scenarios, but also creates the
                    // very real possibility of leaving 'orphan' sessions running.
                    //
                    // To help avoid this by default TraceEventSession sets 'StopOnDispose' so that it will stop
                    // the ETW session if the TraceEventSession dies.   Thus executions that 'clean up' the TraceEventSession
                    // will clean up the ETW session.   This covers many cases (including throwing exceptions)
                    //
                    // However if the process is killed manually (including control C) this cleanup will not happen.
                    // Thus best practices include
                    //
                    //     * Add a Control C handler that calls session.Dispose() so it gets cleaned up in this common case
                    //     * use the same session name run-to-run so you don't create many orphans.
                    //
                    // By default TraceEventSessions are in 'create' mode where it assumes you want to create a new session.
                    // In this mode if a session already exists, it is stopped and the new one is created.
                    //
                    // Here we install the Control C handler.   It is OK if Dispose is called more than once.
                    Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { session.Dispose(); kernelSession.Dispose(); };

                    // Enable kernel events.
                    kernelSession.EnableKernelProvider(KernelTraceEventParser.Keywords.ImageLoad | KernelTraceEventParser.Keywords.Process | KernelTraceEventParser.Keywords.Thread);

                    // Enable my provider, you can call many of these on the same session to get events from other providers

                    // Turn on the eventSource given its name.
                    // Note we turn on Verbose level all keywords (ulong.MaxValue == 0xFFF....) and turn on stacks for
                    // this provider (for all events, until Windows 8.1 you can only turn on stacks for every event
                    // for a particular provider or no stacks)
                    var options = new TraceEventProviderOptions()
                    {
                        StacksEnabled = true
                    };
                    var restarted = session.EnableProvider(eventSourceName, TraceEventLevel.Verbose, ulong.MaxValue, options);
                    if (restarted)  // Generally you don't bother with this warning, but for the demo we do.
                    {
                        Out.WriteLine("The session {0} was already active, it has been restarted.", sessionName);
                    }

                    // We also turn on CLR events because we need them to decode Stacks and we also get exception events (and their stacks)
                    session.EnableProvider(ClrTraceEventParser.ProviderGuid, TraceEventLevel.Verbose, (ulong)ClrTraceEventParser.Keywords.Default);

                    // Start another thread that Causes MyEventSource to create some events
                    // Normally this code as well as the EventSource itself would be in a different process.
                    EventGenerator.CreateEvents();

                    // Also generate some exceptions so we have interesting stacks to look at
                    Thread.Sleep(100);
                    EventGenerator.GenerateExceptions();

                    Out.WriteLine("Waiting 12 seconds for events to come in.");
                    Thread.Sleep(12000);

                    // Because the process in question (this process) lives both before and after the time the events were
                    // collected, we don't have complete information about JIT compiled methods in that method.   There are
                    // some methods that were JIT compiled before the session started (e.g. SimpleTraceLog.Main) for which
                    // we do not have information.   We collect this by forcing a CLR 'rundown' which will dump method information
                    // for JIT compiled methods that were not present.  If you know that the process of interest ends before
                    // data collection ended or that data collection started before the process started, then this is not needed.
                    Out.WriteLine("Forcing rundown of JIT methods.");
                    var rundownFileName = Path.ChangeExtension(dataFileName, ".clrRundown.etl");
                    using (var rundownSession = new TraceEventSession(sessionName + "Rundown", rundownFileName))
                    {
                        rundownSession.EnableProvider(ClrRundownTraceEventParser.ProviderGuid, TraceEventLevel.Verbose, (ulong)ClrRundownTraceEventParser.Keywords.Default);
                        // Poll until 2 second goes by without growth.
                        for (var prevLength = new FileInfo(rundownFileName).Length; ;)
                        {
                            Thread.Sleep(2000);
                            var newLength = new FileInfo(rundownFileName).Length;
                            if (newLength == prevLength)
                            {
                                break;
                            }
                            prevLength = newLength;
                        }
                    }
                    Out.WriteLine("Done with rundown.");
                }

            Out.WriteLine("Zipping the raw files into a single '{0}' file.", dataFileName);

            // At this point you have multiple ETL files that don't have all the information
            // inside them necessary for analysis off the currentn machine.    To do analsysis
            // of the machine you need to merge the ETL files (which can be done with
            //        TraceEventSession.MergeInPlace(dataFileName, Out);
            // However this does not get the symbolic information (NGEN PDBS) needed to
            // decode the stacks in the .NET managed framewrok on another machine.
            // To do the merging AND generate these NGEN images it is best to us ethe
            // ZipppedETLWriter that does all this (and compresses all the files in a ZIP archive).

            ZippedETLWriter writer = new ZippedETLWriter(dataFileName, Out);

            writer.WriteArchive();

            Out.WriteLine("Zip complete, output file = {0}", writer.ZipArchivePath);
        }
Esempio n. 4
0
        static void DoMain(string[] args)
        {
            if (TraceEventSession.IsElevated() != true)
            {
                Console.Error.WriteLine("Must be elevated (Admin) to run this program.");
                return;
            }

            List <string>      procargs = null;
            bool               showhelp = false, spawnNewConsoleWindow = false;
            TraceOutputOptions options = TraceOutputOptions.TracesAndSummary;

            int pid = 0;

            var p = new OptionSet
            {
                { "newconsole", "Start the process in a new console window.", v => { spawnNewConsoleWindow = v != null; } },
                { "summary", "Prints only a summary of the collected trace.", v => {
                      if (v != null)
                      {
                          options = TraceOutputOptions.OnlySummary;
                      }
                  } },
                { "nosummary", "Prints only ETW events - no summary at the end.", v => {
                      if (v != null)
                      {
                          options = TraceOutputOptions.NoSummary;
                      }
                  } },
                { "h|help", "Show this message and exit", v => showhelp = v != null },
                { "?", "Show this message and exit", v => showhelp = v != null }
            };

            try {
                procargs = p.Parse(args);
            } catch (OptionException ex) {
                Console.Error.Write("ERROR: invalid argument");
                Console.Error.WriteLine(ex.Message);
                Console.Error.WriteLine();
                showhelp = true;
            } catch (FormatException) {
                Console.Error.WriteLine("ERROR: invalid number in one of the constraints");
                Console.Error.WriteLine();
                showhelp = true;
            }

            Debug.Assert(procargs != null);
            if (!showhelp && procargs.Count == 0)
            {
                Console.Error.WriteLine("ERROR: please provide either process name or PID of the already running process");
                Console.Error.WriteLine();
                showhelp = true;
            }

            if (showhelp)
            {
                ShowHelp(p);
                return;
            }

            try {
                if (!int.TryParse(procargs[0], out pid))
                {
                    TraceNewProcess(procargs, spawnNewConsoleWindow, options);
                }
                else
                {
                    TraceRunningProcess(pid, options);
                }
            }
            catch (COMException ex) {
                if ((uint)ex.HResult == 0x800700B7)
                {
                    Console.Error.WriteLine("ERROR: could not start the kernel logger - make sure it is not running.");
                }
            }
            catch (Win32Exception ex) {
                Console.Error.WriteLine(
                    $"ERROR: an error occurred while trying to start or open the process, hr: 0x{ex.HResult:X8}, " +
                    $"code: 0x{ex.NativeErrorCode:X8} ({ex.Message}).");
            }
            catch (Exception ex) {
                Console.Error.WriteLine($"ERROR: severe error happened when starting application: {ex.Message}");
            }
        }
        /// <summary>
        /// This is a demo of using TraceEvent to activate a 'real time' provider that is listening to
        /// the MyEventSource above.   Normally this event source would be in a different process,  but
        /// it also works if this process generate the events and I do that here for simplicity.
        /// </summary>
        public static int Run()
        {
            Out.WriteLine("******************** SimpleEventSourceMonitor DEMO ********************");
            Out.WriteLine("This program generates processes and displays EventSource events");
            Out.WriteLine("using the ETW REAL TIME pipeline. (thus no files are created)");
            Out.WriteLine();

            // Today you have to be Admin to turn on ETW events (anyone can write ETW events).
            if (!(TraceEventSession.IsElevated() ?? false))
            {
                Out.WriteLine("To turn on ETW events you need to be Administrator, please run from an Admin process.");
                Debugger.Break();
                return(-1);
            }

            // To listen to ETW events you need a session, which allows you to control which events will be produced
            // Note that it is the session and not the source that buffers events, and by default sessions will buffer
            // 64MB of events before dropping events.  Thus even if you don't immediately connect up the source and
            // read the events you should not lose them.
            //
            // As mentioned below, sessions can outlive the process that created them.  Thus you may need a way of
            // naming the session so that you can 'reconnect' to it from another process.   This is what the name
            // is for.  It can be anything, but it should be descriptive and unique.   If you expect multiple versions
            // of your program to run simultaneously, you need to generate unique names (e.g. add a process ID suffix)
            // however this is dangerous because you can leave data collection on if the program ends unexpectedly.
            var sessionName = "SimpleMonitorSession";

            Out.WriteLine("Creating a '{0}' session", sessionName);
            Out.WriteLine("Use 'logman query -ets' to see active sessions.");
            Out.WriteLine("Use 'logman stop {0} -ets' to manually stop orphans.", sessionName);
            using (var session = new TraceEventSession(sessionName))
            {
                /* BY DEFAULT ETW SESSIONS SURVIVE THE DEATH OF THE PROCESS THAT CREATES THEM! */
                // Unlike most other resources on the system, ETW session live beyond the lifetime of the
                // process that created them.   This is very useful in some scenarios, but also creates the
                // very real possibility of leaving 'orphan' sessions running.
                //
                // To help avoid this by default TraceEventSession sets 'StopOnDispose' so that it will stop
                // the ETW session if the TraceEventSession dies.   Thus executions that 'clean up' the TraceEventSession
                // will clean up the ETW session.   This covers many cases (including throwing exceptions)
                //
                // However if the process is killed manually (including control C) this cleanup will not happen.
                // Thus best practices include
                //
                //     * Add a Control C handler that calls session.Dispose() so it gets cleaned up in this common case
                //     * use the same session name (say your program name) run-to-run so you don't create many orphans.
                //
                // By default TraceEventSessions are in 'create' mode where it assumes you want to create a new session.
                // In this mode if a session already exists, it is stopped and the new one is created.
                //
                // Here we install the Control C handler.   It is OK if Dispose is called more than once.
                Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { session.Dispose(); };

                // To demonstrate non-trivial event manipulation, we calculate the time delta between 'MyFirstEvent and 'MySecondEvent'
                // firstEventTimeMSec remembers all the 'MyFirstEvent' arrival times (indexed by their ID)
                var firstEventTimeMSec = new Dictionary <int, double>();

                /*****************************************************************************************************/
                // Hook up events.   To so this first we need a 'Parser. which knows how to part the events of a particular Event Provider.
                // In this case we get a DynamicTraceEventSource, which knows how to parse any EventSource provider.    This parser
                // is so common, that TraceEventSource as a shortcut property called 'Dynamic' that fetches this parsers.

                // For debugging, and demo purposes, hook up a callback for every event that 'Dynamic' knows about (this is not EVERY
                // event only those know about by DynamicTraceEventParser).   However the 'UnhandledEvents' handler below will catch
                // the other ones.
                session.Source.Dynamic.All += delegate(TraceEvent data)
                {
                    // ETW buffers events and only delivers them after buffering up for some amount of time.  Thus
                    // there is a small delay of about 2-4 seconds between the timestamp on the event (which is very
                    // accurate), and the time we actually get the event.  We measure that delay here.
                    var delay = (DateTime.Now - data.TimeStamp).TotalSeconds;
                    Out.WriteLine("GOT Event Delay={0:f1}sec: {1} ", delay, data.ToString());
                };

                // Add logic on what to do when we get "MyFirstEvent"
                session.Source.Dynamic.AddCallbackForProviderEvent("Microsoft-Demos-SimpleMonitor", "MyFirstEvent", delegate(TraceEvent data)
                {
                    // On First Events, simply remember the ID and time of the event
                    firstEventTimeMSec[(int)data.PayloadByName("MyId")] = data.TimeStampRelativeMSec;
                });

                // Add logic on what to do when we get "MySecondEvent"
                session.Source.Dynamic.AddCallbackForProviderEvent("Microsoft-Demos-SimpleMonitor", "MySecondEvent", delegate(TraceEvent data)
                {
                    // On Second Events, if the ID matches, compute the delta and display it.
                    var myID = (int)data.PayloadByName("MyId");
                    double firstEventTime;
                    if (firstEventTimeMSec.TryGetValue(myID, out firstEventTime))
                    {
                        firstEventTimeMSec.Remove(myID);            // We are done with the ID after matching it, so remove it from the table.
                        Out.WriteLine("   >>> Time Delta from first Event = {0:f3} MSec", data.TimeStampRelativeMSec - firstEventTime);
                    }
                    else
                    {
                        Out.WriteLine("   >>> WARNING, Found a 'SecondEvent' without a corresponding 'FirstEvent'");
                    }
                });

                // Add logic on what to do when we get "Stop"
                session.Source.Dynamic.AddCallbackForProviderEvent("Microsoft-Demos-SimpleMonitor", "Stop", delegate(TraceEvent data)
                {
                    Out.WriteLine("    >>> Got a stop message");
                    // Stop processing after we we see the 'Stop' event, this will 'Process() to return.   It is OK to call Dispose twice
                    session.Source.Dispose();
                });

#if DEBUG
                // The callback above will only be called for events the parser recognizes (in the case of DynamicTraceEventParser, EventSources)
                // It is sometimes useful to see the other events that are not otherwise being handled.  The source knows about these and you
                // can ask the source to send them to you like this.
                session.Source.UnhandledEvents += delegate(TraceEvent data)
                {
                    if ((int)data.ID != 0xFFFE)         // The EventSource manifest events show up as unhanded, filter them out.
                    {
                        Out.WriteLine("GOT UNHANDLED EVENT: " + data.Dump());
                    }
                };
#endif
                // At this point we have created a TraceEventSession, hooked it up to a TraceEventSource, and hooked the
                // TraceEventSource to a TraceEventParser (you can do several of these), and then hooked up callbacks
                // up to the TraceEventParser (again you can have several).  However we have NOT actually told any
                // provider (EventSources) to actually send any events to our TraceEventSession.
                // We do that now.

                // Enable my provider, you can call many of these on the same session to get events from other providers.
                // Because this EventSource did not define any keywords, I can only turn on all events or none.
                var restarted = session.EnableProvider("Microsoft-Demos-SimpleMonitor");
                if (restarted)      // Generally you don't bother with this warning, but for the demo we do.
                {
                    Out.WriteLine("The session {0} was already active, it has been restarted.", sessionName);
                }

                // Start another thread that Causes MyEventSource to create some events
                // Normally this code as well as the EventSource itself would be in a different process.
                EventGenerator.CreateEvents();

                Out.WriteLine("**** Start listening for events from the Microsoft-Demos-SimpleMonitor provider.");
                // go into a loop processing events can calling the callbacks.  Because this is live data (not from a file)
                // processing never completes by itself, but only because someone called 'source.Dispose()'.
                session.Source.Process();
                Out.WriteLine();
                Out.WriteLine("Stopping the collection of events.");
            }
            return(0);
        }
Esempio n. 6
0
        public static void Run()
        {
            var monitoringTimeSec = 10;

            Out.WriteLine("******************** ModuleLoadMonitor DEMO ********************");
            Out.WriteLine("Monitoring DLL Loads and Process Starts/Stops system wide");
            Out.WriteLine("The monitor will run for a maximum of {0} seconds", monitoringTimeSec);
            Out.WriteLine("Press Ctrl-C to stop monitoring early.");
            Out.WriteLine();
            Out.WriteLine("Start a program to see some events!");
            Out.WriteLine();
            if (TraceEventSession.IsElevated() != true)
            {
                Out.WriteLine("Must be elevated (Admin) to run this program.");
                Debugger.Break();
                return;
            }

            // Start the session as a real time monitoring session,
            // Before windows 8, there is a restriction that if you wanted kernel events you must name your session
            // 'NT Kernel Logger' (the value of KernelSessionName) and there can only be one such session and no
            // other ETW providers can be enabled for that session (thus you need two sessions if you want both
            // kernel and non-kernel events (fixed in Win 8).  We want this to work on Win 7 so we live with those
            // restrictions.
            using (TraceEventSession session = new TraceEventSession(KernelTraceEventParser.KernelSessionName))
            {
                /* BY DEFAULT ETW SESSIONS SURVIVE THE DEATH OF THE PROESS THAT CREATES THEM! */
                // Unlike most other resources on the system, ETW session live beyond the lifetime of the
                // process that created them.   This is very useful in some scenarios, but also creates the
                // very real possibility of leaving 'orphan' sessions running.
                //
                // To help avoid this by default TraceEventSession sets 'StopOnDispose' so that it will stop
                // the ETW session if the TraceEventSession dies.   Thus executions that 'clean up' the TraceEventSession
                // will clean up the ETW session.   This covers many cases (including throwing exceptions)
                //
                // However if the process is killed manually (including control C) this cleanup will not happen.
                // Thus best practices include
                //
                //     * Add a Control C handler that calls session.Dispose() so it gets cleaned up in this common case
                //     * use the same session name run-to-run so you don't create many orphans.
                //
                // By default TraceEventSessions are in 'create' mode where it assumes you want to create a new session.
                // In this mode if a session already exists, it is stopped and the new one is created.
                //
                // Here we install the Control C handler.
                Console.CancelKeyPress += new ConsoleCancelEventHandler((object sender, ConsoleCancelEventArgs cancelArgs) =>
                {
                    Out.WriteLine("Control C pressed");     // Note that if you hit Ctrl-C twice rapidly you may be called concurrently.
                    session.Dispose();                      // Note that this causes Process() to return.
                    cancelArgs.Cancel = true;               // This says don't abort, since Process() will return we can terminate nicely.
                });

                // Enable the Kernel events that we want.   At this point data is being collected (but being buffered since we are not reading it)
                // See KernelTraceEventParser.Keywords for what else can be turned on and KernelTraceEventParser for a description
                // of the events that you get when you turn on the various kernel keywords.   Many kernel events will also log a stack
                // when they fire see EnableKernelProvider for more on that.
                session.EnableKernelProvider(KernelTraceEventParser.Keywords.ImageLoad | KernelTraceEventParser.Keywords.Process);

                // .Source will auto-create a TraceEventSource reading the data from the session
                // .Kernel will auto-create a KernelTraceEventParser getting its events from the source
                // .ImageLoad is an event that you can subscribe to that will be called back when Image load events happen (complete with parsed event)
                session.Source.Kernel.ImageLoad += delegate(ImageLoadTraceData data)
                {
                    Out.WriteLine("Process {0,16} At 0x{1,8:x} Loaded {2}", data.ProcessName, data.ImageBase, data.FileName);
                };
                //  Subscribe to more events (process start)
                session.Source.Kernel.ProcessStart += delegate(ProcessTraceData data)
                {
                    Out.WriteLine("Process Started {0,6} Parent {1,6} Name {2,8} Cmd: {3}",
                                  data.ProcessID, data.ParentID, data.ProcessName, data.CommandLine);
                };
                //  Subscribe to more events (process end)
                session.Source.Kernel.ProcessStop += delegate(ProcessTraceData data)
                {
                    Out.WriteLine("Process Ending {0,6} ", data.ProcessID);
                };

                // Set up a timer to stop processing after monitoringTimeSec
                var timer = new Timer(delegate(object state)
                {
                    Out.WriteLine("Stopped after {0} sec", monitoringTimeSec);
                    session.Source.StopProcessing();
                }, null, monitoringTimeSec * 1000, Timeout.Infinite);

                // Start listening for events, will end if session.Source.StopProcessing() is called or session.Dispose() is called.
                // Here we never do either of these and thus will only stop when Ctrl-C is hit (but it will clean up because of
                // our control C handler).
                session.Source.Process();
                timer.Dispose();    // Done with the timer.
            }
            Out.WriteLine("Stopping monitor");
        }
Esempio n. 7
0
        /// <summary>
        /// Sample function demonstrating how to match pairs of events in a live ETW stream,
        /// and compute a duration based on the start and end events. It uses CLR's JIT events
        ///  MethodJittingStarted, ModuleLoadUnload, and ModuleLoadUnloadVerbose.
        ///  for this but the principle applies to most events that mark a duration.
        /// </summary>
        public static void Run()
        {
            Out.WriteLine("******************** ObserveJitEvents DEMO ********************");
            Out.WriteLine("This program Demos using the reactive framework (IObservable) to monitor");
            Out.WriteLine(".NET Runtime JIT compiler events.");
            Out.WriteLine();
            Out.WriteLine("This program shows how you can use the reactive framework to find pairs");
            Out.WriteLine("of related events (in this the JIT start and stop events) and use them");
            Out.WriteLine("to calculate values (in this case the time spent JIT compiling. ");
            Out.WriteLine();
            Out.WriteLine("The program also shows how to create on the fly aggregate statistics using");
            Out.WriteLine("the reactive framework.   ");
            Out.WriteLine();
            Out.WriteLine("The program will print a line every time a .NET method is JIT compiled");
            Out.WriteLine("in any process on the machine and will print stats every 8 methods.");
            Out.WriteLine();
            Out.WriteLine("Start a .NET Program while the monitoring is active to see the JIT events.");
            Out.WriteLine();

            if (TraceEventSession.IsElevated() != true)
            {
                Out.WriteLine("Must be elevated (Admin) to run this method.");
                Debugger.Break();
                return;
            }
            var monitoringTimeSec = 10;

            Out.WriteLine("The monitor will run for a maximum of {0} seconds", monitoringTimeSec);
            Out.WriteLine("Press Ctrl-C to stop monitoring early.");

            // create a real time user mode session
            using (var userSession = new TraceEventSession("ObserveJitEvents1"))
            {
                // Set up Ctrl-C to stop both user mode and kernel mode sessions
                SetupCtrlCHandler(() => { if (userSession != null)
                                          {
                                              userSession.Stop();
                                          }
                                  });

                // enable the CLR JIT compiler events.
                userSession.EnableProvider(ClrTraceEventParser.ProviderGuid, TraceEventLevel.Verbose, (ulong)(ClrTraceEventParser.Keywords.Default));

                // Get the stream of starts.
                IObservable <MethodJittingStartedTraceData> jitStartStream = userSession.Source.Clr.Observe <MethodJittingStartedTraceData>("Method/JittingStarted");

                // And the stream of ends.
                IObservable <MethodLoadUnloadVerboseTraceData> jitEndStream = userSession.Source.Clr.Observe <MethodLoadUnloadVerboseTraceData>("Method/LoadVerbose");

                // Compute the stream of matched-up pairs, and for each create a tuple of the start event and the time between the pair of events.
                // Note that the 'Take(1)' is pretty important because a nested 'from' statement logically creates the 'cross product' of a two streams
                // In this case the stream of starts and the stream of ends).   Because we filter this stream only to matching entities and then only
                // take the first entry, we stop waiting.   Thus we only 'remember' those 'starts' that are not yet matched, which is very important
                // for efficiency.   Note that any 'lost' end events will never be matched and will accumulate over time, slowing things down.
                // We should put a time window on it as well to 'forget' old start events.
                var jitTimes =
                    from start in jitStartStream
                    from end in jitEndStream.Where(e => start.MethodID == e.MethodID && start.ProcessID == e.ProcessID).Take(1)
                    select new
                {
                    Name      = GetName(start),
                    ProcessID = start.ProcessID,
                    JitTIme   = end.TimeStampRelativeMSec - start.TimeStampRelativeMSec
                };

                // Create a stream of just the JIT times and compute statistics every 8 methods that are JIT compiled.
                IObservable <Statistics> jitStats = ComputeRunningStats(jitTimes, jitData => jitData.JitTIme, windowSize: 8);

                // Print every time you compile a method
                jitTimes.Subscribe(onNext: jitData => Out.WriteLine("JIT_TIME: {0,7:f2} PROC: {1,10} METHOD: {2}", jitData.JitTIme, GetProcessName(jitData.ProcessID), jitData.Name));

                // Also output the statistics.
                jitStats.Subscribe(onNext: Out.WriteLine);      // print some aggregation stats

                // for debugging purposes to see any events that entered by were not handled by any parser.   These can be bugs.
                // IObservable<TraceEvent> unhandledEventStream = userSession.Source.ObserveUnhandled();
                // unhandledEventStream.Subscribe(onNext: ev => Out.WriteLine("UNHANDLED :  PID: {0,5} {1}/{2} ", ev.ProcessID, ev.ProviderName, ev.EventName));

                // Set up a timer to stop processing after monitoringTimeSec
                IObservable <long> timer = Observable.Timer(new TimeSpan(0, 0, monitoringTimeSec));
                timer.Subscribe(delegate
                {
                    Out.WriteLine("Stopped after {0} sec", monitoringTimeSec);
                    userSession.Stop();
                });

                // OK we are all set up, time to listen for events and pass them to the observers.
                userSession.Source.Process();
            }
        }
Esempio n. 8
0
        public static void Run()
        {
            var monitoringTimeSec = 10;

            Out.WriteLine("******************** KernelAndClrMonitor DEMO (Win7) ********************");
            Out.WriteLine("Printing both Kernel and CLR (user mode) events simultaneously");
            Out.WriteLine("The monitor will run for a maximum of {0} seconds", monitoringTimeSec);
            Out.WriteLine("Press Ctrl-C to stop monitoring early.");
            Out.WriteLine();
            Out.WriteLine("Start a .NET program to see some events!");
            Out.WriteLine();
            if (TraceEventSession.IsElevated() != true)
            {
                Out.WriteLine("Must be elevated (Admin) to run this program.");
                Debugger.Break();
                return;
            }

            // Set up Ctrl-C to stop both user mode and kernel mode sessions
            Console.CancelKeyPress += (object sender, ConsoleCancelEventArgs cancelArgs) =>
            {
                StopSessions();
                cancelArgs.Cancel = true;
            };

            // Note that because there are different sessions, the events may not be printed
            // in time order since the different sessions may flush their buffers at different
            // times.   If you care, you must buffer the events and order them by event
            // timestamp.   Note that the timestamps however ARE accurate.
            Out.WriteLine("Setup up threads to process the events");

            // start processing kernel events on a thread pool thread
            var task1 = Task.Run(() =>
            {
                // Note that TraceEventSession and EtwTraceEventParser are IN GENERAL NOT THREADSAFE,
                // Normally this is not a hardship you just set up the session TraceDispacher on one
                // thread.  It is OK to call a session's Dispose() and 'Enable and Disable provider APIS
                // from another thread, but things associated with ETWTraceEventSource and TraceEventParsers
                // should all be on the same thread.
                Out.WriteLine("Kernel event Thread Starting");
                Out.WriteLine("Enabling Image load, thread and process kernel events.");
                using (s_kernelSession = new TraceEventSession(KernelTraceEventParser.KernelSessionName))
                {
                    // Enable the events we care about for the kernel in the kernel session
                    // For this instant the session will buffer any incoming events.
                    // If you only have to run on Win8 systems you can use one session for both.
                    // Here we turn in process, thread and Image load events.
                    s_kernelSession.EnableKernelProvider(
                        KernelTraceEventParser.Keywords.ImageLoad |
                        KernelTraceEventParser.Keywords.Process |
                        KernelTraceEventParser.Keywords.Thread);

                    // You should do all processing from a single source on a single thread.
                    // Thus call calls to .Source, or Process() should be on the same thread.
                    s_kernelSession.Source.Kernel.All += Print;
#if DEBUG
                    // in debug builds it is useful to see any unhandled events because they could be bugs.
                    s_kernelSession.Source.UnhandledEvents += Print;
#endif
                    // process events until Ctrl-C is pressed

                    Out.WriteLine("Waiting on kernel events.");
                    s_kernelSession.Source.Process();
                }
                Out.WriteLine("Thread 1 dieing");
            });

            // start processing CLR events on a thread pool thread
            var task2 = Task.Run(() =>
            {
                // Note that TraceEventSession and EtwTraceEventParser are IN GENERAL NOT THREADSAFE,
                // Normally this is not a hardship you just set up the session TraceDispacher on one
                // thread.  It is OK to call a session's Dispose() and 'Enable and Disable provider APIS
                // from another thread, but things associated with ETWTraceEventSource and TraceEventParsers
                // should all be on the same thread.
                using (s_userSession = new TraceEventSession("MonitorKernelAndClrEventsSession"))
                {
                    Out.WriteLine("Enabling CLR GC and Exception events.");
                    // Enable the events we care about for the CLR (in the user session).
                    // unlike the kernel session, you can call EnableProvider on other things too.
                    // For this instant the ;session will buffer any incoming events.
                    s_userSession.EnableProvider(
                        ClrTraceEventParser.ProviderGuid,
                        TraceEventLevel.Informational,
                        (ulong)(ClrTraceEventParser.Keywords.GC | ClrTraceEventParser.Keywords.Exception));

                    // s_userSession.Source.Clr.GCHeapStats += (GCHeapStatsTraceData data) => Out.WriteLine(" ", data.GenerationSize0);

                    Out.WriteLine("User event Thread  Starting");
                    s_userSession.Source.Clr.All += Print;
#if DEBUG
                    // in debug builds it is useful to see any unhandled events because they could be bugs.
                    s_userSession.Source.UnhandledEvents += Print;
#endif
                    // process events until Ctrl-C is pressed or timeout expires
                    Out.WriteLine("Waiting on user events.");
                    s_userSession.Source.Process();
                }
                Out.WriteLine("Thread 2 dieing");
            });

            // Set up a timer to stop processing after monitoringTimeSec
            var timer = new Timer(delegate(object state)
            {
                Out.WriteLine("Stopped Monitoring after {0} sec", monitoringTimeSec);
                StopSessions();
            }, null, monitoringTimeSec * 1000, Timeout.Infinite);

            // Wait until tasks are complete
            Out.WriteLine("Waiting for processing tasks to complete");
            Task.WaitAll(task1, task2);
            Out.WriteLine("Monitoring stopped");
            timer.Dispose();
        }
        public static bool RealTimeTraceEventSession
        (
            string providerName
            , string sessionName
            , string tracingFileName = null
            , string[] traceEvents   = null
            , Action
            <
                long
                , TraceEventDispatcher
                , TraceEventSession
                , TraceEvent
            > onOneEventTracedOnceProcessAction = null
            , TraceEventProviderOptions traceEventProviderOptions = null
            , TraceEventSessionOptions traceEventSessionOptions   = TraceEventSessionOptions.Create
            , TraceEventSourceType traceEventSourceType           = TraceEventSourceType.MergeAll
            , TraceEventLevel traceEventLevel = TraceEventLevel.Always
            , ulong matchKeywords             = ulong.MaxValue
            , bool needCountHits = false
        )
        {
            var r = false;

            if (!(TraceEventSession.IsElevated() ?? false))
            {
                Out.WriteLine("To turn on ETW events you need to be Administrator, please run from an Admin process.");
                return(r);
            }
            var needTracingFile = !string.IsNullOrEmpty(tracingFileName);

            if
            (
                traceEvents != null
                &&
                traceEvents.Length > 0
                &&
                onOneEventTracedOnceProcessAction != null
            )
            {
                using
                (
                    var session =
                        (
                            needTracingFile
                                    ?
                            new TraceEventSession
                            (
                                sessionName
                                , tracingFileName
                                , traceEventSessionOptions
                            )
                {
                    StopOnDispose = true
                }
                                    :
                            new TraceEventSession
                            (
                                sessionName
                                , traceEventSessionOptions
                            )
                {
                    StopOnDispose = true
                }
                        )
                )
                {
                    using
                    (
                        var source =
                            (
                                needTracingFile
                                            ?
                                new ETWTraceEventSource(tracingFileName)
                                            :
                                session.Source
                            )
                    )
                    {
                        long sequence = 0;
                        RegisterCallbacks
                        (
                            providerName
                            , traceEvents
                            , source
                            , session
                            , (x, y, z) =>
                        {
                            long id = 0;
                            if (needCountHits)
                            {
                                id = Interlocked.Increment(ref sequence);
                            }
                            onOneEventTracedOnceProcessAction
                            (
                                id
                                , x
                                , y
                                , z
                            );
                        }
                        );
                        var restarted = session
                                        .EnableProvider
                                        (
                            providerName
                            , traceEventLevel
                            , matchKeywords
                            , traceEventProviderOptions
                                        );
                        source
                        .Process();
                        r = true;
                    }
                }
            }
            return(r);
        }
Esempio n. 10
0
        public static void StartTrace(CollectorParameters Collector)
        {
            void RetargetEventSource(String LegacySource)
            {
                // This is a fix for: https://github.com/fireeye/SilkETW/issues/4
                // When both SilkETW and SilkService are used on the same host
                // eventlog logging would fail for one or the other as they had
                // the same source. This function will retarget the source.
                if (EventLog.SourceExists(LegacySource))
                {
                    EventLog.DeleteEventSource(LegacySource);
                }
            }

            Boolean WriteEventLogEntry(String Message, EventLogEntryType Type, EventIds EventId, String Path)
            {
                //--[Event ID's]
                // 0 == Collector start
                // 1 == Collector terminated -> by user
                // 2 == Collector terminated -> by error
                // 3 == Event recorded
                //--

                try
                {
                    // Fix legacy collector source
                    RetargetEventSource("ETW Collector");

                    // Event log properties
                    String Source = "SilkService Collector";

                    // If the source doesn't exist we have to create it first
                    if (!EventLog.SourceExists(Source))
                    {
                        EventLog.CreateEventSource(Source, Path);
                    }

                    // Write event
                    using (EventLog Log = new EventLog(Path))
                    {
                        Log.Source           = Source;
                        Log.MaximumKilobytes = 99968;                                   // Max ~100mb size -> needs 64kb increments
                        Log.ModifyOverflowPolicy(OverflowAction.OverwriteAsNeeded, 10); // Always overwrite oldest
                        Log.WriteEntry(Message, Type, (int)EventId);
                    }
                    return(true);
                }
                catch
                {
                    return(false);
                }
            }

            int ProcessJSONEventData(String JSONData, OutputType OutputType, String Path, String YaraScan, YaraOptions YaraOptions, YSInstance YaraInstance, YSRules YaraRules)
            {
                // Yara matches
                List <String> YaraRuleMatches = new List <String>();

                // Yara options
                if (YaraScan != String.Empty)
                {
                    byte[]           JSONByteArray = Encoding.ASCII.GetBytes(JSONData);
                    List <YSMatches> Matches       = YaraInstance.ScanMemory(JSONByteArray, YaraRules, null, 0);
                    YaraRuleMatches.Clear();
                    if (Matches.Count != 0)
                    {
                        foreach (YSMatches Match in Matches)
                        {
                            YaraRuleMatches.Add(Match.Rule.Identifier);
                        }

                        // Dynamically update the JSON object -> List<String> YaraRuleMatches
                        JObject obj = JObject.Parse(JSONData);
                        ((JArray)obj["YaraMatch"]).Add(YaraRuleMatches);
                        JSONData = obj.ToString(Newtonsoft.Json.Formatting.None);
                    }
                }

                if (YaraOptions == YaraOptions.All || YaraOptions == YaraOptions.None || (YaraScan != String.Empty && YaraRuleMatches.Count > 0))
                {
                    //--[Return Codes]
                    // 0 == OK
                    // 1 == File write failed
                    // 2 == URL POST request failed
                    // 3 == Eventlog write failed
                    //--

                    // Process JSON
                    if (OutputType == OutputType.file)
                    {
                        try
                        {
                            if (!File.Exists(Path))
                            {
                                File.WriteAllText(Path, (JSONData + Environment.NewLine));
                            }
                            else
                            {
                                File.AppendAllText(Path, (JSONData + Environment.NewLine));
                            }

                            return(0);
                        }
                        catch
                        {
                            return(1);
                        }
                    }
                    else if (OutputType == OutputType.url)
                    {
                        try
                        {
                            string         responseFromServer = string.Empty;
                            HttpWebRequest webRequest         = (HttpWebRequest)WebRequest.Create(Path);
                            webRequest.Timeout     = 10000; // 10 second timeout
                            webRequest.Method      = "POST";
                            webRequest.ContentType = "application/json";
                            webRequest.Accept      = "application/json";
                            using (var streamWriter = new StreamWriter(webRequest.GetRequestStream()))
                            {
                                streamWriter.Write(JSONData);
                                streamWriter.Flush();
                                streamWriter.Close();
                            }
                            var httpResponse = (HttpWebResponse)webRequest.GetResponse();
                            using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
                            {
                                var result = streamReader.ReadToEnd();
                            }

                            return(0);
                        }
                        catch
                        {
                            return(2);
                        }
                    }
                    else
                    {
                        Boolean WriteEvent = WriteEventLogEntry(JSONData, EventLogEntryType.Information, EventIds.Event, Path);

                        if (WriteEvent)
                        {
                            return(0);
                        }
                        else
                        {
                            return(3);
                        }
                    }
                }
                else
                {
                    return(0);
                }
            }

            // Local variables for StartTrace
            String  EventParseSessionName;
            Boolean ProcessEventData;

            // Is elevated? While running as a service this should always be true but
            // this is kept for edge-case user-fail.
            if (TraceEventSession.IsElevated() != true)
            {
                SilkUtility.WriteCollectorGuidMessageToServiceTextLog(Collector.CollectorGUID, "The collector must be run elevated", true);
                return;
            }

            // Print status
            SilkUtility.WriteCollectorGuidMessageToServiceTextLog(Collector.CollectorGUID, "Starting trace collector", false);

            // We tag event sessions with a unique name
            // While running these are observable with => logman -ets
            if (Collector.CollectorType == CollectorType.Kernel)
            {
                EventParseSessionName = KernelTraceEventParser.KernelSessionName;
            }
            else
            {
                String RandId = Guid.NewGuid().ToString();
                EventParseSessionName = ("SilkServiceUserCollector_" + RandId);
            }

            // Create trace session
            using (var TraceSession = new TraceEventSession(EventParseSessionName))
            {
                // The collector cannot survive process termination (safeguard)
                TraceSession.StopOnDispose = true;

                // Create event source
                using (var EventSource = new ETWTraceEventSource(EventParseSessionName, TraceEventSourceType.Session))
                {
                    // A DynamicTraceEventParser can understand how to read the embedded manifests that occur in the dataStream
                    var EventParser = new DynamicTraceEventParser(EventSource);

                    // Loop events as they arrive
                    EventParser.All += delegate(TraceEvent data)
                    {
                        // It's a bit ugly but ... ¯\_(ツ)_/¯
                        if (Collector.FilterOption != FilterOption.None)
                        {
                            if (Collector.FilterOption == FilterOption.Opcode && (byte)data.Opcode != (byte)Collector.FilterValue)
                            {
                                ProcessEventData = false;
                            }
                            else if (Collector.FilterOption == FilterOption.ProcessID && data.ProcessID != (UInt32)Collector.FilterValue)
                            {
                                ProcessEventData = false;
                            }
                            else if (Collector.FilterOption == FilterOption.ProcessName && data.ProcessName != (String)Collector.FilterValue)
                            {
                                ProcessEventData = false;
                            }
                            else if (Collector.FilterOption == FilterOption.EventName && data.EventName != (String)Collector.FilterValue)
                            {
                                ProcessEventData = false;
                            }
                            else
                            {
                                ProcessEventData = true;
                            }
                        }
                        else
                        {
                            ProcessEventData = true;
                        }

                        // Only process/serialize events if they match our filter
                        if (ProcessEventData)
                        {
                            var eRecord = new EventRecordStruct
                            {
                                ProviderGuid    = data.ProviderGuid,
                                YaraMatch       = new List <String>(),
                                ProviderName    = data.ProviderName,
                                EventName       = data.EventName,
                                Opcode          = data.Opcode,
                                OpcodeName      = data.OpcodeName,
                                TimeStamp       = data.TimeStamp,
                                ThreadID        = data.ThreadID,
                                ProcessID       = data.ProcessID,
                                ProcessName     = data.ProcessName,
                                PointerSize     = data.PointerSize,
                                EventDataLength = data.EventDataLength
                            };

                            // Populate Proc name if undefined
                            if (String.IsNullOrEmpty(eRecord.ProcessName))
                            {
                                try
                                {
                                    eRecord.ProcessName = Process.GetProcessById(eRecord.ProcessID).ProcessName;
                                }
                                catch
                                {
                                    eRecord.ProcessName = "N/A";
                                }
                            }
                            var EventProperties = new Hashtable();

                            // Try to parse event XML
                            try
                            {
                                StringReader  XmlStringContent   = new StringReader(data.ToString());
                                XmlTextReader EventElementReader = new XmlTextReader(XmlStringContent);
                                while (EventElementReader.Read())
                                {
                                    for (int AttribIndex = 0; AttribIndex < EventElementReader.AttributeCount; AttribIndex++)
                                    {
                                        EventElementReader.MoveToAttribute(AttribIndex);

                                        // Cap maxlen for eventdata elements to 10k
                                        if (EventElementReader.Value.Length > 10000)
                                        {
                                            String DataValue = EventElementReader.Value.Substring(0, Math.Min(EventElementReader.Value.Length, 10000));
                                            EventProperties.Add(EventElementReader.Name, DataValue);
                                        }
                                        else
                                        {
                                            EventProperties.Add(EventElementReader.Name, EventElementReader.Value);
                                        }
                                    }
                                }
                            }
                            catch
                            {
                                // For debugging (?), never seen this fail
                                EventProperties.Add("XmlEventParsing", "false");
                            }
                            eRecord.XmlEventData = EventProperties;

                            // Serialize to JSON
                            String JSONEventData = Newtonsoft.Json.JsonConvert.SerializeObject(eRecord);
                            int    ProcessResult = ProcessJSONEventData(JSONEventData, Collector.OutputType, Collector.Path, Collector.YaraScan, Collector.YaraOptions, Collector.YaraInstance, Collector.YaraRules);

                            // Verify that we processed the result successfully
                            if (ProcessResult != 0)
                            {
                                if (ProcessResult == 1)
                                {
                                    SilkUtility.WriteCollectorGuidMessageToServiceTextLog(Collector.CollectorGUID, "The collector failed to write to file", true);
                                }
                                else if (ProcessResult == 2)
                                {
                                    SilkUtility.WriteCollectorGuidMessageToServiceTextLog(Collector.CollectorGUID, "The collector failed to POST the result", true);
                                }
                                else
                                {
                                    SilkUtility.WriteCollectorGuidMessageToServiceTextLog(Collector.CollectorGUID, "The collector failed write to the eventlog", true);
                                }

                                // Write status to eventlog if dictated by the output type
                                if (Collector.OutputType == OutputType.eventlog)
                                {
                                    WriteEventLogEntry($"{{\"Collector\":\"Stop\",\"Error\":true,\"ErrorCode\":{ProcessResult}}}", EventLogEntryType.Error, EventIds.StopError, Collector.Path);
                                }

                                // This collector encountered an error, terminate the service
                                TerminateCollector();
                            }
                        }
                    };

                    // Specify the providers details
                    if (Collector.CollectorType == CollectorType.Kernel)
                    {
                        TraceSession.EnableKernelProvider((KernelTraceEventParser.Keywords)Collector.KernelKeywords);
                    }
                    else
                    {
                        // Note that the collector doesn't know if you specified a wrong provider name,
                        // the only tell is that you won't get any events ;)
                        TraceSession.EnableProvider(Collector.ProviderName, (TraceEventLevel)Collector.UserTraceEventLevel, (ulong)Collector.UserKeywords);
                    }

                    // Write status to eventlog if dictated by the output type
                    if (Collector.OutputType == OutputType.eventlog)
                    {
                        String ConvertKeywords;
                        if (Collector.CollectorType == CollectorType.Kernel)
                        {
                            ConvertKeywords = Enum.GetName(typeof(KernelTraceEventParser.Keywords), Collector.KernelKeywords);
                        }
                        else
                        {
                            ConvertKeywords = "0x" + String.Format("{0:X}", (ulong)Collector.UserKeywords);
                        }
                        String Message = $"{{\"Collector\":\"Start\",\"Data\":{{\"Type\":\"{Collector.CollectorType}\",\"Provider\":\"{Collector.ProviderName}\",\"Keywords\":\"{ConvertKeywords}\",\"FilterOption\":\"{Collector.FilterOption}\",\"FilterValue\":\"{Collector.FilterValue}\",\"YaraPath\":\"{Collector.YaraScan}\",\"YaraOption\":\"{Collector.YaraOptions}\"}}}}";
                        WriteEventLogEntry(Message, EventLogEntryType.SuccessAudit, EventIds.Start, Collector.Path);
                    }

                    // Populate the trace bookkeeper
                    var CollectorInstance = new CollectorInstance
                    {
                        CollectorGUID         = Collector.CollectorGUID,
                        EventSource           = EventSource,
                        EventParseSessionName = EventParseSessionName,
                    };
                    SilkUtility.CollectorTaskList.Add(CollectorInstance);

                    // Signal the ManualResetEvent
                    SilkUtility.SignalThreadStarted.Set();

                    // Continuously process all new events in the data source
                    EventSource.Process();

                    void TerminateCollector()
                    {
                        EventSource.StopProcessing();
                        TraceSession?.Stop();
                        SilkUtility.WriteCollectorGuidMessageToServiceTextLog(Collector.CollectorGUID, "Collector terminated", false);
                        return;
                    }
                }
            }
        }
        public static bool TraceETWTraceEventSource
        (
            string providerName
            , string tracedFileName
            , string[] traceEvents = null
            , Action
            <
                long
                , TraceEventDispatcher
                , TraceEventSession
                , TraceEvent
            > onOneEventTracedOnceProcessAction = null
            , TraceEventProviderOptions traceEventProviderOptions = null
            , TraceEventSourceType traceEventSourceType           = TraceEventSourceType.MergeAll
            , TraceEventLevel traceEventLevel = TraceEventLevel.Always
            , ulong matchKeywords             = ulong.MaxValue
            , bool needCountHits = false
        )
        {
            var r = false;

            if (!(TraceEventSession.IsElevated() ?? false))
            {
                Out.WriteLine("To turn on ETW events you need to be Administrator, please run from an Admin process.");
                return(r);
            }
            if
            (
                traceEvents != null
                &&
                traceEvents.Length > 0
                &&
                onOneEventTracedOnceProcessAction != null
            )
            {
                using (var source = new ETWTraceEventSource(tracedFileName, traceEventSourceType))
                {
                    //闭包
                    long sequence = 0;
                    RegisterCallbacks
                    (
                        providerName
                        , traceEvents
                        , source
                        , null
                        , (x, y, z) =>
                    {
                        long id = 0;
                        if (needCountHits)
                        {
                            id = Interlocked.Increment(ref sequence);
                        }
                        onOneEventTracedOnceProcessAction
                        (
                            id
                            , x
                            , y
                            , z
                        );
                    }
                    );
                    source.Process();   // call the callbacks for each event
                }
            }
            return(true);
        }
Esempio n. 12
0
        public static void Run()
        {
            Out.WriteLine("******************** ObserveGCEvents DEMO ********************");
            Out.WriteLine("This program Demos using the reactive framework (IObservable) to monitor");
            Out.WriteLine(".NET Garbage collector (GC) events.");
            Out.WriteLine();
            Out.WriteLine("The program will print a line every time 100K of memory was allocated");
            Out.WriteLine("on the GC heap along with the type of the object that 'tripped' the 100K");
            Out.WriteLine("sample.   It will also print a line every time a GC happened and show ");
            Out.WriteLine("the sizes of each generation after the GC.");
            Out.WriteLine();
            Out.WriteLine("Run a .NET Program while the monitoring is active to see GC events.");
            Out.WriteLine();

            if (TraceEventSession.IsElevated() != true)
            {
                Out.WriteLine("Must be elevated (Admin) to run this method.");
                Debugger.Break();
                return;
            }
            var monitoringTimeSec = 10;

            Out.WriteLine("The monitor will run for a maximum of {0} seconds", monitoringTimeSec);
            Out.WriteLine("Press Ctrl-C to stop monitoring of GC Allocs");

            // create a real time user mode session
            using (var userSession = new TraceEventSession("ObserveGCAllocs"))
            {
                // Set up Ctrl-C to stop the session
                SetupCtrlCHandler(() => { userSession.Stop(); });

                // enable the CLR provider with default keywords (minus the rundown CLR events)
                userSession.EnableProvider(ClrTraceEventParser.ProviderGuid, TraceEventLevel.Verbose,
                                           (ulong)(ClrTraceEventParser.Keywords.GC));

                // Create a stream of GC Allocation events (happens every time 100K of allocations happen)
                IObservable <GCAllocationTickTraceData> gcAllocStream = userSession.Source.Clr.Observe <GCAllocationTickTraceData>();

                // Print the outgoing stream to the console
                gcAllocStream.Subscribe(allocData =>
                                        Out.WriteLine("GC Alloc  :  Proc: {0,10} Amount: {1,6:f1}K  TypeSample: {2}", GetProcessName(allocData.ProcessID), allocData.AllocationAmount / 1000.0, allocData.TypeName));

                // Create a stream of GC Collection events
                IObservable <GCHeapStatsTraceData> gcCollectStream = userSession.Source.Clr.Observe <GCHeapStatsTraceData>();

                // Print the outgoing stream to the console
                gcCollectStream.Subscribe(collectData =>
                                          Out.WriteLine("GC Collect:  Proc: {0,10} Gen0: {1,6:f1}M Gen1: {2,6:f1}M Gen2: {3,6:f1}M LargeObj: {4,6:f1}M",
                                                        GetProcessName(collectData.ProcessID),
                                                        collectData.GenerationSize0 / 1000000.0,
                                                        collectData.GenerationSize1 / 1000000.0,
                                                        collectData.GenerationSize2 / 1000000.0,
                                                        collectData.GenerationSize3 / 1000000.0));

                IObservable <long> timer = Observable.Timer(new TimeSpan(0, 0, monitoringTimeSec));
                timer.Subscribe(delegate
                {
                    Out.WriteLine("Stopped after {0} sec", monitoringTimeSec);
                    userSession.Dispose();
                });

                // OK we are all set up, time to listen for events and pass them to the observers.
                userSession.Source.Process();
            }
            Out.WriteLine("Done with program.");
        }
Esempio n. 13
0
        static void DoMain(string[] args)
        {
            if (TraceEventSession.IsElevated() != true)
            {
                Console.Error.WriteLine("Must be elevated (Admin) to run this program.");
                return;
            }

            List <string> procargs = null;
            bool          showhelp = false, spawnNewConsoleWindow = false,
                          collectSystemStats = false, printSummary = true, traceChildProcesses = false;
            string eventNameFilter = null, outputFilename = null;

            int pid = 0;

            var p   = new OptionSet
            {
                { "f|filter=", "Display only events which names contain the given keyword " +
                  "(case insensitive). Does not impact the summary.", v => { eventNameFilter = v; } },
                { "s|system", "Collect system statistics (DPC/ISR) - shown in the summary.", v => { collectSystemStats = v != null; } },
                { "c|children", "Trace process and all its children.", v => { traceChildProcesses = v != null; } },
                { "newconsole", "Start the process in a new console window.", v => { spawnNewConsoleWindow = v != null; } },
                { "nosummary", "Prints only ETW events - no summary at the end.", v => { printSummary = v == null; } },
                { "h|help", "Show this message and exit.", v => showhelp = v != null },
                { "w|writefile=", "Write the output to a logfile", v => { outputFilename = v; } },
                { "?", "Show this message and exit.", v => showhelp = v != null }
            };

            try {
                procargs = p.Parse(args);
            } catch (OptionException ex) {
                Console.Error.Write("ERROR: invalid argument");
                Console.Error.WriteLine(ex.Message);
                Console.Error.WriteLine();
                showhelp = true;
            } catch (FormatException) {
                Console.Error.WriteLine("ERROR: invalid number in one of the constraints");
                Console.Error.WriteLine();
                showhelp = true;
            }

            Debug.Assert(procargs != null);
            if (!showhelp && !collectSystemStats && procargs.Count == 0)
            {
                Console.Error.WriteLine("ERROR: please provide either process name, PID, or turn on system tracing (-s)");
                Console.Error.WriteLine();
                showhelp = true;
            }

            if (showhelp)
            {
                ShowHelp(p);
                return;
            }

            // for diagnostics information
#if DEBUG
            Trace.Listeners.Add(new ConsoleTraceListener());
#endif

            var traceSession = new TraceSession(new WTraceOutput(eventNameFilter, outputFilename), printSummary);

            SetConsoleCtrlCHook(traceSession);

            try {
                if (procargs.Count == 0)
                {
                    Console.WriteLine("System tracing has started. Press Ctrl + C to stop...");
                    traceSession.TraceSystemOnly();
                }
                else if (!int.TryParse(procargs[0], out pid))
                {
                    traceSession.TraceNewProcess(procargs, spawnNewConsoleWindow, traceChildProcesses,
                                                 collectSystemStats);
                }
                else
                {
                    traceSession.TraceRunningProcess(pid, traceChildProcesses, collectSystemStats);
                }
            } catch (COMException ex) {
                if ((uint)ex.HResult == 0x800700B7)
                {
                    Console.Error.WriteLine("ERROR: could not start the kernel logger - make sure it is not running.");
                }
            } catch (Win32Exception ex) {
                Console.Error.WriteLine(
                    $"ERROR: an error occurred while trying to start or open the process, hr: 0x{ex.HResult:X8}, " +
                    $"code: 0x{ex.NativeErrorCode:X8} ({ex.Message}).");
            }
#if !DEBUG
            catch (Exception ex) {
                Console.Error.WriteLine($"ERROR: severe error happened when starting application: {ex.Message}");
            }
#endif
        }
Esempio n. 14
0
 static Helper()
 {
     AvailablePreciseMachineCounters = TraceEventProfileSources.GetInfo();
     CanEnableKernelProvider         = TraceEventSession.IsElevated() == true;
 }
Esempio n. 15
0
        /// <summary>
        /// This is a demo of using TraceEvent to activate a 'real time' provider that is listening to
        /// the MyEventSource above.   Normally this event source would be in a different process,  but
        /// it also works if this process generate the events and I do that here for simplicity.
        /// </summary>
        public int Run()
        {
            // Today you have to be Admin to turn on ETW events (anyone can write ETW events).
            if (!(TraceEventSession.IsElevated() ?? false))
            {
                ExceptionHelper.WriteFile("EtwErrors", "Not running as admin");
                return(-1);
            }

            // To listen to ETW events you need a session, which allows you to control which events will be produced
            // Note that it is the session and not the source that buffers events, and by default sessions will buffer
            // 64MB of events before dropping events.  Thus even if you don't immediately connect up the source and
            // read the events you should not lose them.
            //
            // As mentioned below, sessions can outlive the process that created them.  Thus you may need a way of
            // naming the session so that you can 'reconnect' to it from another process.   This is what the name
            // is for.  It can be anything, but it should be descriptive and unique.   If you expect multiple versions
            // of your program to run simultaneously, you need to generate unique names (e.g. add a process ID suffix)
            // however this is dangerous because you can leave data collection on if the program ends unexpectedly.
            var sessionName = "SellyServiceEtwMonitor";

            using (session = new TraceEventSession(sessionName))
            {
                /* BY DEFAULT ETW SESSIONS SURVIVE THE DEATH OF THE PROESS THAT CREATES THEM! */
                // Unlike most other resources on the system, ETW session live beyond the lifetime of the
                // process that created them.   This is very useful in some scenarios, but also creates the
                // very real possibility of leaving 'orphan' sessions running.
                //
                // To help avoid this by default TraceEventSession sets 'StopOnDispose' so that it will stop
                // the ETW session if the TraceEventSession dies.   Thus executions that 'clean up' the TraceEventSession
                // will clean up the ETW session.   This covers many cases (including throwing exceptions)
                //
                // However if the process is killed manually (including control C) this cleanup will not happen.
                // Thus best practices include
                //
                //     * Add a Control C handler that calls session.Dispose() so it gets cleaned up in this common case
                //     * use the same session name (say your program name) run-to-run so you don't create many orphans.
                //
                // By default TraceEventSessions are in 'create' mode where it assumes you want to create a new session.
                // In this mode if a session already exists, it is stopped and the new one is created.
                //
                // Here we install the Control C handler.   It is OK if Dispose is called more than once.
                Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { session.Dispose(); };

                /*****************************************************************************************************/
                // Hook up events.   To so this first we need a 'Parser. which knows how to part the events of a particular Event Provider.
                // In this case we get a DynamicTraceEventSource, which knows how to parse any EventSource provider.    This parser
                // is so common, that TraceEventSource as a shortcut property called 'Dynamic' that fetches this parsers.

                // For debugging, and demo purposes, hook up a callback for every event that 'Dynamic' knows about (this is not EVERY
                // event only those know about by RegisteredTraceEventParser).   However the 'UnhandledEvents' handler below will catch
                // the other ones.
                session.Source.Dynamic.All += EtwCallback.EventOccured;

                // At this point we have created a TraceEventSession, hooked it up to a TraceEventSource, and hooked the
                // TraceEventSource to a TraceEventParser (you can do several of these), and then hooked up callbacks
                // up to the TraceEventParser (again you can have several).  However we have NOT actually told any
                // provider (EventSources) to actually send any events to our TraceEventSession.
                // We do that now.

                // Enable my provider, you can call many of these on the same session to get events from other providers.
                // Because this EventSource did not define any keywords, I can only turn on all events or none.
                var restarted = session.EnableProvider("Microsoft-Windows-WFP", matchAnyKeywords: 0x0000010000000000);

                // Generally you don't bother with this warning, but for the demo we do.
                if (restarted)
                {
                    ToastHelper.PopToast("Restarting ETW session");
                }

                // go into a loop processing events can calling the callbacks.  Because this is live data (not from a file)
                // processing never completes by itself, but only because someone called 'source.Dispose()'.
                session.Source.Process();
            }
            return(0);
        }
Esempio n. 16
0
        private static void DoMain(string[] args)
        {
            List <string> procargs = null;
            var           showhelp = false;
            var           spawnNewConsoleWindow = false;
            var           traceOptions          = new TraceSession.TraceOptions();
            string        eventNameFilter       = null;

            var p = new OptionSet {
                {
                    "f|filter=", "Display only events which names contain the given keyword " +
                    "(case insensitive). Does not impact the summary.",
                    v => { eventNameFilter = v; }
                },
                { "b|bytes", "Dump packet bytes to the console.", v => { traceOptions.PrintPacketBytes = v != null; } },
                { "c|children", "Trace process and all its children.", v => { traceOptions.TraceChildProcesses = v != null; } },
                { "newconsole", "Start the process in a new console window.", v => { spawnNewConsoleWindow = v != null; } },
                { "h|help", "Show this message and exit.", v => showhelp = v != null },
                { "?", "Show this message and exit.", v => showhelp = v != null }
            };

            try {
                procargs = p.Parse(args);
            } catch (OptionException ex) {
                Console.Error.Write("ERROR: invalid argument");
                Console.Error.WriteLine(ex.Message);
                Console.Error.WriteLine();
                showhelp = true;
            } catch (FormatException) {
                Console.Error.WriteLine("ERROR: invalid number in one of the constraints");
                Console.Error.WriteLine();
                showhelp = true;
            }

            if (traceOptions.TraceChildProcesses && TraceEventSession.IsElevated() != true)
            {
                Console.Error.WriteLine("Must run elevated (Admin) to trace process children.");
                return;
            }


            if (!showhelp && procargs != null && procargs.Count == 0)
            {
                Console.Error.WriteLine("ERROR: please provide either process name or PID");
                Console.Error.WriteLine();
                showhelp = true;
            }

            if (showhelp)
            {
                ShowHelp(p);
                return;
            }

            // for diagnostics information
#if DEBUG
            Trace.Listeners.Add(new ConsoleTraceListener());
#endif

            var traceSession = new TraceSession(new ConsoleTraceOutput(eventNameFilter));

            SetConsoleCtrlCHook(traceSession);

            try {
                if (!int.TryParse(procargs[0], out var pid))
                {
                    traceSession.TraceNewProcess(procargs, spawnNewConsoleWindow, traceOptions);
                }
                else
                {
                    traceSession.TraceRunningProcess(pid, traceOptions);
                }
            } catch (COMException ex) {
                if ((uint)ex.HResult == 0x800700B7)
                {
                    Console.Error.WriteLine("ERROR: could not start the kernel logger - make sure it is not running.");
                }
            } catch (Win32Exception ex) {
                Console.Error.WriteLine(
                    $"ERROR: an error occurred while trying to start or open the process, hr: 0x{ex.HResult:X8}, " +
                    $"code: 0x{ex.NativeErrorCode:X8} ({ex.Message}).");
            }
#if !DEBUG
            catch (Exception ex) {
                Console.Error.WriteLine($"ERROR: severe error happened when starting application: {ex.Message}");
            }
#endif
        }
Esempio n. 17
0
        public static void Main()
        {
            if (TraceEventSession.IsElevated() != true)
            {
                Console.WriteLine("Must be elevated (Admin) to run this program.");
                Console.ReadKey();
                //Debugger.Break();
                return;
            }

            string       FileLocation = @"C:\Users\Sam\Desktop\Events.csv";
            StreamWriter sw           = File.AppendText(FileLocation);

            using (TraceEventSession session = new TraceEventSession(KernelTraceEventParser.KernelSessionName))
            {
                session.EnableKernelProvider(
                    KernelTraceEventParser.Keywords.Registry |
                    KernelTraceEventParser.Keywords.ImageLoad |
                    KernelTraceEventParser.Keywords.FileIOInit |
                    KernelTraceEventParser.Keywords.NetworkTCPIP |
                    KernelTraceEventParser.Keywords.Process);
                //  Subscribe to RegistryOpen
                //session.Source.Kernel.AddCallbackForEvents<RegistryTraceData>(processEvent);
                session.Source.Kernel.RegistrySetValue += delegate(RegistryTraceData data)
                {
                    //Console.WriteLine(data);
                    //sw.WriteLine(data);
                    //sw.WriteLine(RegistryOBJ.Registry(data.ProcessID,null,data.ProcessName,data.EventName,getStatus(data.Status),data.KeyName,data.KeyHandle,null,0));
                    //sw.WriteLine(data.ProcessID+","+null+"," +data.ProcessName+","+ data.EventName+"," +getStatus(data.Status)+","+ data.KeyName+","+ data.KeyHandle+"," +null+","+ 0);
                };
                session.Source.Kernel.RegistryOpen += delegate(RegistryTraceData data)
                {
                    //Console.WriteLine(data);
                    //sw.WriteLine(data);
                    //sw.WriteLine(data.ProcessID + "," + null + "," + data.ProcessName + "," + data.EventName + "," + getStatus(data.Status) + "," + data.KeyName + "," + data.KeyHandle + "," + null + "," + 0);
                };
                session.Source.Kernel.FileIOFileDelete += delegate(FileIONameTraceData data)
                {
                    //Console.WriteLine(data);
                    //sw.WriteLine(data);
                };
                session.Source.Kernel.RegistryDelete += delegate(RegistryTraceData data)
                {
                    //Console.WriteLine(data);
                    //sw.WriteLine(data);
                    //sw.WriteLine(data.ProcessID + "," + null + "," + data.ProcessName + "," + data.EventName + "," + getStatus(data.Status) + "," + data.KeyName + "," + data.KeyHandle + "," + null + "," + 0);
                };
                session.Source.Kernel.RegistryKCBDelete += delegate(RegistryTraceData data)
                {
                    //Console.WriteLine(data);
                    //sw.WriteLine(data);
                    //sw.WriteLine(data.ProcessID + "," + null + "," + data.ProcessName + "," + data.EventName + "," + getStatus(data.Status) + "," + data.KeyName + "," + data.KeyHandle + "," + null + "," + 0);
                };
                session.Source.Kernel.RegistryKCBCreate += delegate(RegistryTraceData data)
                {
                    //Console.WriteLine(data);
                    //sw.WriteLine(data);
                    //sw.WriteLine(data.ProcessID + "," + null + "," + data.ProcessName + "," + data.EventName + "," + getStatus(data.Status) + "," + data.KeyName + "," + data.KeyHandle + "," + null + "," + 0);
                };

                session.Source.Kernel.FileIOCreate += delegate(FileIOCreateTraceData data)
                {
                    //Console.WriteLine(data);
                    //sw.WriteLine(data);
                };
                session.Source.Kernel.ImageLoad += delegate(ImageLoadTraceData data)
                {
                    //Console.WriteLine(data);
                    //sw.WriteLine(data);
                };

                session.Source.Kernel.FileIORename += delegate(FileIOInfoTraceData data)
                {
                    //Console.WriteLine(data);
                    //sw.WriteLine(data);
                };
                session.Source.Kernel.ProcessStart += delegate(ProcessTraceData data)
                {
                    Console.WriteLine(data);
                    //sw.WriteLine(data);
                };

                session.Source.Kernel.ProcessStop += delegate(ProcessTraceData data)
                {
                    //Console.WriteLine(data);
                    //sw.WriteLine(data);
                };
                session.Source.Kernel.TcpIpConnect += delegate(TcpIpConnectTraceData data)
                {
                    //Console.WriteLine(data);
                    //sw.WriteLine(data);
                    //sw.WriteLine(data.ProcessID + "," + null + "," + data.ProcessName + "," + data.EventName + "," + 0 + "," + 0 + "," + 0 + "," + data.daddr + "," + data.dport);
                };
                session.Source.Kernel.UdpIpSend += delegate(UdpIpTraceData data)
                {
                    //Console.WriteLine(data);
                    //sw.WriteLine(data);
                    //sw.WriteLine(data.ProcessName +","+ data.dport);
                };


                session.Source.Process();
            }
        }
        public static void Run()
        {
            Out.WriteLine("******************** ObserveEventSource DEMO ********************");
            Out.WriteLine("This program Demos using the reactive framework (IObservable) to monitor");
            Out.WriteLine("EventSource events in real time, parsing their payloads dynamically.");
            Out.WriteLine();
            Out.WriteLine("The program has an EventSource that generates two kinds of events for 10 secs.");
            Out.WriteLine("while another part of the program reads them using IObservables and prints");
            Out.WriteLine("their parsed payload values.  ");
            Out.WriteLine();

            if (TraceEventSession.IsElevated() != true)
            {
                Out.WriteLine("Must be elevated (Admin) to run this method.");
                Debugger.Break();
                return;
            }
            var monitoringTimeSec = 15;

            Out.WriteLine("The monitor will run for a maximum of {0} seconds", monitoringTimeSec);
            Out.WriteLine("Press Ctrl-C to stop monitoring.");

            // create a real time user mode session
            using (var userSession = new TraceEventSession("ObserveEventSource"))
            {
                // Set up Ctrl-C to stop both user mode and kernel mode sessions
                SetupCtrlCHandler(() => { if (userSession != null)
                                          {
                                              userSession.Stop();
                                          }
                                  });

                // Turn on the Microsoft-Demos-SimpleMonitor provider
                userSession.EnableProvider("Microsoft-Demos-SimpleMonitor");

                // Create a stream of the 'MyFirstEvent' event source events and print their payloads
                IObservable <TraceEvent> firstEventStream = userSession.Source.Dynamic.Observe("Microsoft-Demos-SimpleMonitor", "MyFirstEvent");
                firstEventStream.Subscribe(onNext: ev => Out.WriteLine("FIRST_EVENTS :  MyName: '{0}' MyId: {1}", ev.PayloadByName("MyName"), ev.PayloadByName("MyId")));

                // Create a stream of the 'MySecond'Event' event source events and print their payloads
                IObservable <TraceEvent> secondEventStream = userSession.Source.Dynamic.Observe("Microsoft-Demos-SimpleMonitor", "MySecondEvent");
                secondEventStream.Subscribe(onNext: ev => Out.WriteLine("SECOND_EVENTS :  MyId: {0}", ev.PayloadByName("MyId")));

                // For debugging purposes, print every event from the SimpleMonitor stream
                IObservable <TraceEvent> allEventStream = userSession.Source.Dynamic.Observe(null);
                allEventStream.Subscribe(onNext: ev => Out.WriteLine("FROM_EVENTSOURCE: {0}/{1} ", ev.ProviderName, ev.EventName));

                // It is also useful for debugging purposes to see any events that entered by were not handled by any parser.   These can be bugs.
                IObservable <TraceEvent> unhandledEventStream = userSession.Source.ObserveUnhandled();
                unhandledEventStream.Subscribe(onNext: ev => Out.WriteLine("UNHANDLED :  {0}/{1} ", ev.ProviderName, ev.EventName));

                // Start Generate some events so we have something to see
                Producer.EventGenerator.CreateEvents();

                // Set up a timer to stop processing after monitoringTimeSec
                IObservable <long> timer = Observable.Timer(new TimeSpan(0, 0, monitoringTimeSec));
                timer.Subscribe(delegate
                {
                    Out.WriteLine("Stopped after {0} sec", monitoringTimeSec);
                    userSession.Dispose();
                });

                // OK we are all set up, time to listen for events and pass them to the observers.
                userSession.Source.Process();
            }
            Out.WriteLine("Done with program.");
        }
Esempio n. 19
0
        static int Main(string[] args)
        {
            bool bNetConnect = false, bNetTransfer = false, bProcess = false, bThread = false, bImageLoad = false;
            bool bDns = false, bSysmon = false, bRegistry = false, bFile = false;

            if (args.Length == 0)
            {
                Console.WriteLine("\nUsage: ETWMonitor [net_connect | net_transfer | process | thread | imageload | memory | registry | dns | sysmon]\n");
                Console.WriteLine("net_connect  : Show new TCP connections");
                Console.WriteLine("net_transfer : Show network transfers");
                Console.WriteLine("process      : Show process creations and exits");
                Console.WriteLine("thread       : Show suspicious thread creation (cross-process)");
                Console.WriteLine("imageload    : Show image loading");
                Console.WriteLine("file         : Show file activity");
                Console.WriteLine("registry     : Show registry details");
                Console.WriteLine("dns          : Show DNS requests");
                Console.WriteLine("sysmon       : Show entries from Sysmon");
                return(1);
            }

            if (args[0] == "net_connect")
            {
                Console.WriteLine("\nShowing new network connections");
                bNetConnect = true;
            }
            else if (args[0] == "net_transfer")
            {
                Console.WriteLine("\nShowing network transfers");
                bNetTransfer = true;
            }
            else if (args[0] == "process")
            {
                Console.WriteLine("\nShowing process creation and exits");
                bProcess = true;
            }
            else if (args[0] == "thread")
            {
                Console.WriteLine("\nShowing suspicious thread creations (cross-process)");
                bThread = true;
            }
            else if (args[0] == "imageload")
            {
                Console.WriteLine("\nShowing image loads");
                bImageLoad = true;
            }
            else if (args[0] == "file")
            {
                Console.WriteLine("\nShowing file system activity");
                bFile = true;
            }
            else if (args[0] == "registry")
            {
                Console.WriteLine("\nShowing registry details");
                bRegistry = true;
            }
            else if (args[0] == "dns")
            {
                Console.WriteLine("\nShowing DNS requests");
                bDns = true;
            }
            else if (args[0] == "sysmon")
            {
                Console.WriteLine("\nShowing Sysmon entries");
                bSysmon = true;
            }
            else
            {
                Console.WriteLine("\nInvalid option");
                return(1);
            }

            // Today you have to be Admin to turn on ETW events (anyone can write ETW events).
            if (!(TraceEventSession.IsElevated() ?? false))
            {
                Console.WriteLine("To turn on ETW events you need to be Administrator, please run from an Admin process.");
                return(-1);
            }

            var sessionName = "";

            if (bNetConnect)
            {
                sessionName = "NetConnectSession";
            }
            else if (bNetTransfer)
            {
                sessionName = "NetTransferSession";
            }
            else if (bProcess)
            {
                sessionName = "ProcessSession";
            }
            else if (bThread)
            {
                sessionName = "ThreadSession";
            }
            else if (bImageLoad)
            {
                sessionName = "ImageLoadSession";
            }
            else if (bFile)
            {
                sessionName = "FileSession";
            }
            else if (bRegistry)
            {
                sessionName = "RegistrySession";
            }
            else if (bDns)
            {
                sessionName = "DnsSession";
            }
            else if (bSysmon)
            {
                sessionName = "SysmonSession";
            }
            else
            {
                Console.WriteLine("Error");
                return(-1);
            }

            using (var session = new TraceEventSession(sessionName, null))  // the null second parameter means 'real time session'
            {
                session.StopOnDispose = true;

                Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { session.Dispose(); };

                // prepare to read from the session, connect the ETWTraceEventSource to the session
                using (var source = new ETWTraceEventSource(sessionName, TraceEventSourceType.Session))
                {
                    Action <TraceEvent> action = delegate(TraceEvent data)
                    {
                        var taskName  = data.TaskName;
                        var EventName = data.EventName;

                        if (bProcess)
                        {
                            if (EventName == "Process/DCStart" || EventName == "Process/Start")
                            {
                                ProcessTraceData startprocdata = (ProcessTraceData)data;

                                string exe = (string)data.PayloadByName("ImageFileName");

                                Console.Write(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + EventName);
                                Console.Write(" PPID: " + startprocdata.ParentID.ToString() + " PID: " + startprocdata.ProcessID.ToString());
                                Console.Write(" Name: " + exe);

                                Process PName = GetProcByID2(startprocdata.ParentID);

                                if (PName != null)
                                {
                                    Console.Write(" ParentName: " + PName.ProcessName);
                                }

                                Console.WriteLine(" CommandLine: " + startprocdata.CommandLine);
                            }
                            else if (EventName == "Process/End")
                            {
                                ProcessTraceData exitprocdata = (ProcessTraceData)data;
                                string           exe          = (string)data.PayloadByName("ImageFileName");

                                Console.Write(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + EventName);
                                Console.WriteLine(" PPID: " + exitprocdata.ParentID.ToString() + " PID: " + exitprocdata.ProcessID.ToString() + " " + exe);
                            }
                        }
                        else if (bNetConnect)
                        {
                            if (taskName == "TcpRequestConnect")
                            {
                                int threadID  = data.ThreadID;
                                int processID = data.ProcessID;

                                byte[] local_addr  = (byte[])data.PayloadByName("LocalAddress");
                                byte[] remote_addr = (byte[])data.PayloadByName("RemoteAddress");

                                if (local_addr == null || remote_addr == null)
                                {
                                    Console.WriteLine("Null addr!");
                                }

                                // First two bytes are address family: 2 for ipv4, 10 for ipv6
                                // Next two bytes are the port

                                var family = new byte[2];

                                family[0] = local_addr[0];
                                family[1] = local_addr[1];

                                ushort family_nr = BitConverter.ToUInt16(family, 0);

                                if (family_nr == 2)
                                {
                                    var local_port  = new byte[2];
                                    var remote_port = new byte[2];

                                    local_port[0] = local_addr[2];
                                    local_port[1] = local_addr[3];

                                    Array.Reverse(local_port); // Need to reverse port

                                    remote_port[0] = remote_addr[2];
                                    remote_port[1] = remote_addr[3];

                                    Array.Reverse(remote_port); // Need to reverse port

                                    ushort local_port_nr  = BitConverter.ToUInt16(local_port, 0);
                                    ushort remote_port_nr = BitConverter.ToUInt16(remote_port, 0);

                                    Process proc;
                                    string  processname = "<not found>";

                                    if (processID > 0)
                                    {
                                        proc = GetProcByID(processID);
                                        if (proc != null)
                                        {
                                            processname = proc.MainModule.ModuleName;
                                        }
                                    }

                                    Console.Write(data.TimeStamp.ToString("yyyy-MM-dd HH:mm:ss") + " " + taskName + " PID: " + processID);

                                    int parentid = GetParentProcessID(processID);

                                    if (parentid != 0)
                                    {
                                        Console.Write(" PPID: " + parentid);
                                    }
                                    else
                                    {
                                        Console.Write(" PPID: (null)");
                                    }

                                    Console.Write(" TID: " + threadID + " Name: " + processname);

                                    proc = GetProcByID(parentid);

                                    if (proc != null)
                                    {
                                        Console.Write(" Parent Name: " + proc.ProcessName);
                                    }
                                    else
                                    {
                                        Console.Write(" Parent Name: (null)");
                                    }

                                    string local_ip  = local_addr[4] + "." + local_addr[5] + "." + local_addr[6] + "." + local_addr[7];
                                    string remote_ip = remote_addr[4] + "." + remote_addr[5] + "." + remote_addr[6] + "." + remote_addr[7];

                                    Console.Write(" " + local_ip + ":" + local_port_nr + "->");
                                    Console.WriteLine(remote_ip + ":" + remote_port_nr + " ");
                                }
                                else if (family_nr == 0x10)
                                {
                                    Console.WriteLine("IPV6");
                                }
                            }
                        }
                        else if (bNetTransfer)
                        {
                            if (EventName == "TcpIp/Send" || EventName == "TcpIp/Recv")
                            {
                                Console.Write(data.TimeStamp.ToString("yyyy-MM-dd HH:mm:ss") + " " + EventName + " PID: " + data.ProcessID);

                                Process processname;

                                processname = GetProcByID(data.ProcessID);

                                if (processname != null)
                                {
                                    Console.Write(" Name: " + processname.ProcessName);
                                }
                                else
                                {
                                    Console.Write(" Name: (null)");
                                }

                                IPAddress saddr = (IPAddress)data.PayloadByName("saddr");
                                IPAddress daddr = (IPAddress)data.PayloadByName("daddr");
                                int       sport = (int)data.PayloadByName("sport");
                                int       dport = (int)data.PayloadByName("dport");
                                int       size  = (int)data.PayloadByName("size");

                                Console.Write(" Src: " + saddr.ToString() + ":" + sport + " Dst: " + daddr.ToString() + ":" + dport);
                                Console.WriteLine(" Size: " + size);
                            }
                        }
                        else if (bThread) // try to catch remote thread injections only
                        {
                            if (taskName == "ThreadStart")
                            {
                                int     destProcessID = (int)data.PayloadByName("ProcessID");
                                int     parentid;
                                Process processname;

                                if (data.ProcessID != destProcessID && data.ProcessID != 4)
                                {
                                    // check if destpid is not a child of srcpid, otherwise we have a problem!
                                    // check the parentpid of srcpid

                                    int destThreadID = (int)data.PayloadByName("ThreadID");
                                    int srcThreadID  = data.ThreadID;

                                    parentid = GetParentProcessID(destProcessID);
                                    if (parentid != 0 && parentid != data.ProcessID)
                                    {
                                        Console.Write(data.TimeStamp.ToString("yyyy-MM-dd HH:mm:ss") + " POSSIBLE THREAD INJECTION: ");
                                        Console.Write(taskName + " TID: " + destThreadID + " SrcTID: " + srcThreadID + " SrcPID: " + data.ProcessID);
                                        Console.Write(" DestPID: " + destProcessID);

                                        processname = GetProcByID(data.ProcessID);

                                        if (processname != null)
                                        {
                                            Console.Write(" SrcName: " + processname.ProcessName);
                                        }
                                        else
                                        {
                                            Console.Write(" SrcName: (null)");
                                        }

                                        processname = GetProcByID(destProcessID);

                                        if (processname != null)
                                        {
                                            Console.WriteLine(" DestName: " + processname.ProcessName);
                                        }
                                        else
                                        {
                                            Console.WriteLine(" DestName: (null)");
                                        }

                                        Console.WriteLine("\nDetailed information:\n" + data.ToString());
                                    }
                                }
                            }
                        }
                        else if (bImageLoad)
                        {
                            if (EventName == "Image/DCStart" || EventName == "Image/Load" || EventName == "Image/Unload")
                            {
                                int pid = (int)data.ProcessID;
                                Console.Write(data.TimeStamp.ToString("yyyy-MM-dd HH:mm:ss ") + EventName);
                                Console.Write(" PID: " + pid);

                                Process processname;

                                processname = GetProcByID(pid);

                                if (processname != null)
                                {
                                    Console.Write(" Name: " + processname.ProcessName);
                                }
                                else
                                {
                                    Console.Write(" Name: (null)");
                                }

                                string filename = (string)data.PayloadByName("FileName");
                                Console.WriteLine(" FileName: " + filename);
                            }
                        }
                        else if (bFile)
                        {
                            if (EventName == "CreateNewFile" || EventName == "DeletePath" || EventName == "NameDelete")
                            {
                                int pid = (int)data.ProcessID;
                                Console.Write(data.TimeStamp.ToString("yyyy-MM-dd HH:mm:ss ") + EventName);
                                Console.Write(" PID: " + pid);

                                Process processname;

                                processname = GetProcByID(pid);

                                if (processname != null)
                                {
                                    Console.Write(" Name: " + processname.ProcessName);
                                }
                                else
                                {
                                    Console.Write(" Name: (null)");
                                }

                                string filename = "";

                                if (EventName == "DeletePath")
                                {
                                    filename = (string)data.PayloadByName("FilePath");
                                }
                                else
                                {
                                    filename = (string)data.PayloadByName("FileName");
                                }

                                Console.WriteLine(" File: " + filename);
                            }
                        }
                        else if (bRegistry)
                        {
                            if (EventName == "EventID(1)/CreateKey" || EventName == "EventID(5)/SetValueKey" || EventName == "EventID(3)/DeleteKey" || EventName == "EventID(6)/DeleteValueKey")
                            {
                                int pid = (int)data.ProcessID;
                                Console.Write(data.TimeStamp.ToString("yyyy-MM-dd HH:mm:ss ") + EventName);
                                Console.Write(" PID: " + pid);

                                Process processname;

                                processname = GetProcByID(pid);

                                if (processname != null)
                                {
                                    Console.Write(" Name: " + processname.ProcessName);
                                }
                                else
                                {
                                    Console.Write(" Name: (null)");
                                }

                                if (EventName == "EventID(1)/CreateKey")
                                {
                                    string RelativeName = (string)data.PayloadByName("RelativeName");
                                    int    status       = (int)data.PayloadByName("Status");
                                    Console.WriteLine(" Status: " + status + " RelativeName: " + RelativeName);
                                }
                                else if (EventName == "EventID(3)/DeleteKey")
                                {
                                    int status = (int)data.PayloadByName("Status");
                                    Console.WriteLine(" Status: " + status);
                                }
                                else if (EventName == "EventID(5)/SetValueKey")
                                {
                                    string ValueName = (string)data.PayloadByName("ValueName");
                                    int    status    = (int)data.PayloadByName("Status");
                                    Console.WriteLine(" Status: " + status + " ValueName: " + ValueName);
                                }
                                else if (EventName == "EventID(6)/DeleteValueKey")
                                {
                                    string ValueName = (string)data.PayloadByName("ValueName");
                                    int    status    = (int)data.PayloadByName("Status");
                                    Console.WriteLine(" Status: " + status + " ValueName: " + ValueName);
                                }
                            }
                        }
                        else if (bDns)
                        {
                            int pid = (int)data.ProcessID;
                            Console.Write(data.TimeStamp.ToString("yyyy-MM-dd HH:mm:ss ") + EventName);
                            Console.Write(" PID: " + pid);

                            Process processname;

                            processname = GetProcByID(pid);

                            if (processname != null)
                            {
                                Console.Write(" Name: " + processname.ProcessName);
                            }
                            else
                            {
                                Console.Write(" Name: (null)");
                            }

                            string QueryName = (string)data.PayloadByName("QueryName");
                            Console.WriteLine(" QueryName: " + QueryName);
                        }
                        else if (bSysmon)
                        {
                            Console.WriteLine(data.ToString());
                        }
                    };

                    // You can also simply use 'logman query providers' to find out the GUID yourself and wire it in.

                    Guid processProviderGuid;

                    if (bProcess)
                    {
                        session.EnableKernelProvider(KernelTraceEventParser.Keywords.Process);
                    }
                    else if (bNetConnect)
                    {
                        processProviderGuid = TraceEventSession.GetProviderByName("Microsoft-Windows-TCPIP");
                        session.EnableProvider(processProviderGuid, TraceEventLevel.Informational, 0x80);  // ut:TcpipDiagnosis seems to do the job
                    }
                    else if (bNetTransfer)
                    {
                        session.EnableKernelProvider(KernelTraceEventParser.Keywords.NetworkTCPIP);
                    }
                    else if (bThread)
                    {
                        processProviderGuid = TraceEventSession.GetProviderByName("Microsoft-Windows-Kernel-Process");
                        session.EnableProvider(processProviderGuid, TraceEventLevel.Informational, 0x20);  // WINEVENT_KEYWORD_THREAD
                    }
                    else if (bImageLoad)
                    {
                        session.EnableKernelProvider(KernelTraceEventParser.Keywords.ImageLoad);
                    }
                    else if (bFile)
                    {
                        processProviderGuid = TraceEventSession.GetProviderByName("Microsoft-Windows-Kernel-File");
                        session.EnableProvider(processProviderGuid, TraceEventLevel.Informational, 0x0000000000001410); // KERNEL_FILE_KEYWORD_CREATE_NEW_FILE, KERNEL_FILE_KEYWORD_DELETE_PATH, KERNEL_FILE_KEYWORD_FILENAME
                    }
                    else if (bRegistry)
                    {
                        processProviderGuid = TraceEventSession.GetProviderByName("Microsoft-Windows-Kernel-Registry");
                        session.EnableProvider(processProviderGuid, TraceEventLevel.Informational, 0x0000000000005300); // SetValueKey, CreateKey, DeleteKey, DeleteValueKey
                    }
                    else if (bDns)
                    {
                        processProviderGuid = TraceEventSession.GetProviderByName("Microsoft-Windows-DNS-Client");
                        session.EnableProvider(processProviderGuid, TraceEventLevel.Informational, 0x8000000000000000);  //
                    }
                    else if (bSysmon)
                    {
                        processProviderGuid = TraceEventSession.GetProviderByName("Microsoft-Windows-Sysmon");
                        session.EnableProvider(processProviderGuid, TraceEventLevel.Informational, 0x8000000000000000);  // KERNEL_MEM_KEYWORD_MEMINFO
                    }
                    else
                    {
                        Console.WriteLine("Error");
                        return(-1);
                    }

                    // We use different parsers depending on the events. For TCP/IP stuff we need to
                    // use another since we want to register not only ProcessID but also ThreadID for each event
                    if (bNetConnect || bThread || bFile || bRegistry || bDns || bSysmon)
                    {
                        // Hook up the parser that knows about Any EventSources regsitered with windows.  (e.g. the OS ones).
                        var registeredParser = new RegisteredTraceEventParser(source);
                        registeredParser.All += action;
                    }
                    else
                    {
                        // Hook up the parser that knows about kernel traces
                        var KernelParser = new KernelTraceEventParser(source);
                        KernelParser.All += action;
                    }

                    Console.WriteLine("Starting Listening for events");
                    // go into a loop processing events can calling the callbacks.  Because this is live data (not from a file)
                    // processing never completes by itself, but only because someone called 'source.Close()'.
                    source.Process();
                    Console.WriteLine();
                    Console.WriteLine("Stopping Listening for events");
                }
            }
            return(0);
        }
Esempio n. 20
0
        /// <summary>
        /// This is a demo of using TraceEvent to activate a 'real time' provider that is listening to
        /// the MyEventSource above.   Normally this event source would be in a differnet process,  but
        /// it also works if this process generate the evnets and I do that here for simplicity.
        /// </summary>
        static int Main(string[] args)
        {
            // Today you have to be Admin to turn on ETW events (anyone can write ETW events).
            if (!(TraceEventSession.IsElevated() ?? false))
            {
                Console.WriteLine("To turn on ETW events you need to be Administrator, please run from an Admin process.");
                return(-1);
            }

            // As mentioned below, sessions can outlive the process that created them.  Thus you need a way of
            // naming the session so that you can 'reconnect' to it from another process.   This is what the name
            // is for.  It can be anything, but it should be descriptive and unique.   If you expect mulitple versions
            // of your program to run simultaneously, you need to generate unique names (e.g. add a process ID suffix)
            var sessionName = "ProessMonitorSession";

            using (var session = new TraceEventSession(sessionName, null))      // the null second parameter means 'real time session'
            {
                // Note that sessions create a OS object (a session) that lives beyond the lifetime of the process
                // that created it (like Filles), thus you have to be more careful about always cleaning them up.
                // An importanty way you can do this is to set the 'StopOnDispose' property which will cause the session to
                // stop (and thus the OS object will die) when the TraceEventSession dies.   Because we used a 'using'
                // statement, this means that any exception in the code below will clean up the OS object.
                session.StopOnDispose = true;

                // By default, if you hit Ctrl-C your .NET objects may not be disposed, so force it to.  It is OK if dispose is called twice.
                Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { session.Dispose(); };

                // prepare to read from the session, connect the ETWTraceEventSource to the session
                using (var source = new ETWTraceEventSource(sessionName, TraceEventSourceType.Session))
                {
                    Action <TraceEvent> action = delegate(TraceEvent data)
                    {
                        // Console.WriteLine("GOT EVENT: " + data.ToString());
                        var taskName = data.TaskName;
                        if (taskName == "ProcessStart" || taskName == "ProcessStop")
                        {
                            string exe     = (string)data.PayloadByName("ImageName");
                            string exeName = Path.GetFileNameWithoutExtension(exe);

                            int processId = (int)data.PayloadByName("ProcessID");
                            if (taskName == "ProcessStart")
                            {
                                int parentProcessId = (int)data.PayloadByName("ParentProcessID");
                                Console.WriteLine("{0:HH:mm:ss.fff}: {1,-12}: {2} ID: {3} ParentID: {4}",
                                                  data.TimeStamp, taskName, exeName, processId, parentProcessId);
                            }
                            else
                            {
                                int  exitCode  = (int)data.PayloadByName("ExitCode");
                                long cpuCycles = (long)data.PayloadByName("CPUCycleCount");
                                Console.WriteLine("{0:HH:mm:ss.fff}: {1,-12}: {2} ID: {3} EXIT: {4} CPU Cycles: {5:n0}",
                                                  data.TimeStamp, taskName, exeName, processId, exitCode, cpuCycles);
                            }
                        }
                    };

                    // Hook up the parser that knows about Any EventSources regsitered with windows.  (e.g. the OS ones.
                    var registeredParser = new RegisteredTraceEventParser(source);
                    registeredParser.All += action;

                    // You can also simply use 'logman query providers' to find out the GUID yourself and wire it in.
                    var processProviderGuid = TraceEventSession.GetProviderByName("Microsoft-Windows-Kernel-Process");
                    if (processProviderGuid == Guid.Empty)
                    {
                        Console.WriteLine("Error could not find Microsoft-Windows-Kernel-Process etw provider.");
                        return(-1);
                    }

                    // Using logman query providers Microsoft-Windows-Kernel-Process I get
                    //     0x0000000000000010  WINEVENT_KEYWORD_PROCESS
                    //     0x0000000000000020  WINEVENT_KEYWORD_THREAD
                    //     0x0000000000000040  WINEVENT_KEYWORD_IMAGE
                    //     0x0000000000000080  WINEVENT_KEYWORD_CPU_PRIORITY
                    //     0x0000000000000100  WINEVENT_KEYWORD_OTHER_PRIORITY
                    //     0x0000000000000200  WINEVENT_KEYWORD_PROCESS_FREEZE
                    //     0x8000000000000000  Microsoft-Windows-Kernel-Process/Analytic
                    // So 0x10 is WINEVENT_KEYWORD_PROCESS
                    session.EnableProvider(processProviderGuid, TraceEventLevel.Informational, 0x10);

                    Console.WriteLine("Starting Listening for events");
                    // go into a loop processing events can calling the callbacks.  Because this is live data (not from a file)
                    // processing never completes by itself, but only because someone called 'source.Close()'.
                    source.Process();
                    Console.WriteLine();
                    Console.WriteLine("Stopping Listening for events");
                }
            }
            return(0);
        }
Esempio n. 21
0
        protected override void ProcessRecord()
        {
            ErrorRecord errorRecord = null;

            if (TraceEventSession.IsElevated() != true)
            {
                errorRecord = new ErrorRecord(new InvalidOperationException("Must be elevated (Admin) to run this cmdlet."),
                                              "MissingAdminRights", ErrorCategory.InvalidOperation, null);
                WriteError(errorRecord);
                return;
            }

            processTraceRunner = new TraceSession(new PowerShellTraceOutput(eventQueue, Filter), !NoSummary);
            bool       isMainThreadFinished = false;
            const bool collectSystemStats   = false; // not available in PowerShell

            ThreadPool.QueueUserWorkItem((o) => {
                try {
                    if (string.Equals(ParameterSetName, "StartNewProcess", StringComparison.Ordinal))
                    {
                        var args = new List <string>()
                        {
                            FilePath
                        };
                        if (ArgumentList != null)
                        {
                            args.AddRange(ArgumentList);
                        }
                        processTraceRunner.TraceNewProcess(args, NewConsole, TraceChildProcesses,
                                                           collectSystemStats);
                    }
                    else
                    {
                        processTraceRunner.TraceRunningProcess(Pid, TraceChildProcesses, collectSystemStats);
                    }
                    isMainThreadFinished = true;
                } catch (Exception ex) {
                    errorRecord          = new ErrorRecord(ex, ex.GetType().FullName, ErrorCategory.InvalidOperation, null);
                    isMainThreadFinished = true;
                }
            });

            PowerShellWtraceEvent ev;

            while (!isMainThreadFinished)
            {
                while (eventQueue.TryDequeue(out ev))
                {
                    WriteObject(ev);
                }
                Thread.Sleep(100);
            }
            // the rest of the events
            while (eventQueue.TryDequeue(out ev))
            {
                WriteObject(ev);
            }

            if (errorRecord != null)
            {
                WriteError(errorRecord);
            }
        }
 public bool?IsElevated()
 {
     return(TraceEventSession.IsElevated());
 }
        public static void Run()
        {
            // Check OS version
            if (Environment.OSVersion.Version.Major * 10 + Environment.OSVersion.Version.Minor < 62)
            {
                _out.WriteLine("The monitor only works on Win 8 / Win Server 2012 and above.");
                return;
            }

            // Check the process's privilege
            if (TraceEventSession.IsElevated() != true)
            {
                _out.WriteLine("You must be elevated as admin to run this program.");
                return;
            }

            TraceEventSession session = null;

            _out.WriteLine("************** KernelEventMonitor ***************");
            _out.WriteLine("Press <C>-C to stop the monitor!");
            _out.WriteLine();

            // Set up <C>-C to stop kernel mode sessions
            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs cancelArgs)
            {
                if (session != null)
                {
                    session.Dispose();
                }
                cancelArgs.Cancel = true;
            };

            // Set up a timer to stop processing after monitorTime
            //var timer = new Timer(delegate (object state)
            //{
            //    Out.WriteLine("Stopped Monitoring after {0} sec", monitorTime);
            //    if (session != null)
            //        session.Dispose();
            //}, null, monitorTime * 1000, Timeout.Infinite);

            // Create new session to receive kernel evetn
            using (session = new TraceEventSession("MonitorKernelEventSession"))
            {
                //Enable the kernel events we interest
                _out.WriteLine("Enabling Image Load, Process, FileIO, Registry and Network");
                session.EnableKernelProvider(
                    KernelTraceEventParser.Keywords.ImageLoad |
                    KernelTraceEventParser.Keywords.Process |
                    KernelTraceEventParser.Keywords.FileIOInit |
                    KernelTraceEventParser.Keywords.Registry |
                    KernelTraceEventParser.Keywords.NetworkTCPIP);

                // Subscribe kernel events we interest
                session.Source.UnhandledEvents            += EventProcess;
                session.Source.Kernel.FileIODelete        += EventProcess;
                session.Source.Kernel.FileIOCreate        += EventProcess;
                session.Source.Kernel.FileIODirEnum       += EventProcess;
                session.Source.Kernel.FileIORead          += EventProcess;
                session.Source.Kernel.FileIORename        += EventProcess;
                session.Source.Kernel.FileIOWrite         += EventProcess;
                session.Source.Kernel.ProcessStop         += EventProcess;
                session.Source.Kernel.ProcessStart        += EventProcess;
                session.Source.Kernel.ImageLoad           += EventProcess;
                session.Source.Kernel.TcpIpSend           += EventProcess;
                session.Source.Kernel.TcpIpRecv           += EventProcess;
                session.Source.Kernel.UdpIpRecv           += EventProcess;
                session.Source.Kernel.UdpIpSend           += EventProcess;
                session.Source.Kernel.RegistryCreate      += EventProcess;
                session.Source.Kernel.RegistryDelete      += EventProcess;
                session.Source.Kernel.RegistryDeleteValue += EventProcess;
                session.Source.Kernel.RegistrySetValue    += EventProcess;

                // Begin to monitor events
                session.Source.Process();
            }

            //timer.Dispose();
        }
        public void Run()
        {
            var monitoredAppPools = ConfigTools.GetConfiguredAppPools();
            var monitoredApps     = ConfigTools.GetConfiguredApps();
            var console           = Boolean.Parse(ConfigurationManager.AppSettings["ConsoleOutput"]);
            var api = Boolean.Parse(ConfigurationManager.AppSettings["APIOutput"]);


            if (TraceEventSession.IsElevated() != true)
            {
                Console.WriteLine("Must be elevated (Admin) to run this method.");
                Debugger.Break();
                return;
            }


            try
            {
                var appPoolNames = IISAdminTools.GetApplicationPools();

                foreach (var appPoolName in appPoolNames)
                {
                    appPools.Add(appPoolName, IISAdminTools.GetAppPoolProcesses(appPoolName));
                }
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("not registered"))
                {
                    Console.WriteLine("Could not initialize; IIS isn't installed upon this machine.");
                }
                Debugger.Break();
            }

            //var monitoringTimeSec = 60;
            //Console.WriteLine("The monitor will run for a maximum of {0} seconds", monitoringTimeSec);
            //Console.WriteLine("Press Ctrl-C to stop monitoring of GC Allocs");

            // create a real time user mode session
            using (var userSession = new TraceEventSession("ObserveGCAllocs"))
            {
                // Set up Ctrl-C to stop the session
                SetupCtrlCHandler(() => { userSession.Stop(); });

                // enable the CLR provider with default keywords (minus the rundown CLR events)
                userSession.EnableProvider(ClrTraceEventParser.ProviderGuid, TraceEventLevel.Verbose,
                                           (ulong)(ClrTraceEventParser.Keywords.GC));

                // Create a stream of GC Allocation events (happens every time 100K of allocations happen)
                IObservable <GCAllocationTickTraceData> gcAllocStream = userSession.Source.Clr.Observe <GCAllocationTickTraceData>();

                // Print the outgoing stream to the console
                //gcAllocStream.Subscribe(allocData =>
                //{
                //    if (GetProcessName(allocData.ProcessID) == "devenv")
                //    {
                //        //Out.WriteLine("GC Alloc  :  Proc: {0,10}({1,3}) Amount: {2,6:f1}K  TypeSample: {3}", GetProcessName(allocData.ProcessID), GetProcessCPU(allocData.ProcessID), allocData.AllocationAmount / 1000.0, allocData.TypeName);
                //    }
                //});

                // Create a stream of GC Collection events
                IObservable <GCHeapStatsTraceData> gcCollectStream = userSession.Source.Clr.Observe <GCHeapStatsTraceData>();

                // Print the outgoing stream to the console
                gcCollectStream.Subscribe(collectData =>
                {
                    var appName     = GetProcessName(collectData.ProcessID);
                    var metricsList = new List <MetricPackage>();


                    if (DEBUG_LEVEL == "DEBUG")
                    {
                        Out.WriteLine("Application Name : {0} is reporting in..", appName);
                    }

                    if (DoesProcessIdExist(collectData.ProcessID))
                    {
                        var appPoolName = GetAppPoolName(collectData.ProcessID);

                        if (DEBUG_LEVEL == "DEBUG")
                        {
                            Out.WriteLine("App Pool Name : {0}", appPoolName);
                        }


                        if (monitoredAppPools.Contains(appPoolName))
                        {
                            int pid              = collectData.ProcessID;
                            Process toMonitor    = Process.GetProcessById(pid);
                            int threadCt         = toMonitor.Threads.Count;
                            long memoryUsed      = toMonitor.WorkingSet64;
                            long memoryCommitted = toMonitor.PeakWorkingSet64;
                            var machineName      = System.Environment.MachineName;
                            if (api)
                            {
                                metricsList.Add(CreateMetricPackage(string.Format("Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}", machineName, appPoolName, "Memory Heap - Gen 0 Usage"), collectData.GenerationSize0));
                                metricsList.Add(CreateMetricPackage(string.Format("Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}", machineName, appPoolName, "Memory Heap - Gen 1 Usage"), collectData.GenerationSize1));
                                metricsList.Add(CreateMetricPackage(string.Format("Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}", machineName, appPoolName, "Memory Heap - Gen 2 Usage"), collectData.GenerationSize2));
                                metricsList.Add(CreateMetricPackage(string.Format("Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}", machineName, appPoolName, "Large Object Heap - Current Usage"), collectData.GenerationSize3));
                                metricsList.Add(CreateMetricPackage(string.Format("Custom Metrics|Memory|Nodes|{0}|{1}|Usage Metrics|{2}", machineName, appPoolName, "Current Usage"), memoryUsed));
                                metricsList.Add(CreateMetricPackage(string.Format("Custom Metrics|Memory|Nodes|{0}|{1}|Usage Metrics|{2}", machineName, appPoolName, "Current Committed"), memoryCommitted));
                                metricsList.Add(CreateMetricPackage(string.Format("Custom Metrics|Memory|Nodes|{0}|{1}|Usage Metrics|{2}", machineName, appPoolName, "Thread Count"), threadCt));
                            }
                            if (console)
                            {
                                Out.WriteLine("name = Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}, value={3}", machineName, appPoolName, "Memory Heap - Gen 0 Usage", collectData.GenerationSize0);
                                Out.WriteLine("name = Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}, value={3}", machineName, appPoolName, "Memory Heap - Gen 1 Usage", collectData.GenerationSize1);
                                Out.WriteLine("name = Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}, value={3}", machineName, appPoolName, "Memory Heap - Gen 2 Usage", collectData.GenerationSize2);
                                Out.WriteLine("name = Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}, value={3}", machineName, appPoolName, "Large Object Heap - Current Usage", collectData.GenerationSize3);
                                Out.WriteLine("name = Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}, value={3}", machineName, appPoolName, "Current Usage", memoryUsed);
                                Out.WriteLine("name = Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}, value={3}", machineName, appPoolName, "Current Committed", memoryCommitted);
                                Out.WriteLine("name = Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}, value={3}", machineName, appPoolName, "Thread Count", threadCt);
                            }
                        }
                    }
                    else if (monitoredApps.Contains(appName))
                    {
                        {
                            var machineName      = System.Environment.MachineName;
                            int pid              = collectData.ProcessID;
                            Process toMonitor    = Process.GetProcessById(pid);
                            long memoryUsed      = toMonitor.WorkingSet64;
                            long memoryCommitted = toMonitor.PeakWorkingSet64;

                            if (api)
                            {
                                metricsList.Add(CreateMetricPackage(string.Format("Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}", machineName, appName, "Memory Heap - Gen 0 Usage"), collectData.GenerationSize0));
                                metricsList.Add(CreateMetricPackage(string.Format("Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}", machineName, appName, "Memory Heap - Gen 1 Usage"), collectData.GenerationSize1));
                                metricsList.Add(CreateMetricPackage(string.Format("Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}", machineName, appName, "Memory Heap - Gen 2 Usage"), collectData.GenerationSize2));
                                metricsList.Add(CreateMetricPackage(string.Format("Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}", machineName, appName, "Large Object Heap - Current Usage"), collectData.GenerationSize3));
                                metricsList.Add(CreateMetricPackage(string.Format("Custom Metrics|Memory|Nodes|{0}|{1}|Usage Metrics|{2}", machineName, appName, "Current Usage"), memoryUsed));
                                metricsList.Add(CreateMetricPackage(string.Format("Custom Metrics|Memory|Nodes|{0}|{1}|Usage Metrics|{2}", machineName, appName, "Current Committed"), memoryCommitted));
                            }
                            if (console)
                            {
                                Out.WriteLine("name=Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}, value={3}", machineName, appName, "Memory Heap - Gen 0 Usage", collectData.GenerationSize0);
                                Out.WriteLine("name=Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}, value={3}", machineName, appName, "Memory Heap - Gen 1 Usage", collectData.GenerationSize1);
                                Out.WriteLine("name=Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}, value={3}", machineName, appName, "Memory Heap - Gen 2 Usage", collectData.GenerationSize2);
                                Out.WriteLine("name=Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}, value={3}", machineName, appName, "Large Object Heap - Current Usage", collectData.GenerationSize3);
                                Out.WriteLine("name=Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}, value={3}", machineName, appName, "Current Usage", memoryUsed);
                                Out.WriteLine("name=Custom Metrics|Memory|Nodes|{0}|{1}|GC Metrics|{2}, value={3}", machineName, appName, "Current Committed", memoryCommitted);
                            }
                        }

                        //    Out.WriteLine("GC Collect:  Proc: {0,10}({1,3}) Gen0: {2,6:f1}M Gen1: {3,6:f1}M Gen2: {4,6:f1}M LargeObj: {5,6:f1}M",
                        //         GetProcessName(collectData.ProcessID),
                        //         GetProcessCPU(collectData.ProcessID),
                        //         collectData.GenerationSize0 / 1000000.0,
                        //         collectData.GenerationSize1 / 1000000.0,
                        //         collectData.GenerationSize2 / 1000000.0,
                        //         collectData.GenerationSize3 / 1000000.0);
                    }
                    if (metricsList.Count > 0)
                    {
                        WriteLines(metricsList);
                    }
                });

                //IObservable<long> timer = Observable.Timer(new TimeSpan(0, 0, monitoringTimeSec));
                //timer.Subscribe(delegate
                //{
                //    Console.WriteLine("Stopped after {0} sec", monitoringTimeSec);
                //    userSession.Dispose();
                //});

                // OK we are all set up, time to listen for events and pass them to the observers.
                userSession.Source.Process();
            }

            Console.WriteLine("Done with program.");
        }
Esempio n. 25
0
        static void Main(string[] args)
        {
            // This is the name of the event source.
            // Given just the name of the eventSource you can get the GUID for the evenSource by calling this API.
            // From a ETW perspective, the GUID is the 'true name' of the EventSource.
            var providerGuid2 = Guid.Parse("{E13C0D23-CCBC-4E12-931B-D9CC2EEE27E4}");

            // Today you have to be Admin to turn on ETW events (anyone can write ETW events).
            if (!(TraceEventSession.IsElevated() ?? false))
            {
                Console.WriteLine(
                    "To turn on ETW events you need to be Administrator, please run from an Admin process.");
            }

            // As mentioned below, sessions can outlive the process that created them.  Thus you need a way of
            // naming the session so that you can 'reconnect' to it from another process.   This is what the name
            // is for.  It can be anything, but it should be descriptive and unique.   If you expect mulitple versions
            // of your program to run simultaneously, you need to generate unique names (e.g. add a process ID suffix)
            Console.WriteLine("Creating a 'My Session' session");
            var sessionName = "My Session";

            using (var session = new TraceEventSession(sessionName, null))
            // the null second parameter means 'real time session'
            {
                // Note that sessions create a OS object (a session) that lives beyond the lifetime of the process
                // that created it (like Filles), thus you have to be more careful about always cleaning them up.
                // An importanty way you can do this is to set the 'StopOnDispose' property which will cause the session to
                // stop (and thus the OS object will die) when the TraceEventSession dies.   Because we used a 'using'
                // statement, this means that any exception in the code below will clean up the OS object.
                session.StopOnDispose = true;

                // By default, if you hit Ctrl-C your .NET objects may not be disposed, so force it to.  It is OK if dispose is called twice.
                Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { session.Dispose(); };

                // prepare to read from the session, connect the ETWTraceEventSource to the session
                using (var source = new ETWTraceEventSource(sessionName, TraceEventSourceType.Session))
                {
                    // To demonstrate non-trivial event manipuation, we calculate the time delta between 'MyFirstEvent and 'MySecondEvent'
                    // These variables are used in this calculation
                    int    lastMyEventID   = int.MinValue; // an illegal value to start with.
                    double lastMyEventMSec = 0;

                    // Hook up the parser that knows about EventSources
                    var callParser = new ETWClrProfilerTraceEventParser(source);
                    callParser.AddCallbackForEvents(delegate(TraceEvent eventdata)
                    {
                        using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\etwdata.txt", true))
                        {
                            file.WriteLine(eventdata.EventName + eventdata);
                        }
                    });


                    //parser2.All += delegate (TraceEvent data)
                    //{
                    //    using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\etwdata.txt", true))
                    //    {
                    //        file.WriteLine(data.EventName);
                    //    }
                    //    Console.WriteLine("Event : " + data.EventName);
                    //};


                    // Enable my provider, you can call many of these on the same session to get other events.
                    session.EnableProvider(ETWClrProfilerTraceEventParser.ProviderGuid, TraceEventLevel.Always, (ulong)ETWClrProfilerTraceEventParser.Keywords.Call);

                    Console.WriteLine("Staring Listing for events");
                    // go into a loop processing events can calling the callbacks.  Because this is live data (not from a file)
                    // processing never completes by itself, but only because someone called 'source.Close()'.
                    source.Process();
                    Console.WriteLine();
                    Console.WriteLine("Stopping the collection of events.");
                }
            }
        }
Esempio n. 26
0
        public static void StartTrace(CollectorType CollectorType, ulong TraceKeywords, OutputType OutputType, String Path, FilterOption FilterOption, Object FilterValue, String YaraScan, YaraOptions YaraOptions, String ProviderName = "", UserTraceEventLevel UserTraceEventLevel = UserTraceEventLevel.Informational)
        {
            // Is elevated?
            if (TraceEventSession.IsElevated() != true)
            {
                SilkUtility.ReturnStatusMessage("[!] The collector must be run as Administrator..", ConsoleColor.Red);
                return;
            }

            // Print status
            SilkUtility.ReturnStatusMessage("[>] Starting trace collector (Ctrl-c to stop)..", ConsoleColor.Yellow);
            SilkUtility.ReturnStatusMessage("[?] Events captured: 0", ConsoleColor.Green); // We will update this dynamically

            // The kernel collector has naming requirements
            if (CollectorType == CollectorType.Kernel)
            {
                SilkUtility.EventParseSessionName = KernelTraceEventParser.KernelSessionName;
            }
            else
            {
                // We add a GUID in case of concurrent SilkETW execution
                String RandId = Guid.NewGuid().ToString();
                SilkUtility.EventParseSessionName = ("SilkETWUserCollector_" + RandId);
            }

            // Create trace session
            using (var TraceSession = new TraceEventSession(SilkUtility.EventParseSessionName))
            {
                // The collector cannot survive process termination (safeguard)
                TraceSession.StopOnDispose = true;

                // Create event source
                using (var EventSource = new ETWTraceEventSource(SilkUtility.EventParseSessionName, TraceEventSourceType.Session))
                {
                    // Ctrl-c callback handler
                    SilkUtility.SetupCtrlCHandler(() =>
                    {
                        if (OutputType == OutputType.eventlog)
                        {
                            SilkUtility.WriteEventLogEntry("{\"Collector\":\"Stop\",\"Error\":false}", EventLogEntryType.SuccessAudit, EventIds.StopOk, Path);
                        }
                        TerminateCollector();
                    });

                    // A DynamicTraceEventParser can understand how to read the embedded manifests that occur in the dataStream
                    var EventParser = new DynamicTraceEventParser(EventSource);

                    // Loop events as they arrive
                    EventParser.All += delegate(TraceEvent data)
                    {
                        // It's a bit ugly but ... ¯\_(ツ)_/¯
                        if (FilterOption != FilterOption.None)
                        {
                            if (FilterOption == FilterOption.Opcode && (byte)data.Opcode != (byte)FilterValue)
                            {
                                SilkUtility.ProcessEventData = false;
                            }
                            else if (FilterOption == FilterOption.ProcessID && data.ProcessID != (UInt32)FilterValue)
                            {
                                SilkUtility.ProcessEventData = false;
                            }
                            else if (FilterOption == FilterOption.ProcessName && data.ProcessName != (String)FilterValue)
                            {
                                SilkUtility.ProcessEventData = false;
                            }
                            else if (FilterOption == FilterOption.EventName && data.EventName != (String)FilterValue)
                            {
                                SilkUtility.ProcessEventData = false;
                            }
                            else
                            {
                                SilkUtility.ProcessEventData = true;
                            }
                        }
                        else
                        {
                            SilkUtility.ProcessEventData = true;
                        }

                        // Only process/serialize events if they match our filter
                        if (SilkUtility.ProcessEventData)
                        {
                            // Display running event count
                            SilkUtility.RunningEventCount += 1;
                            SilkUtility.UpdateEventCount("[?] Events captured: " + SilkUtility.RunningEventCount);

                            var eRecord = new EventRecordStruct
                            {
                                ProviderGuid    = data.ProviderGuid,
                                YaraMatch       = new List <String>(),
                                ProviderName    = data.ProviderName,
                                EventName       = data.EventName,
                                Opcode          = data.Opcode,
                                OpcodeName      = data.OpcodeName,
                                TimeStamp       = data.TimeStamp,
                                ThreadID        = data.ThreadID,
                                ProcessID       = data.ProcessID,
                                ProcessName     = data.ProcessName,
                                PointerSize     = data.PointerSize,
                                EventDataLength = data.EventDataLength
                            };

                            // Populate Proc name if undefined
                            if (String.IsNullOrEmpty(eRecord.ProcessName))
                            {
                                try
                                {
                                    eRecord.ProcessName = Process.GetProcessById(eRecord.ProcessID).ProcessName;
                                }
                                catch
                                {
                                    eRecord.ProcessName = "N/A";
                                }
                            }
                            var EventProperties = new Hashtable();

                            // Try to parse event XML
                            try
                            {
                                StringReader  XmlStringContent   = new StringReader(data.ToString());
                                XmlTextReader EventElementReader = new XmlTextReader(XmlStringContent);
                                while (EventElementReader.Read())
                                {
                                    for (int AttribIndex = 0; AttribIndex < EventElementReader.AttributeCount; AttribIndex++)
                                    {
                                        EventElementReader.MoveToAttribute(AttribIndex);

                                        // Cap maxlen for eventdata elements to 10k
                                        if (EventElementReader.Value.Length > 10000)
                                        {
                                            String DataValue = EventElementReader.Value.Substring(0, Math.Min(EventElementReader.Value.Length, 10000));
                                            EventProperties.Add(EventElementReader.Name, DataValue);
                                        }
                                        else
                                        {
                                            EventProperties.Add(EventElementReader.Name, EventElementReader.Value);
                                        }
                                    }
                                }
                            }
                            catch
                            {
                                // For debugging (?), never seen this fail
                                EventProperties.Add("XmlEventParsing", "false");
                            }
                            eRecord.XmlEventData = EventProperties;

                            // Serialize to JSON
                            String JSONEventData = Newtonsoft.Json.JsonConvert.SerializeObject(eRecord);
                            int    ProcessResult = SilkUtility.ProcessJSONEventData(JSONEventData, OutputType, Path, YaraScan, YaraOptions);

                            // Verify that we processed the result successfully
                            if (ProcessResult != 0)
                            {
                                if (ProcessResult == 1)
                                {
                                    SilkUtility.ReturnStatusMessage("[!] The collector failed to write to file", ConsoleColor.Red);
                                }
                                else if (ProcessResult == 2)
                                {
                                    SilkUtility.ReturnStatusMessage("[!] The collector failed to POST the result", ConsoleColor.Red);
                                }
                                else
                                {
                                    SilkUtility.ReturnStatusMessage("[!] The collector failed write to the eventlog", ConsoleColor.Red);
                                }

                                // Write status to eventlog if dictated by the output type
                                if (OutputType == OutputType.eventlog)
                                {
                                    SilkUtility.WriteEventLogEntry($"{{\"Collector\":\"Stop\",\"Error\":true,\"ErrorCode\":{ProcessResult}}}", EventLogEntryType.Error, EventIds.StopError, Path);
                                }

                                // Shut down the collector
                                TerminateCollector();
                            }
                        }
                    };

                    // Specify the providers details
                    if (CollectorType == CollectorType.Kernel)
                    {
                        TraceSession.EnableKernelProvider((KernelTraceEventParser.Keywords)TraceKeywords);
                    }
                    else
                    {
                        // Note that the collector doesn't know if you specified a wrong provider name,
                        // the only tell is that you won't get any events ;)
                        TraceSession.EnableProvider(ProviderName, (TraceEventLevel)UserTraceEventLevel, TraceKeywords);
                    }

                    // Write status to eventlog if dictated by the output type
                    if (OutputType == OutputType.eventlog)
                    {
                        String ConvertKeywords;
                        if (CollectorType == CollectorType.Kernel)
                        {
                            ConvertKeywords = Enum.GetName(typeof(KernelTraceEventParser.Keywords), TraceKeywords);
                        }
                        else
                        {
                            ConvertKeywords = "0x" + String.Format("{0:X}", TraceKeywords);
                        }
                        String Message = $"{{\"Collector\":\"Start\",\"Data\":{{\"Type\":\"{CollectorType}\",\"Provider\":\"{ProviderName}\",\"Keywords\":\"{ConvertKeywords}\",\"FilterOption\":\"{FilterOption}\",\"FilterValue\":\"{FilterValue}\",\"YaraPath\":\"{YaraScan}\",\"YaraOption\":\"{YaraOptions}\"}}}}";
                        SilkUtility.WriteEventLogEntry(Message, EventLogEntryType.SuccessAudit, EventIds.Start, Path);
                    }

                    // Continuously process all new events in the data source
                    EventSource.Process();

                    // Helper to clean up colloector
                    void TerminateCollector()
                    {
                        EventSource.StopProcessing();
                        TraceSession?.Stop();
                        Console.CursorVisible = true;
                        SilkUtility.ReturnStatusMessage("[+] Collector terminated", ConsoleColor.Green);
                    }
                }
            }
        }
Esempio n. 27
0
        /// <summary>
        ///     1. In the specified assembly, get the ETW providers set as assembly attributes (PerformanceTestInfo)
        ///     2. Check if the benchmark assembly request Precise Machine Counters(PMC) to be collected
        ///     3. Enable Kernel providers if needed
        ///     4. Get non-kernel ETW flags set and enable them
        ///     5. Run the benchmarks
        ///     6. Stop collecting ETW
        ///     7. Merge ETL files.
        /// </summary>
        /// <param name="assemblyFileName"></param>
        /// <param name="runId"></param>
        /// <param name="outputDirectory"></param>
        /// <param name="action"></param>
        /// <param name="collectOutputFilesCallback">Callback used to collect a list of files generated.</param>
        /// <returns></returns>
        public static void Record(string assemblyFileName, string runId, string outputDirectory, Action action, Action <string> collectOutputFilesCallback)
        {
            if (TraceEventSession.IsElevated() != true)
            {
                const string errMessage = "In order to profile, application is required to run as Administrator.";
                WriteErrorLine(errMessage);
                throw new InvalidOperationException(errMessage);
            }

            const int bufferSizeMB       = 256;
            var       sessionName        = $"Performance-Api-Session-{runId}";
            var       name               = $"{runId}-{Path.GetFileNameWithoutExtension(assemblyFileName)}";
            var       userFullFileName   = Path.Combine(outputDirectory, $"{name}.etl");
            var       kernelFullFileName = Path.Combine(outputDirectory, $"{name}.kernel.etl"); // without this parameter, EnableKernelProvider will fail

            PrintProfilingInformation(assemblyFileName, sessionName, userFullFileName);

            (var providers, var performanceTestMessages) = XunitBenchmark.GetMetadata(assemblyFileName);
            var kernelProviderInfo = providers.OfType <KernelProviderInfo>().FirstOrDefault();

            var needKernelSession = NeedSeparateKernelSession(kernelProviderInfo);

            using (var safeKernelSession = needKernelSession ? MakeSafeTerminateTraceEventSession(KernelTraceEventParser.KernelSessionName, kernelFullFileName) : null)
            {
                var kernelSession = safeKernelSession?.BaseDisposableObject;
                if (kernelSession != null)
                {
                    SetPreciseMachineCounters(providers);
                    kernelSession.BufferSizeMB = bufferSizeMB;
                    var flags        = (KernelTraceEventParser.Keywords)kernelProviderInfo.Keywords;
                    var stackCapture = (KernelTraceEventParser.Keywords)kernelProviderInfo.StackKeywords;
                    kernelSession.EnableKernelProvider(flags, stackCapture);
                }

                using (var safeUserEventSession = MakeSafeTerminateTraceEventSession(sessionName, userFullFileName))
                {
                    var userEventSession = safeUserEventSession.BaseDisposableObject;
                    userEventSession.BufferSizeMB = bufferSizeMB;

                    var flags        = KernelTraceEventParser.Keywords.Process | KernelTraceEventParser.Keywords.ImageLoad | KernelTraceEventParser.Keywords.Thread;
                    var stackCapture = KernelTraceEventParser.Keywords.Profile | KernelTraceEventParser.Keywords.ContextSwitch;
                    userEventSession.EnableKernelProvider(flags, stackCapture);

                    foreach (var userProviderInfo in providers.OfType <UserProviderInfo>())
                    {
                        userEventSession.EnableProvider(userProviderInfo.ProviderGuid, userProviderInfo.Level, userProviderInfo.Keywords);
                    }

                    action.Invoke();
                }
            }

            TraceEventSession.MergeInPlace(userFullFileName, Console.Out);
            WriteInfoLine($"ETW Tracing Session saved to \"{userFullFileName}\"");
            collectOutputFilesCallback(userFullFileName);

            var assemblyModel = GetAssemblyModel(assemblyFileName, userFullFileName, runId, performanceTestMessages);
            var xmlFileName   = Path.Combine(outputDirectory, $"{name}.xml");

            new AssemblyModelCollection {
                assemblyModel
            }.Serialize(xmlFileName);
            WriteInfoLine($"Performance results saved to \"{xmlFileName}\"");
            collectOutputFilesCallback(xmlFileName);

            var mdFileName = Path.Combine(outputDirectory, $"{name}.md");
            var dt         = assemblyModel.GetStatistics();
            var mdTable    = MarkdownHelper.GenerateMarkdownTable(dt);

            MarkdownHelper.Write(mdFileName, mdTable);
            WriteInfoLine($"Markdown file saved to \"{mdFileName}\"");
            collectOutputFilesCallback(mdFileName);
            Console.WriteLine(MarkdownHelper.ToTrimmedTable(mdTable));

            var csvFileName = Path.Combine(outputDirectory, $"{name}.csv");

            dt.WriteToCSV(csvFileName);
            WriteInfoLine($"Statistics written to \"{csvFileName}\"");
            collectOutputFilesCallback(csvFileName);
        }
        public static void Run()
        {
            var monitoringTimeSec = 10;

            if (Environment.OSVersion.Version.Major * 10 + Environment.OSVersion.Version.Minor < 62)
            {
                Out.WriteLine("This demo only works on Win8 / Win 2012 an above)");
                return;
            }

            Out.WriteLine("******************** KernelAndClrMonitor DEMO (Win 8) ********************");
            Out.WriteLine("Printing both Kernel and CLR (user mode) events simultaneously");
            Out.WriteLine("The monitor will run for a maximum of {0} seconds", monitoringTimeSec);
            Out.WriteLine("Press Ctrl-C to stop monitoring early.");
            Out.WriteLine();
            Out.WriteLine("Start a .NET program to see some events!");
            Out.WriteLine();
            if (TraceEventSession.IsElevated() != true)
            {
                Out.WriteLine("Must be elevated (Admin) to run this program.");
                Debugger.Break();
                return;
            }

            TraceEventSession session = null;

            // Set up Ctrl-C to stop both user mode and kernel mode sessions
            Console.CancelKeyPress += (object sender, ConsoleCancelEventArgs cancelArgs) =>
            {
                if (session != null)
                {
                    session.Dispose();
                }
                cancelArgs.Cancel = true;
            };

            // Set up a timer to stop processing after monitoringTimeSec
            var timer = new Timer(delegate(object state)
            {
                Out.WriteLine("Stopped Monitoring after {0} sec", monitoringTimeSec);
                if (session != null)
                {
                    session.Dispose();
                }
            }, null, monitoringTimeSec * 1000, Timeout.Infinite);

            // Create the new session to receive the events.
            // Because we are on Win 8 this single session can handle both kernel and non-kernel providers.
            using (session = new TraceEventSession("MonitorKernelAndClrEventsSession"))
            {
                // Enable the events we care about for the kernel
                // For this instant the session will buffer any incoming events.
                // Enabling kernel events must be done before anything else.
                // This will fail on Win7.
                Out.WriteLine("Enabling Image load, Process and Thread events.");
                session.EnableKernelProvider(
                    KernelTraceEventParser.Keywords.ImageLoad |
                    KernelTraceEventParser.Keywords.Process |
                    KernelTraceEventParser.Keywords.Thread);

                // Subscribe the events of interest.   In this case we just print all events.
                session.Source.Kernel.All += Print;

                Out.WriteLine("Enabling CLR GC and Exception events.");
                // Enable the events we care about for the CLR (in the user session).
                // unlike the kernel session, you can call EnableProvider on other things too.
                // For this instant the ;session will buffer any incoming events.
                session.EnableProvider(
                    ClrTraceEventParser.ProviderGuid,
                    TraceEventLevel.Informational,
                    (ulong)(ClrTraceEventParser.Keywords.GC | ClrTraceEventParser.Keywords.Exception));

                session.Source.Clr.All += Print;
#if DEBUG
                // in debug builds it is useful to see any unhandled events because they could be bugs.
                session.Source.UnhandledEvents += Print;
#endif
                // process events until Ctrl-C is pressed or timeout expires
                Out.WriteLine("Waiting for Events.");
                session.Source.Process();
            }

            timer.Dispose();    // Turn off the timer.
        }
Esempio n. 29
0
        private int StartListen()
        {
            // This is the name of the event source.
            var providerName = textBox1.Text;

            //Debug.Assert(providerName == MyEventSource.Log.Name);
            // Given just the name of the eventSource you can get the GUID for the evenSource by calling this API.
            // From a ETW perspective, the GUID is the 'true name' of the EventSource.
            //var providerGuid = TraceEventSession.GetEventSourceGuidFromName(providerName);
            //Debug.Assert(providerGuid == MyEventSource.Log.Guid);

            // Today you have to be Admin to turn on ETW events (anyone can write ETW events).
            if (!(TraceEventSession.IsElevated() ?? false))
            {
                Console.WriteLine("To turn on ETW events you need to be Administrator, please run from an Admin process.");
                return(-1);
            }

            // As mentioned below, sessions can outlive the process that created them.  Thus you need a way of
            // naming the session so that you can 'reconnect' to it from another process.   This is what the name
            // is for.  It can be anything, but it should be descriptive and unique.   If you expect mulitple versions
            // of your program to run simultaneously, you need to generate unique names (e.g. add a process ID suffix)
            Console.WriteLine("Creating a 'My Session' session");
            var sessionName = "My Session";

            using (var session = new TraceEventSession(sessionName, null))  // the null second parameter means 'real time session'
            {
                // Note that sessions create a OS object (a session) that lives beyond the lifetime of the process
                // that created it (like Filles), thus you have to be more careful about always cleaning them up.
                // An importanty way you can do this is to set the 'StopOnDispose' property which will cause the session to
                // stop (and thus the OS object will die) when the TraceEventSession dies.   Because we used a 'using'
                // statement, this means that any exception in the code below will clean up the OS object.
                session.StopOnDispose = true;

                // By default, if you hit Ctrl-C your .NET objects may not be disposed, so force it to.  It is OK if dispose is called twice.
                Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { session.Dispose(); };

                // prepare to read from the session, connect the ETWTraceEventSource to the session
                using (var source = new ETWTraceEventSource(sessionName, TraceEventSourceType.Session))
                {
                    // To demonstrate non-trivial event manipuation, we calculate the time delta between 'MyFirstEvent and 'MySecondEvent'
                    // These variables are used in this calculation
                    int    lastMyEventID   = int.MinValue;  // an illegal value to start with.
                    double lastMyEventMSec = 0;

                    // Hook up the parser that knows about EventSources
                    var parser = new DynamicTraceEventParser(source);
                    parser.All += delegate(TraceEvent data)
                    {
                        Console.WriteLine("GOT EVENT: " + data.ToString());

                        //if (data.ProviderGuid == providerGuid)  // We don't actually need this since we only turned one one provider.
                        //{
                        // Note that this is the inefficient way of parsing events (there are string comparisions on the
                        // event Name and every payload value), however it is fine for events that occur less than 100 times
                        // a second.   For more volumous events, you should consider making a parser for you eventSource
                        // (covered in another demo).  This makes your code fare less 'reflection-like' where you have lots
                        // of strings (e.g. "MyFirstEvent", "MyId" ...) which is better even ignoring the performance benefit.
                        if (data.EventName == "MyFirstEvent")
                        {
                            // On First Events, simply remember the ID and time of the event
                            lastMyEventID   = (int)data.PayloadByName("MyId");
                            lastMyEventMSec = data.TimeStampRelativeMSec;
                        }
                        else if (data.EventName == "MySecondEvent")
                        {
                            // On Second Events, if the ID matches, compute the delta and display it.
                            if (lastMyEventID == (int)data.PayloadByName("MyId"))
                            {
                                Console.WriteLine("   > Time Delta from first Event = {0:f3} MSec", data.TimeStampRelativeMSec - lastMyEventMSec);
                            }
                        }
                        else if (data.EventName == "Stop")
                        {
                            // Stop processing after we we see the 'Stop' event
                            //source.DisposeClose();
                        }
                        //}
                    };

                    // Enable my provider, you can call many of these on the same session to get other events.
                    session.EnableProvider(providerName, TraceEventLevel.Always);

                    // Start another thread that Causes MyEventSource to create some events
                    // Normally this code as well as the EventSource itself would be in a different process.


                    Console.WriteLine("Staring Listing for events");
                    // go into a loop processing events can calling the callbacks.  Because this is live data (not from a file)
                    // processing never completes by itself, but only because someone called 'source.Close()'.
                    source.Process();
                    Console.WriteLine();
                    Console.WriteLine("Stopping the collection of events.");
                }
            }
            return(0);
        }