Example #1
0
        static void Main(string[] args)
        {
            var filter = new EventFilter(Filter
                                         .EventIdIs(3018)
                                         .Or(Filter.EventIdIs(3020)));

            filter.OnEvent += (IEventRecord r) => {
                var      query             = r.GetUnicodeString("QueryName");
                var      result            = r.GetUnicodeString("QueryResults");
                TimeSpan t                 = DateTime.UtcNow - new DateTime(1970, 1, 1);
                int      secondsSinceEpoch = (int)t.TotalSeconds;
                Console.WriteLine($"{secondsSinceEpoch} | {r.Id} | {query} | {result}");
            };

            var provider = new Provider("Microsoft-Windows-DNS-Client");

            provider.AddFilter(filter);

            var trace = new UserTrace();

            trace.Enable(provider);

            Console.CancelKeyPress += (sender, eventArg) =>
            {
                if (trace != null)
                {
                    trace.Stop();
                }
            };
            trace.Start();
        }
Example #2
0
        static void Main(string[] args)
        {
            var trace           = new UserTrace();
            var processProvider = new Provider("Microsoft-Windows-Kernel-Process");

            processProvider.All = 0x40; // Enable the WINEVENT_KEYWORD_IMAGE flag.
            var filter = new EventFilter(Filter.EventIdIs(5));

            filter.OnEvent += (record) =>
            {
                var dllName = record.GetUnicodeString("ImageName", "<UNKNOWN>");
                if (dllName.ToLower().EndsWith("mscoree.dll"))
                {
                    var pid         = record.GetUInt32("ProcessID", 0);
                    var processName = string.Empty;

                    try { processName = System.Diagnostics.Process.GetProcessById((int)pid).ProcessName; }
                    catch (Exception) { }
                    Console.WriteLine($"{processName} (PID: {pid}) loaded .NET runtime ({dllName})");
                }
            };

            processProvider.AddFilter(filter);
            trace.Enable(processProvider);

            Console.CancelKeyPress += (sender, eventArg) =>
            {
                if (trace != null)
                {
                    trace.Stop();
                }
            };

            trace.Start();
        }
        public static void Start()
        {
            var trace    = new UserTrace("UserTrace007_StackTrace");
            var provider = new Provider("Microsoft-Windows-Kernel-Process");

            provider.Any         = 0x10; // WINEVENT_KEYWORD_PROCESS
            provider.TraceFlags |= TraceFlags.IncludeStackTrace;

            var processFilter = new EventFilter(Filter.EventIdIs(1));  // ProcessStart

            processFilter.OnEvent += (record) =>
            {
                var pid       = record.GetUInt32("ProcessID");
                var imageName = record.GetUnicodeString("ImageName");
                Console.WriteLine($"{record.TaskName} pid={pid} ImageName={imageName}\nCallStack:");
                foreach (var returnAddress in record.GetStackTrace())
                {
                    Console.WriteLine($"    0x{returnAddress.ToUInt64():x}");
                }
            };
            provider.AddFilter(processFilter);

            trace.Enable(provider);
            trace.Start();
        }
        public static void Start()
        {
            var trace = new UserTrace("UserTrace006_Rundown");

            // Rundown events are not true real-time tracing events. Instead they describe the state of the system.

            // Usually these are just extra events in the provider. For example, Microsoft-Windows-Kernel-Process
            // has ProcessRundown events as well as ProcessStart events.
            var provider = new Provider("Microsoft-Windows-Kernel-Process");

            provider.Any = 0x10;  // WINEVENT_KEYWORD_PROCESS
                                  // ...but the rundown events often cannot be enabled by keyword alone.
                                  // The trace needs to be sent EVENT_CONTROL_CODE_CAPTURE_STATE.
                                  // This is what EnableRundownEvents() does.
            provider.EnableRundownEvents();

            // real-time process start events
            var processFilter = new EventFilter(Filter.EventIdIs(1));  // ProcessStart

            processFilter.OnEvent += ProcessEventHandler;
            provider.AddFilter(processFilter);

            // process rundown events - i.e. running processes
            var processRundownFilter = new EventFilter(Filter.EventIdIs(15));  // ProcessRundown

            processRundownFilter.OnEvent += ProcessEventHandler;
            provider.AddFilter(processRundownFilter);

            trace.Enable(provider);
            trace.Start();
        }
        static void Main(string[] args)
        {
            var trace = new UserTrace();

            // The name of the PowerShell provider that gives us with detailed
            // method execution logging is "Microsoft-Windows-PowerShell".
            //
            // If you want to explore all the events in this provider,
            // you'll need to use Message Analyzer to load the trace and explore
            // the events.
            //
            // Download: https://www.microsoft.com/en-us/download/details.aspx?id=44226
            var powershellProvider = new Provider("Microsoft-Windows-PowerShell");

            var powershellFilter = new EventFilter(
                Filter.EventIdIs(7937)
                .And(UnicodeString.Contains("Payload", "Started")));

            powershellFilter.OnEvent += OnEvent;

            // The "Any" and "All" flags can be sussed out using Microsoft Message Analyzer.
            powershellProvider.Any = 0x20;
            powershellProvider.AddFilter(powershellFilter);

            trace.Enable(powershellProvider);

            // This is a blocking call. Ctrl-C to stop.
            trace.Start();
        }
Example #6
0
            public void it_should_read_provider_id()
            {
                var provider = new Provider(PowerShellEvent.ProviderId);

                provider.OnEvent += e =>
                {
                    Assert.AreEqual(PowerShellEvent.ProviderId, e.ProviderId);
                };

                trace.Enable(provider);
                proxy.PushEvent(PowerShellEvent.CreateRecord(
                                    String.Empty, String.Empty, String.Empty));
            }
Example #7
0
        static void Main(string[] args)
        {
            // UserTrace instances should be used for any non-kernel traces that are defined
            // by components or programs in Windows. They can optionally take a name -- if none
            // is provided, a random GUID is assigned as the name.
            var trace = new UserTrace("Silly Gooby");

            // A trace can have any number of providers, which are identified by GUID. These
            // GUIDs are defined by the components that emit events, and their GUIDs can
            // usually be found with various ETW tools (like wevutil).
            var powershellProvider = new Provider(Guid.Parse("{A0C1853B-5C40-4B15-8766-3CF1C58F985A}"));

            // UserTrace providers typically have any and all flags, whose meanings are
            // unique to the specific providers that are being invoked. To understand these
            // flags, you'll need to look to the ETW event producer.
            powershellProvider.Any = Provider.AllBitsSet;

            // In user_trace_001.cs, we manually filter events by checking the information
            // in our callback functions. In this example, we're going to use a provider
            // filter to do this for us.

            // We instantiate an EventFilter first. An EventFilter is created with a predicate --
            // literally just a function that does some check on an EventRecord and returns a boolean
            // (true when the even should be passed on to callbacks, false otherwise).

            // EventFilters are more than just convenient -- Lobster provides combinators for
            // expressing simple but powerful filters that actually execute in the underlying C++
            // krabs library. This means that events can be filtered before ever running in the
            // CLR (saving us a ton of cost in spinning up objects on event firing).

            // The combinators cannot express everything a filter must do, so for complicated
            // filters, it's recommended to write the filters in a managed C++/CLI project and
            // use those to keep the perf benefits. The filters that Lobster provides are on
            // the Filter object (and can be combined with &&, ||, !)
            var filter = new EventFilter(Filter.EventIdIs(7937));

            // EventFilters have attached callbacks, just like a regular provider.
            filter.OnEvent += (EventRecord record) =>
            {
                var schema = new Schema(record);
                System.Diagnostics.Debug.Assert(schema.Id == 7937);
                Console.WriteLine("Event 7937 received");
            };

            // EventFilters are attached to providers. Events that are attached to the filter
            // will only be called when the filter allows the event through. Any events attached
            // to the provider directly will be called for all events that are fired by the ETW
            // producer.
            powershellProvider.AddFilter(filter);
            trace.Enable(powershellProvider);
            trace.Start();
        }
        public void given_invalid_property_name_parse_should_throw()
        {
            var provider = new Provider(WinINetEvent.ProviderId);

            provider.OnEvent +=
                e => e.GetAnsiString("InvalidName");

            trace.Enable(provider);
            proxy.PushEvent(WinINetEvent.CreateRecord(
                                String.Empty, String.Empty, 0u));
        }
Example #9
0
        static void Main(string[] args)
        {
            // UserTrace instances should be used for any non-kernel traces that are defined
            // by components or programs in Windows.
            var trace = new UserTrace();

            // A trace can have any number of providers, which are identified by GUID. These
            // GUIDs are defined by the components that emit events, and their GUIDs can
            // usually be found with various ETW tools (like wevutil).
            var powershellProvider = new Provider(Guid.Parse("{A0C1853B-5C40-4B15-8766-3CF1C58F985A}"));

            // UserTrace providers typically have any and all flags, whose meanings are
            // unique to the specific providers that are being invoked. To understand these
            // flags, you'll need to look to the ETW event producer.
            powershellProvider.Any = Provider.AllBitsSet;

            // Providers should be wired up to functions that are called when
            // events from that provider are fired.
            powershellProvider.OnEvent += (EventRecord record) =>
            {
                // Once an event is received, if we want krabs to help us analyze it, we need
                // to snap in a schema to ask it for information.
                var schema = new Schema(record);

                // We then have the ability to ask a few questions of the event.
                Console.WriteLine("Event " + schema.Id + " (" + schema.Name + ") received.");

                if (schema.Id == 7937)
                {
                    // The event we're interested in has a field that contains a bunch of
                    // info about what it's doing. We can snap in a parser to help us get
                    // the property information out.
                    var parser = new Parser(schema);

                    // We need to call the specific method to parse the type we expect.
                    // If we don't want to deal with the possibility of failure, we can
                    // provide a default if parsing fails.
                    var context = parser.ParseWStringWithDefault("ContextInfo", "None.");
                    Console.WriteLine("Context: " + context);
                }
            };

            // The UserTrace needs to know about the provider that we've set up.
            trace.Enable(powershellProvider);

            // Begin listening for events. This call blocks, so if you want to do other things
            // while this runs, you'll need to call this on another thread.
            trace.Start();
        }
Example #10
0
 internal void EnableProvider(PSEtwUserProvider provider)
 {
     lock (_sync)
     {
         if (!_isRunning)
         {
             provider.EnsureDefaultHandlerSetup(DefaultEventRecordHandler);
             _trace.Enable(provider.Provider);
         }
         else
         {
             throw new TraceAlreadyRunningException();
         }
     }
 }
Example #11
0
        public void it_should_raise_OnEvent_for_raw_provider_on_user_trace()
        {
            var called = false;

            var trace = new UserTrace();
            var proxy = new Proxy(trace);

            var provider = new RawProvider(PowerShellEvent.ProviderId);

            provider.OnEvent += e => { called = true; };

            trace.Enable(provider);
            proxy.PushEvent(PowerShellEvent.CreateRecord("user data", "context info", "payload"));

            Assert.IsTrue(called, "proxy call raised on event");
        }
Example #12
0
        static void Main(string[] args)
        {
            var count = 0;
            var cts   = new CancellationTokenSource();
            var trace = new UserTrace("MY AWESOME TEST THING");
            //var provider = new RawProvider(EventSource.GetGuid(typeof(TestEventSource)));

            var provider = new Provider(Guid.Parse("{A0C1853B-5C40-4B15-8766-3CF1C58F985A}"));

            // Only pull in method invocations
            var powershellFilter = new EventFilter(Filter.EventIdIs(7937)
                                                   .And(UnicodeString.Contains("Payload", "Started")));

            powershellFilter.OnEvent += e =>
            {
                Console.WriteLine($"{e.ProviderName} - {e.Id}: {count++}");
            };

            provider.AddFilter(powershellFilter);

            Console.CancelKeyPress += (s, e) =>
            {
                cts.Cancel();
                trace.Stop();
            };

            trace.Enable(provider);

            var statsLoop = Task.Run(() => PrintStats(trace, cts.Token));

            Task.Run(() => trace.Start())
            .ContinueWith(t => Console.WriteLine($"Task ended with status {t.Status}"));

            Console.WriteLine("Enter to restart trace");
            Console.ReadKey();

            Task.Run(() => trace.Start())
            .ContinueWith(t => Console.WriteLine($"Task ended with status {t.Status}"));

            Console.WriteLine("Ctrl+C to quit");
            statsLoop.Wait();

            Console.WriteLine("Done");
        }
Example #13
0
        public void when_requesting_mismatched_type_in_debug_it_should_throw()
        {
            var data = 200u;
            var prop = WinINetEvent.Status;

            var provider = new Provider(WinINetEvent.ProviderId);

            provider.OnEvent +=
                e => Assert.AreEqual(data, e.GetInt32(prop));

            trace.Enable(provider);
            proxy.PushEvent(WinINetEvent.CreateRecord(
                                String.Empty, String.Empty, data));
        }
Example #14
0
        public static void Start()
        {
            // UserTrace instances should be used for any non-kernel traces that are defined
            // by components or programs in Windows.
            var trace = new UserTrace();

            // A trace can have any number of providers, which are identified by GUID. These
            // GUIDs are defined by the components that emit events, and their GUIDs can
            // usually be found with various ETW tools (like wevutil).
            var powershellProvider = new Provider(Guid.Parse("{A0C1853B-5C40-4B15-8766-3CF1C58F985A}"));

            // UserTrace providers typically have any and all flags, whose meanings are
            // unique to the specific providers that are being invoked. To understand these
            // flags, you'll need to look to the ETW event producer.
            powershellProvider.Any = Provider.AllBitsSet;

            // Providers should be wired up to functions that are called when
            // events from that provider are fired.
            powershellProvider.OnEvent += (record) =>
            {
                // Records have general properties that are applicable to every ETW
                // record regardless of schema. They give us general information.
                Console.WriteLine("Event " + record.Id + " (" + record.Name + ") received.");

                if (record.Id == 7937)
                {
                    // We need to call the specific method to parse the type we expect.
                    // If we don't want to deal with the possibility of failure, we can
                    // provide a default if parsing fails.
                    var context = record.GetUnicodeString("ContextInfo", "None.");
                    Console.WriteLine("Context: " + context);
                }
            };

            // The UserTrace needs to know about the provider that we've set up.
            trace.Enable(powershellProvider);

            // Begin listening for events. This call blocks, so if you want to do other things
            // while this runs, you'll need to call this on another thread.
            trace.Start();
        }
        static void Main(string[] args)
        {
            var filter = new EventFilter(Filter
                                         .EventIdIs(3018)
                                         .Or(Filter.EventIdIs(3020)));

            filter.OnEvent += (IEventRecord r) => {
                var query  = r.GetUnicodeString("QueryName");
                var result = r.GetUnicodeString("QueryResults");
                Console.WriteLine($"DNS query ({r.Id}): {query} - {result}");
            };

            var provider = new Provider("Microsoft-Windows-DNS-Client");

            provider.AddFilter(filter);

            var trace = new UserTrace();

            trace.Enable(provider);
            trace.Start();
        }
Example #16
0
        public static void Start()
        {
            // While Adminstrator is sufficent to view the Security EventLog,
            // SYSTEM is required for the Microsoft-Windows-Security-Auditing provider.
            if (!WindowsIdentity.GetCurrent().IsSystem)
            {
                Console.WriteLine("Microsoft-Windows-Security-Auditing can only be traced by SYSTEM");
                return;
            }

            // Further, only one trace session is allowed for this provider.
            // This session is created by the OS and is called 'EventLog-Security'.
            // We can't Stop this session, but we can Open a handle to it.
            var trace    = new UserTrace("EventLog-Security");
            var provider = new Provider("Microsoft-Windows-Security-Auditing");

            // We also can't modify the flags of the trace session.
            // This will silently fail.
            provider.Any = Provider.AllBitsSet;

            // But we can receive events - but only those configured by the audit policy.
            // e.g. to enable event 4703 run -> auditpol /set /subcategory:"Token Right Adjusted Events"
            provider.OnEvent += (record) =>
            {
                Console.WriteLine($"Event {record.Id}({record.Name}) received.");

                if (record.Id == 4703) // "A user right was adjusted."
                {
                    var enabledPrivilegeList  = record.GetUnicodeString("EnabledPrivilegeList", "");
                    var disabledPrivilegeList = record.GetUnicodeString("DisabledPrivilegeList", "");

                    Console.WriteLine($"\tEnabledPrivilegeList={enabledPrivilegeList}");
                    Console.WriteLine($"\tDisabledPrivilegeList={disabledPrivilegeList}");
                }
            };

            trace.Enable(provider);

            trace.Start();
        }
Example #17
0
        static void Main(string[] args)
        {
            var filter = new EventFilter(
                Filter.EventIdIs(5)
                //.Or(Filter.EventIdIs(6))
                );

            // Microsoft-Windows-RPC EventID 5 - Client RPC call started
            // EventID 6 - Server RPC call started.

            filter.OnEvent += (IEventRecord r) =>
            {
                var endpoint = r.GetUnicodeString("Endpoint");
                var opNum    = r.GetUInt32("ProcNum");
                var protocol = r.GetUInt32("Protocol");
                Console.WriteLine($"RPC Event {r.Id}");
                Console.WriteLine($"Endpoint: {endpoint}");
                Console.WriteLine($"Protocol {protocol,0:X}");
                Console.WriteLine($"OpNum: {opNum}");
            };

            var provider = new Provider("Microsoft-Windows-RPC");

            provider.AddFilter(filter);

            var trace = new UserTrace();

            trace.Enable(provider);

            Console.CancelKeyPress += (sender, eventArg) =>
            {
                if (trace != null)
                {
                    trace.Stop();
                }
            };

            trace.Start();
        }
Example #18
0
        public static void Start()
        {
            // UserTrace instances should be used for any non-kernel traces that are defined
            // by components or programs in Windows. They can optionally take a name -- if none
            // is provided, a random GUID is assigned as the name.
            var trace = new UserTrace();

            // A trace can have any number of providers, which are identified by GUID. These
            // GUIDs are defined by the components that emit events, and their GUIDs can
            // usually be found with various ETW tools (like wevutil).
            var powershellProvider = new Provider(Guid.Parse("{A0C1853B-5C40-4B15-8766-3CF1C58F985A}"));

            // UserTrace providers typically have any and all flags, whose meanings are
            // unique to the specific providers that are being invoked. To understand these
            // flags, you'll need to look to the ETW event producer.
            powershellProvider.Any = Provider.AllBitsSet;

            // In UserTrace003.cs, we use ETW-based filtering to select a specific event ID.
            //
            // We can combine ETW-based filtering with predicate filters to filter on specific
            // event properties without impacting performance.
            var filter = new EventFilter(7937, UnicodeString.Contains("ContextInfo", "Write-Host"));

            // EventFilters have attached callbacks, just like a regular provider.
            filter.OnEvent += (record) =>
            {
                System.Diagnostics.Debug.Assert(record.Id == 7937);
                Console.WriteLine(record.GetUnicodeString("ContextInfo"));
            };

            // EventFilters are attached to providers. Events that are attached to the filter
            // will only be called when the filter allows the event through. Any events attached
            // to the provider directly will be called for all events that are fired by the ETW
            // producer.
            powershellProvider.AddFilter(filter);
            trace.Enable(powershellProvider);
            trace.Start();
        }
Example #19
0
        public void schema_not_found_should_raise_onerror_on_user_trace()
        {
            var onEventCalled = false;
            var onErrorCalled = false;

            var trace = new UserTrace();
            var proxy = new Proxy(trace);

            var provider = new Provider(PowerShellEvent.ProviderId);

            provider.OnEvent += e => { onEventCalled = true; };
            provider.OnError += e => { onErrorCalled = true; };

            var record = PowerShellEvent.CreateRecord("user data", "context info", "payload");

            // munge the event so the schema can't be found
            record.Id = (ushort)1234;

            trace.Enable(provider);
            proxy.PushEvent(record);

            Assert.IsFalse(onEventCalled, "schema not found raised OnEvent");
            Assert.IsTrue(onErrorCalled, "schema not found raised OnError");
        }
        static void Main(string[] args)
        {
            bool start = false;

            Injected_Processes_IDsList.Add("0");
            Injected_Processes_IDsList.Add("0");

            Console.CancelKeyPress += Console_CancelKeyPress;

            Temp_Thread_InfoDebugMode = new DataTable();
            Temp_Thread_InfoDebugMode.Columns.Add("tid", typeof(int));
            Temp_Thread_InfoDebugMode.Columns.Add("Time_Negative");
            Temp_Thread_InfoDebugMode.Columns.Add("status");
            Temp_Thread_InfoDebugMode.Columns.Add("tid_StartAddress_x64");
            Temp_Thread_InfoDebugMode.Columns.Add("StartTime");
            Temp_Thread_InfoDebugMode.Columns.Add("Proc_Name");
            Temp_Thread_InfoDebugMode.Columns.Add("Proc_id");
            Temp_Thread_InfoDebugMode.Columns.Add("IsNewProcess");
            Temp_Thread_InfoDebugMode.Columns.Add("tid_StartAddress");

            Console.ForegroundColor = ConsoleColor.DarkGray;
            Console.WriteLine();
            Console.WriteLine("ETWMonThread 1.0 (x64 only) ");
            Console.WriteLine("Realtime Scanning/Monitoring Thread Injection for MPD (Meterpreter Payload Detection) by ETW");
            Console.ForegroundColor = ConsoleColor.Gray;
            Console.WriteLine("Published by Damon Mohammadbagher Jan 2018");

            if (args.Length == 0)
            {
                start = true;
            }
            if (args.Length == 1)
            {
                if (args[0].ToUpper() == "IPS")
                {
                    IPS_IDS = true; start = true;
                }
                else
                {
                    IPS_IDS = false; start = true;
                }
                if (args[0].ToUpper() == "SHOWALL")
                {
                    IsShowAllRecrds = true; start = true;
                }
            }

            if (args.Length >= 2)
            {
                if (args[0].ToUpper() == "IPS" && args[1].ToUpper() == "DEBUG")
                {
                    IPS_IDS = true; Is_DebugMode = true; start = true;
                }
                if (args[0].ToUpper() == "SHOWALL" && args[1].ToUpper() == "DEBUG")
                {
                    IsShowAllRecrds = true; Is_DebugMode = true; start = true;
                }
            }

            if (args.Length >= 1)
            {
                if (args[0].ToUpper() == "HELP")
                {
                    start = false;
                    Console.ForegroundColor = ConsoleColor.DarkYellow;
                    Console.WriteLine();
                    Console.WriteLine("[!] ETWMonThread , Realtime Scanning/Monitoring Thread Injection for MPD (Meterpreter Payload Detection) by ETW");
                    Console.ForegroundColor = ConsoleColor.DarkCyan;
                    Console.WriteLine("[!] Syntax 1: Realtime Scanning/Monitoring IPS Mode (Killing Meterpreter Injected Threads)");
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    Console.WriteLine("[!] Syntax 1: ETWMonThread.exe \"IPS\" [optional] \"DEBUG\"");
                    Console.WriteLine("[!] Example1: ETWMonThread.exe IPS ");
                    Console.WriteLine("[!] Example2: ETWMonThread.exe IPS DEBUG");
                    Console.WriteLine();
                    Console.ForegroundColor = ConsoleColor.DarkCyan;
                    Console.WriteLine("[!] Syntax 2: Realtime Monitoring IDS Mode");
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    Console.WriteLine("[!] Syntax 2: ETWMonThread.exe [optional] \"SHOWALL\" [optional] \"DEBUG\" ");
                    Console.WriteLine("[!] Example1: ETWMonThread.exe");
                    Console.WriteLine("[!] Example2: ETWMonThread.exe SHOWALL");
                    Console.WriteLine("[!] Example3: ETWMonThread.exe SHOWALL DEBUG");
                    Console.ForegroundColor = ConsoleColor.Gray;
                }
            }

            if (start)
            {
                Console.WriteLine();
                if (IPS_IDS)
                {
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    Console.WriteLine("[!] Realtime Scanning/Monitoring IPS Mode (warning : Killing Threads)");
                    Console.ForegroundColor = ConsoleColor.Gray;
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    Console.WriteLine("[!] Realtime Monitoring IDS Mode");
                    Console.ForegroundColor = ConsoleColor.Gray;
                }
                /// EventID 3 is for "Thread Created"
                var ETWEventsFilter = new EventFilter(Filter.EventIdIs(3));
                ETWEventsFilter.OnEvent += ETWEventsFilter_OnEvent;
                P.OnError += P_OnError;
                P.AddFilter(ETWEventsFilter);
                T.Enable(P);
                T.Start();
            }
        }
Example #21
0
        /// <summary>
        /// This function build an ETW usertrace from
        /// a configuration INI file and a selected IETWWriter
        /// </summary>
        /// <param name="config">configuration that come from an ini file</param>
        /// <param name="writer">how to writer etw</param>
        /// <returns></returns>
        public static UserTrace BuildFromConfig(IniData config, IETWWriter writer)
        {
            var providers = new Dictionary <Guid, Provider>();

            foreach (var providerConfig in config.Sections)
            {
                // try to parse filtering provider
                var providerDeclaration = providerConfig.SectionName.Split(new string[] { "://" }, StringSplitOptions.RemoveEmptyEntries);
                if (providerDeclaration.Length > 2)
                {
                    continue;
                }

                string providerName = providerDeclaration[0];

                // Try to parse provider name
                ProviderGuid providerGuid = null;
                if (!ProviderGuid.TryParse(providerName, out providerGuid))
                {
                    continue;
                }

                Forwarder forwarder = null;
                if (!Forwarder.TryBuild(providerGuid, out forwarder))
                {
                    continue;
                }

                UInt16?eventId = null;
                if (providerDeclaration.Length == 2)
                {
                    UInt16 tmp = 0;
                    if (!UInt16.TryParse(providerDeclaration[1], out tmp))
                    {
                        continue;
                    }
                    eventId = tmp;
                }

                if (!providers.ContainsKey(providerGuid.Guid))
                {
                    providers.Add(providerGuid.Guid, new Provider(providerGuid.Guid));
                }

                var provider = providers[providerGuid.Guid];

                var predicate = Filter.AnyEvent();

                if (eventId != null)
                {
                    predicate = Filter.EventIdIs(eventId.Value);
                }

                var filter = new EventFilter(predicate);
                foreach (var keyValue in providerConfig.Keys)
                {
                    forwarder.AddFilter(keyValue.KeyName, keyValue.Value);
                }

                filter.OnEvent += (IEventRecord record) =>
                {
                    try
                    {
                        forwarder.Forward(record, writer).Wait();
                    }
                    catch (System.AggregateException) { } // Some event ae not documented even for Microsoft
                };

                provider.AddFilter(filter);
            }

            if (providers.Count == 0)
            {
                throw new Exception("Unable to create a trace without provider");
            }

            UserTrace trace = new UserTrace(String.Format("Splunk-ETW-{0}", Guid.NewGuid().ToString()));

            foreach (var provider in providers.Values)
            {
                trace.Enable(provider);
            }

            return(trace);
        }
Example #22
0
        public static void Start()
        {
            var trace = new UserTrace();

            // WPP providers are basically legacy providers without a registered MOF.
            // They are intended for (internal) debugging purposes only.
            // Note - WPP software tracing has been superceded by TraceLogging.
            //
            // Instead of a manifest or MOF, a separate trace message format (TMF)
            // file is required to interpret the WPP event data.
            // https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/trace-message-format-file
            //
            // In some cases, the TMF is included in the PDB.
            // https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/tracepdb
            //
            // Otherwise, you can attempt to reconstruct the TMF by hand.
            // https://posts.specterops.io/data-source-analysis-and-dynamic-windows-re-using-wpp-and-tracelogging-e465f8b653f7
            //
            // Luckily, WPP tracing is usually added using Microsoft's convenience macros.
            // And, when you have symbols available, WPP metadata is then fairly straightfoward to extract.
            // https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/adding-wpp-software-tracing-to-a-windows-driver

            // Each WPP trace provider defines a control GUID that uniquely identifies that provider.
            // https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/control-guid
            //
            // The WPP macros generate control GUID globals named "WPP_ThisDir_CTLGUID_<name>"
            //
            // For example, this control GUID in the symbols for combase.dll
            // WPP_ThisDir_CTLGUID_OLE32 = bda92ae8-9f11-4d49-ba1d-a4c2abca692e
            var ole32WppProvider = new Provider(Guid.Parse("{bda92ae8-9f11-4d49-ba1d-a4c2abca692e}"));

            // We use the control GUID to enable WPP tracing for the provider, and to set
            // the filtering level and flags.
            //
            // In evntrace.h there are ten defined trace levels -
            // TRACE_LEVEL_NONE        0   // Tracing is not on
            // TRACE_LEVEL_CRITICAL    1   // Abnormal exit or termination
            // TRACE_LEVEL_ERROR       2   // Severe errors that need logging
            // TRACE_LEVEL_WARNING     3   // Warnings such as allocation failure
            // TRACE_LEVEL_INFORMATION 4   // Includes non-error cases(e.g.,Entry-Exit)
            // TRACE_LEVEL_VERBOSE     5   // Detailed traces from intermediate steps
            // TRACE_LEVEL_RESERVED6   6
            // TRACE_LEVEL_RESERVED7   7
            // TRACE_LEVEL_RESERVED8   8
            // TRACE_LEVEL_RESERVED9   9
            //
            // Microsoft WPP providers are known to use the reserved levels.
            // Internally, these levels have names like CHATTY, GARRULOUS and LOQUACIOUS.
            //
            // Everything at or below the configured level will be traced.
            // Technically 9 means trace everything, but the field is a UCHAR
            // so 0xFF means definitely trace everything.
            ole32WppProvider.Level = 0xFF;  // 'TRACE_LEVEL_ALL'

            // Flags is a user-defined bitmask field the developer can use to group
            // related messages.
            // Again, it is a UCHAR for WPP providers so 0xFF means trace everything.
            ole32WppProvider.Any = 0xFF;    // 'TRACE_FLAGS_ALL'

            // WPP events are also a slightly different format to the modern ETW events. In particular,
            // they include a message GUID rather than the control GUID. In order to convince krabs to
            // forward events to us, we need to register an extra 'provider' using the message GUID.
            //
            // The WPP macros generate message GUID globals named "WPP_<guid>_Traceguids"
            //
            // For example, these message GUIDs in the symbols for combase.dll
            // WPP_c0e4dd87b1523146a49921a43cd25160_Traceguids = c0e4dd87-b152-3146-a499-21a43cd25160
            // WPP_c1647dce9b833d97edb9721fff5f0606_Traceguids = c1647dce-9b83-3d97-edb9-721fff5f0606
            var messageGuid_S = new Provider(Guid.Parse("{c0e4dd87-b152-3146-a499-21a43cd25160}"));

            messageGuid_S.OnEvent += (record) =>
            {
                // krabs does not currently support TMF files for parsing WPP messages.
                // Instead you need to manually parse the UserData.
                //
                // The WPP macros generate logging staging functions named "WPP_SF_<format specifiers>"
                // In this case this message GUID is always associate with a WPP_SF_S(...) call.
                // This tells us that the event contains a single unicode string.
                var message = Marshal.PtrToStringUni(record.UserData);
                Console.WriteLine($"Id:{record.Id} WPP_SF_S({message})");
            };

            var messageGuid_ssdDsS = new Provider(Guid.Parse("{c1647dce-9b83-3d97-edb9-721fff5f0606}"));

            messageGuid_ssdDsS.OnEvent += (record) =>
            {
                // WPP_SF_ssdDsS(...)
                var userData = record.UserData;
                var string_1 = Marshal.PtrToStringAnsi(userData);
                userData += string_1.Length + 1;
                var string_2 = Marshal.PtrToStringAnsi(userData);
                userData += string_2.Length + 1;
                var int32_3 = Marshal.ReadInt32(userData);
                userData += sizeof(Int32);
                var uint32_4 = (UInt32)Marshal.ReadInt32(userData);
                userData += sizeof(UInt32);
                var string_5 = Marshal.PtrToStringAnsi(userData);
                userData += string_5.Length + 1;
                var string_6 = Marshal.PtrToStringUni(userData);
                Console.WriteLine($"Id:{record.Id} WPP_SF_ssdDsS({string_1}, {string_2}, {int32_3}, {uint32_4}, {string_5}, {string_6})");
            };

            // Side note - if you want to turn up the verbosity of your COM WPP diagnostic tracing, then enable
            // OLE32 tracing via the registry following the instruction here -
            // https://support.microsoft.com/en-us/help/926098/how-to-enable-com-and-com-diagnostic-tracing
            //
            // Alternatively call _ControlTracing (4) via combase's 18f70770-8e64-11cf-9af1-0020af6e72f4 RPC interface.

            trace.Enable(ole32WppProvider);
            trace.Enable(messageGuid_S);
            trace.Enable(messageGuid_ssdDsS);
            trace.Start();
        }
Example #23
0
        public static void Start()
        {
            var trace = new UserTrace("WPP_OLE32");

            // WPP providers are basically legacy providers without a registered MOF.
            // They are intended for (internal) debugging purposes only.
            // Note - WPP software tracing has been superceded by TraceLogging.
            //
            // Instead of a manifest or MOF, a separate trace message format (TMF)
            // file is required to interpret the WPP event data.
            // https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/trace-message-format-file
            //
            // In some cases, the TMF is included in the PDB.
            // https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/tracepdb
            //
            // Otherwise, you can attempt to reconstruct the TMF by hand.
            // https://posts.specterops.io/data-source-analysis-and-dynamic-windows-re-using-wpp-and-tracelogging-e465f8b653f7
            //
            // Luckily, WPP tracing is usually added using Microsoft's convenience macros.
            // And, when you have symbols available, WPP metadata is then fairly straightfoward to extract.
            // https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/adding-wpp-software-tracing-to-a-windows-driver

            // Each WPP trace provider defines a control GUID that uniquely identifies that provider.
            // https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/control-guid
            //
            // The WPP macros generate control GUID globals named "WPP_ThisDir_CTLGUID_<name>"
            //
            // For example, this control GUID is in the symbols for combase.dll
            // WPP_ThisDir_CTLGUID_OLE32 = bda92ae8-9f11-4d49-ba1d-a4c2abca692e
            var ole32WppProvider = new Provider(Guid.Parse("{bda92ae8-9f11-4d49-ba1d-a4c2abca692e}"));

            // In evntrace.h there are ten defined trace levels -
            // TRACE_LEVEL_NONE        0   // Tracing is not on
            // TRACE_LEVEL_CRITICAL    1   // Abnormal exit or termination
            // TRACE_LEVEL_ERROR       2   // Severe errors that need logging
            // TRACE_LEVEL_WARNING     3   // Warnings such as allocation failure
            // TRACE_LEVEL_INFORMATION 4   // Includes non-error cases(e.g.,Entry-Exit)
            // TRACE_LEVEL_VERBOSE     5   // Detailed traces from intermediate steps
            // TRACE_LEVEL_RESERVED6   6
            // TRACE_LEVEL_RESERVED7   7
            // TRACE_LEVEL_RESERVED8   8
            // TRACE_LEVEL_RESERVED9   9
            //
            // Microsoft WPP providers are known to use the reserved levels.
            // Internally, these levels have names like CHATTY, GARRULOUS and LOQUACIOUS.
            //
            // Everything at or below the configured level will be traced.
            // Technically 9 means trace everything, but the field is a UCHAR
            // so 0xFF means definitely trace everything.
            ole32WppProvider.Level = 0xFF;  // 'TRACE_LEVEL_ALL'

            // Flags is a user-defined bitmask field the developer can use to group
            // related messages.
            // Again, it is a UCHAR for WPP providers so 0xFF means trace everything.
            ole32WppProvider.Any = 0xFF;  // 'TRACE_FLAGS_ALL'

            // We need to enable this provider in order for krabs to correctly enable the OLE32 WPP events.
            trace.Enable(ole32WppProvider);

            // But we can't add any callbacks directly to krabs WPP providers though. Without the TMF
            // information, krabs cannot determine which provider the event belongs to.
            //
            // WPP providers, like MOF providers, return the message GUID in the ProviderId field.
            // So firstly krabs checks if the message GUID matches a provider GUID.
            // If you know the message GUIDs then you can create individual dummy providers for those.
            //
            // Secondly krabs queries TDH to see if it knows the provider GUID for the message GUID.
            // https://docs.microsoft.com/en-us/windows/win32/etw/retrieving-event-data-using-tdh
            // This works for registered MOF providers - but not for WPP providers. In this case, TDH returns
            // an all zero GUID - so we can create a dummy provider for that and add our callbacks there instead.
            // If you subscribe to multiple WPP providers, the events from *all* of them will be delivered to this dummy provider.
            var allWppDummyProvider = new Provider(Guid.Empty);

            allWppDummyProvider.OnEvent += (record) =>
            {
                // Here be dragons.
                //
                // krabs does not currently support TMF files for parsing WPP messages.
                // Instead you need to manually parse the UserData.
                //
                // The WPP macros generate message GUID globals named "WPP_<guid>_Traceguids"
                // They also generate logging staging functions named "WPP_SF_<format specifiers>"
                //
                // There seems to be a one-to-one mapping between message GUIDs and staging functions.
                // WPP events are a slightly different format to the modern ETW events. In particular,
                // they include this message GUID rather than the provider's control GUID.
                //
                // So message GUIDs would be a good candidate for filtering...
                // ... but my experience is that they may change between builds.
                // So I've subscribed to the zero GUID instead.
                //
                // Event ids seem more stable, but they are only unique per message GUID.
                //
                // In this case, combase.dll only has two logging staging functions.
                // WPP_SF_S(...) - which tells us that the event contains a single unicode string.
                // WPP_SF_ssdDsS(...) - which tells us that there are 3 ansi strings, a unicode string and dword.
                //
                // So we can brute force the format...

                var message  = $"Message:{record.ProviderId} Id:{record.Id} ";
                var userData = record.UserData;
                var string_1 = Marshal.PtrToStringAnsi(record.UserData);
                if (string_1.Length != 1)  // definitely an ansi string...
                {
                    // WPP_SF_ssdDsS(...)
                    userData += string_1.Length + 1;
                    var string_2 = Marshal.PtrToStringAnsi(userData);
                    userData += string_2.Length + 1;
                    var int32_3 = Marshal.ReadInt32(userData);
                    userData += sizeof(Int32);
                    var uint32_4 = (UInt32)Marshal.ReadInt32(userData);
                    userData += sizeof(UInt32);
                    var string_5 = Marshal.PtrToStringAnsi(userData);
                    userData += string_5.Length + 1;
                    var string_6 = Marshal.PtrToStringUni(userData);
                    message += $"WPP_SF_ssdDsS({string_1}, {string_2}, {int32_3}, {uint32_4}, {string_5}, {string_6})";
                }
                else // probably a unicode string... (but possibly a single character ansi string)
                {
                    // WPP_SF_S(...)
                    string_1 = Marshal.PtrToStringUni(record.UserData);
                    message += $"WPP_SF_S({string_1})";
                }

                // In this example we only print messages that contain COM class ids.
                if (message.Contains(" clsid"))
                {
                    Console.WriteLine(message);
                }
            };
            trace.Enable(allWppDummyProvider);

            // Side note - if you want to turn up the verbosity of your COM WPP diagnostic tracing, then enable
            // OLE32 tracing via the registry following the instruction here -
            // https://support.microsoft.com/en-us/help/926098/how-to-enable-com-and-com-diagnostic-tracing
            //
            // Alternatively call _ControlTracing (4) via combase's 18f70770-8e64-11cf-9af1-0020af6e72f4 RPC interface.

            trace.Start();
        }