예제 #1
0
 public static extern bool DetourCreateProcessWithDllExA(
     string lpApplicationName,
     string lpCommandLine,
     IntPtr lpProcessAttributes,
     IntPtr lpThreadAttributes,
     bool bInheritHandles,
     uint dwCreationFlags,
     IntPtr lpEnvironment,
     string lpCurrentDirectory,
     ref NativeMethods.StartupInfo lpStartupInfo,
     out NativeMethods.ProcessInformation lpProcessInformation,
     string lpDllName,
     IntPtr pfCreateProcessA);
예제 #2
0
 public static extern bool DetourCreateProcessWithDllsExW(
     [MarshalAs(UnmanagedType.LPWStr)] string lpApplicationName,
     string lpCommandLine,
     IntPtr lpProcessAttributes,
     IntPtr lpThreadAttributes,
     bool bInheritHandles,
     uint dwCreationFlags,
     IntPtr lpEnvironment,
     string lpCurrentDirectory,
     ref NativeMethods.StartupInfo lpStartupInfo,
     out NativeMethods.ProcessInformation lpProcessInformation,
     uint nDlls,
     IntPtr rlpDlls,
     IntPtr pfCreateProcessW);
예제 #3
0
        public static uint CreateProcess(string userName, string domain, string password, string application, string workingDirectory, bool showMinimized = false)
        {
            TraceFactory.Logger.Debug("Creating user process for {0}/{1} - {2}".FormatWith(domain, userName, application));
            try
            {
                // Default flags for the impersonation startup.
                NativeMethods.LogonFlags    logonFlags    = NativeMethods.LogonFlags.LogonWithProfile;
                NativeMethods.CreationFlags creationFlags = 0;
                IntPtr environment      = IntPtr.Zero;
                string currentDirectory = workingDirectory;
                string commandLine      = application;

                NativeMethods.StartupInfo startupInfo = new NativeMethods.StartupInfo();
                startupInfo.Cb = Marshal.SizeOf(typeof(NativeMethods.StartupInfo));

                if (showMinimized)
                {
                    startupInfo.Flags      = (uint)NativeMethods.StartupInfoFlags.StartfUseShowWindow;
                    startupInfo.ShowWindow = (ushort)NativeMethods.StartupInfoFlags.SWMinimize;
                }

                NativeMethods.ProcessInfo processInfo = new NativeMethods.ProcessInfo();

                TraceFactory.Logger.Debug("Calling CreateProcessWithLogonW...");
                bool created = NativeMethods.CreateProcessWithLogonW(userName, domain, password, logonFlags, null,
                                                                     commandLine, creationFlags, environment, currentDirectory, ref startupInfo, out processInfo);

                if (created)
                {
                    TraceFactory.Logger.Debug("Process ({0}) successfully created, closing handles".FormatWith(processInfo.ProcessId));
                    NativeMethods.CloseHandle(processInfo.ProcessPtr);
                    NativeMethods.CloseHandle(processInfo.ThreadPtr);
                }
                else
                {
                    int error = Marshal.GetLastWin32Error();
                    var msg   = "Unable to create Process, error code {3}: {0}, {1}, {2}".FormatWith(userName, domain, password, error);
                    TraceFactory.Logger.Debug(msg);
                    throw new Exception(msg);
                }

                return(processInfo.ProcessId);
            }
            catch (Exception ex)
            {
                // TODO: Need to do something here...
                TraceFactory.Logger.Fatal("Failed to create process", ex);
                throw;
            }
        }
예제 #4
0
 public static bool DetourCreateProcessWithDllsExW(
     string lpApplicationName,
     string lpCommandLine,
     IntPtr lpProcessAttributes,
     IntPtr lpThreadAttributes,
     bool bInheritHandles,
     uint dwCreationFlags,
     IntPtr lpEnvironment,
     string lpCurrentDirectory,
     ref NativeMethods.StartupInfo lpStartupInfo,
     out NativeMethods.ProcessInformation lpProcessInformation,
     uint nDlls,
     IntPtr rlpDlls,
     IntPtr pfCreateProcessW)
 {
     if (Is64Bit)
     {
         return(NativeApi64.DetourCreateProcessWithDllsExW(lpApplicationName,
                                                           lpCommandLine,
                                                           lpProcessAttributes,
                                                           lpThreadAttributes,
                                                           bInheritHandles,
                                                           dwCreationFlags,
                                                           lpEnvironment,
                                                           lpCurrentDirectory,
                                                           ref lpStartupInfo,
                                                           out lpProcessInformation,
                                                           nDlls,
                                                           rlpDlls,
                                                           pfCreateProcessW));
     }
     else
     {
         return(NativeApi32.DetourCreateProcessWithDllsExW(lpApplicationName,
                                                           lpCommandLine,
                                                           lpProcessAttributes,
                                                           lpThreadAttributes,
                                                           bInheritHandles,
                                                           dwCreationFlags,
                                                           lpEnvironment,
                                                           lpCurrentDirectory,
                                                           ref lpStartupInfo,
                                                           out lpProcessInformation,
                                                           nDlls,
                                                           rlpDlls,
                                                           pfCreateProcessW));
     }
 }
예제 #5
0
        private static NativeMethods.ProcessInformation DoCreateProcessWithLogon()
        {
            var cmdLine = new StringBuilder(1024);

            // cmdLine.Append(@"powershell.exe -NoExit -Command ""dir env:"""); // Look at the environment
            cmdLine.Append(@"cmd.exe /k set"); // Look at the environment

            var createProcessFlags = NativeMethods.CreateProcessFlags.CREATE_NEW_CONSOLE |
                                     NativeMethods.CreateProcessFlags.CREATE_UNICODE_ENVIRONMENT;

            /*
             *  NativeMethods.CreateProcessFlags.CREATE_NO_WINDOW |
             *  NativeMethods.CreateProcessFlags.CREATE_BREAKAWAY_FROM_JOB |
             *  NativeMethods.CreateProcessFlags.CREATE_NEW_CONSOLE;
             */

            var startupInfo = new NativeMethods.StartupInfo();

            NativeMethods.ProcessInformation pi;

            if (NativeMethods.CreateProcessWithLogon(userName, ".", password,
                                                     NativeMethods.LogonFlags.LOGON_WITH_PROFILE,
                                                     null,
                                                     cmdLine,
                                                     createProcessFlags,
                                                     IntPtr.Zero,
                                                     workingDir,
                                                     startupInfo,
                                                     out pi))
            {
                Console.WriteLine("create-process-with-logon cmd: '{0}' pid: '{1}'", cmdLine.ToString(), pi.dwProcessId);
                return(pi);
            }
            else
            {
                throw new Win32Exception();
            }
        }
        public bool Start()
        {
            processInfo = new NativeMethods.ProcessInformation();
            var startInfo = new NativeMethods.StartupInfo();
            var success   = false;

            SafeFileHandle hToken, hReadOut, hWriteOut, hReadErr, hWriteErr, hReadIn, hWriteIn;

            var securityAttributes = new NativeMethods.SecurityAttributes();

            securityAttributes.bInheritHandle = true;

            success = NativeMethods.CreatePipe(out hReadOut, out hWriteOut, securityAttributes, 0);
            if (!success)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            success = NativeMethods.CreatePipe(out hReadErr, out hWriteErr, securityAttributes, 0);
            if (!success)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            success = NativeMethods.CreatePipe(out hReadIn, out hWriteIn, securityAttributes, 0);
            if (!success)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            success = NativeMethods.SetHandleInformation(hReadOut, NativeMethods.Constants.HANDLE_FLAG_INHERIT, 0);
            if (!success)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            // Logon user
            success = NativeMethods.LogonUser(
                runSpec.Credentials.UserName,
                runSpec.Credentials.Domain,
                runSpec.Credentials.Password,
                NativeMethods.LogonType.LOGON32_LOGON_BATCH,
                NativeMethods.LogonProvider.LOGON32_PROVIDER_DEFAULT,
                out hToken
                );
            if (!success)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            NativeMethods.LUID privilegeLuid;
            if (!NativeMethods.LookupPrivilegeValue(null, "SeImpersonatePrivilege", out privilegeLuid))
            {
                int lastError = Marshal.GetLastWin32Error();
                throw new Win32Exception(lastError, "Error calling LookupPrivilegeValue: " + lastError);
            }

            var tokenPrivileges = new NativeMethods.TOKEN_PRIVILEGES();

            tokenPrivileges.PrivilegeCount = 1;
            tokenPrivileges.Attributes     = 1;
            tokenPrivileges.Luid           = privilegeLuid;
            if (!NativeMethods.AdjustTokenPrivileges(hToken, false,
                                                     ref tokenPrivileges,
                                                     1024, IntPtr.Zero, IntPtr.Zero))
            {
                var lastError = Marshal.GetLastWin32Error();
                throw new Win32Exception(lastError, "Error calling AdjustTokenPrivileges: " + lastError);
            }

            IntPtr unmanagedEnv;

            if (!NativeMethods.CreateEnvironmentBlock(out unmanagedEnv, hToken.DangerousGetHandle(), false))
            {
                int lastError = Marshal.GetLastWin32Error();
                throw new Win32Exception(lastError, "Error calling CreateEnvironmentBlock: " + lastError);
            }

            // Create process
            startInfo.cb         = Marshal.SizeOf(startInfo);
            startInfo.dwFlags    = NativeMethods.Constants.STARTF_USESTDHANDLES;
            startInfo.hStdOutput = hWriteOut;
            startInfo.hStdError  = hWriteErr;
            startInfo.hStdInput  = hReadIn;

            success = NativeMethods.CreateProcessWithTokenW(
                hToken,
                NativeMethods.LogonFlags.WithProfile,
                null,
                CommandLine(),
                NativeMethods.CreateProcessFlags.CREATE_UNICODE_ENVIRONMENT,
                unmanagedEnv,
                null,
                ref startInfo,
                out processInfo
                );

            if (!success)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            NativeMethods.DestroyEnvironmentBlock(unmanagedEnv);
            NativeMethods.CloseHandle(processInfo.hThread);

            Handle = processInfo.hProcess;

            startInfo.hStdOutput.Close();
            startInfo.hStdError.Close();
            startInfo.hStdInput.Close();
            StandardOutput = new StreamReader(new FileStream(hReadOut, FileAccess.Read), Console.OutputEncoding);
            StandardError  = new StreamReader(new FileStream(hReadErr, FileAccess.Read), Console.OutputEncoding);
            StandardInput  = new StreamWriter(new FileStream(hWriteIn, FileAccess.Write), Console.InputEncoding)
            {
                AutoFlush = true
            };

            WaitForExitAsync();

            return(success);
        }
예제 #7
0
        private void ServiceMain()
        {
            const string testFile = @"C:\tmp\test-it.ps1";

            File.Delete(testFile);
            File.WriteAllText(testFile, testPowershellScript);

            var permissionManager = new DesktopPermissionManager(userName);

            var    startupInfo       = new NativeMethods.StartupInfo();
            string lpApplicationName = @"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe";
            var    cmdLine           = new StringBuilder(1024);

            cmdLine.AppendFormat(@" -InputFormat None -NoLogo -NoProfile -NonInteractive -File {0}", testFile);

            permissionManager.AddDesktopPermission();

            using (var jobObject = new JobObject("StartProcessServiceJobObject"))
            {
                jobObject.KillProcessesOnJobClose = true;

                while (!ct.IsCancellationRequested)
                {
                    try
                    {
                        log.Debug("Executing command: '{0}'", cmdLine);

                        // Now create the process as the user
                        NativeMethods.ProcessInformation pi;

                        var saProcessAttributes = new NativeMethods.SecurityAttributes();
                        var saThreadAttributes  = new NativeMethods.SecurityAttributes();

                        var createProcessFlags =
                            NativeMethods.CreateProcessFlags.CREATE_NO_WINDOW |
                            NativeMethods.CreateProcessFlags.CREATE_UNICODE_ENVIRONMENT;

                        IntPtr primaryToken = Utils.LogonAndGetPrimaryToken(userName, password);

                        if (NativeMethods.CreateProcessAsUser(primaryToken,
                                                              lpApplicationName,
                                                              cmdLine,
                                                              saProcessAttributes,
                                                              saThreadAttributes,
                                                              false,
                                                              createProcessFlags,
                                                              IntPtr.Zero,
                                                              workingDir,
                                                              startupInfo,
                                                              out pi))
                        {
                            log.Debug("created process: '{0}' pid: '{1}'", cmdLine.ToString(), pi.dwProcessId);
                            jobObject.AddProcess(pi.hProcess);
                            log.Debug("job object has '{0}' processes in it.", jobObject.GetJobProcesses().Count());
                            NativeMethods.CloseHandle(pi.hProcess);
                            NativeMethods.CloseHandle(pi.hThread);
                        }
                        else
                        {
                            int err = Marshal.GetLastWin32Error();
                            log.Error("Error '{0}' creating process.", err);
                        }
                    }
                    catch (Exception ex)
                    {
                        log.ErrorException("Exception creating process.", ex);
                    }
                    finally
                    {
                        Thread.Sleep(TimeSpan.FromSeconds(10));
                    }
                }
            }

            permissionManager.RemoveDesktopPermission();
        }
예제 #8
0
        public MatchResult Run()
        {
            const string robotBattleExePath = @"C:\Program Files (x86)\Robot Battle\winrob32.exe";

            var loadListFile = Path.GetTempPath() + "loadlist.ll";
            var scoreLogFile = Path.GetTempPath() + "score.log";
            var statsLogFile = Path.GetTempPath() + "stats.log";

            using (var writer = XmlWriter.Create(loadListFile, new XmlWriterSettings { Indent = true })) {
                matchBuilder.ToXml().WriteTo(writer);
            }


            if (hideWindow) {
                var desktopName = "RobotBattle.Automation." + Guid.NewGuid();
                var desktopPtr = NativeMethods.CreateDesktop(desktopName, null, null, 0, 0xff, IntPtr.Zero);
                try {
                    if (desktopPtr == IntPtr.Zero)
                        throw new InvalidOperationException("Failed to create the secondary desktop");

                    // set startup parameters.
                    var si = new NativeMethods.StartupInfo();
                    si.cb = Marshal.SizeOf(si);
                    si.lpDesktop = desktopName;

                    var pi = new NativeMethods.ProcessInformation();

                    var path = string.Format(
                        "\"{0}\" \"{1}\" /t /lf \"{2}\" /slf \"{3}\" /slg 1 /lo 1 /slo 1",
                        robotBattleExePath,
                        loadListFile,
                        scoreLogFile,
                        statsLogFile
                        );

                    if (
                        !NativeMethods.CreateProcess(null, path, IntPtr.Zero, IntPtr.Zero, true,
                                                     0x00000020, /*NORMAL_PRIORITY_CLASS*/
                                                     IntPtr.Zero, null, ref si, ref pi))
                        throw new InvalidOperationException("Failed to launch the Robot Battle process");

                    Process.GetProcessById(pi.dwProcessId)
                        .WaitForExit();
                } finally {
                    NativeMethods.CloseDesktop(desktopPtr);
                }
            } else {
                Process.Start(new ProcessStartInfo {
                    FileName = robotBattleExePath,
                    Arguments = string.Format(
                        "\"{1}\" /t /lf \"{2}\" /slf \"{3}\" /slg 1 /lo 1 /slo 1",
                        robotBattleExePath,
                        loadListFile,
                        scoreLogFile,
                        statsLogFile
                                  )
                }).WaitForExit();
            }

            return MatchResult.FromFiles(loadListFile, scoreLogFile, statsLogFile);
        }
예제 #9
0
        private static NativeMethods.ProcessInformation DoCreateProcessAsUser()
        {
            var startupInfo = new NativeMethods.StartupInfo();

            string lpApplicationName = @"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe";
            // string lpApplicationName = @"C:\Windows\System32\cmd.exe";

            var cmdLine = new StringBuilder(1024);

            // NB: /k will keep window open. Try running powershell from the window and you won't see any modules available. Weird.
            // This works, however: runas /user:test_user /noprofile /savecred "powershell -NoExit"
            // cmdLine.Append(@" /k set");

            // Other commands to try:
            // cmdLine.Append(@" -NoExit -Command ""dir env:"""); // Look at the environment
            // cmdLine.Append(@"powershell.exe -InputFormat None -NoLogo -NoProfile -NonInteractive -Command ""echo 'START'; Start-Sleep -s 15; echo 'STOP'""");
            // cmdLine.Append(@"cmd /c ping 127.0.0.1 -n 15 -w 1000"); // Useful for "sleep"
            cmdLine.Append(@" -InputFormat None -NoLogo -NoProfile -NonInteractive -Command ""Add-Content -Path C:\tmp\test.txt -Value FOO""");

            // Create structs
            var saProcessAttributes = new NativeMethods.SecurityAttributes();
            var saThreadAttributes  = new NativeMethods.SecurityAttributes();

            // Now create the process as the user
            NativeMethods.ProcessInformation pi;

            var createProcessFlags =
                NativeMethods.CreateProcessFlags.CREATE_NO_WINDOW |
                NativeMethods.CreateProcessFlags.CREATE_UNICODE_ENVIRONMENT;
            // NativeMethods.CreateProcessFlags.CREATE_NEW_CONSOLE; // Remove this to have a hidden window. Having this here allows you to see output

            IntPtr primaryToken = Utils.LogonAndGetPrimaryToken(userName, password);

            /*
             * uint sessionId = 1;
             * if (NativeMethods.SetTokenInformation(primaryToken,
             *  NativeMethods.TokenInformationClass.TokenSessionId,
             *  ref sessionId, (uint)Marshal.SizeOf(sessionId)))
             * {
             */
            if (NativeMethods.CreateProcessWithToken(primaryToken, NativeMethods.LogonFlags.LOGON_WITH_PROFILE,
                                                     lpApplicationName, cmdLine.ToString(), createProcessFlags, IntPtr.Zero, workingDir,
                                                     startupInfo, out pi))
            {
                Console.WriteLine("create-process-with-token cmd: '{0}' pid: '{1}'", cmdLine.ToString(), pi.dwProcessId);
                return(pi);
            }
            else
            {
                throw new Win32Exception();
            }

            /*
             * }
             * else
             * {
             *  throw new Win32Exception();
             * }
             */

            /*
             * var profileInfo = new NativeMethods.ProfileInfo();
             * profileInfo.lpUserName = userName;
             *
             * if (NativeMethods.LoadUserProfile(primaryToken, profileInfo))
             * {
             *  IntPtr envBlock = IntPtr.Zero;
             *  if (NativeMethods.CreateEnvironmentBlock(out envBlock, primaryToken, false))
             *  {
             *      // http://odetocode.com/blogs/scott/archive/2004/10/29/createprocessasuser.aspx
             *      if (NativeMethods.CreateProcessAsUser(
             *          primaryToken,
             *          lpApplicationName,
             *          cmdLine, // lpCommandLine
             *          saProcessAttributes,
             *          saThreadAttributes,
             *          false, // bInheritHandles
             *          createProcessFlags,
             *          envBlock,
             *          workingDir,
             *          startupInfo,
             *          out pi))
             *      {
             *          Console.WriteLine("create-process-as-user cmd: '{0}' pid: '{1}'", cmdLine.ToString(), pi.dwProcessId);
             *          return pi;
             *      }
             *      else
             *      {
             *          throw new Win32Exception();
             *      }
             *  }
             *  else
             *  {
             *      throw new Win32Exception();
             *  }
             * }
             * else
             * {
             *  throw new Win32Exception();
             * }
             */
        }
예제 #10
0
        public bool StartAsUser(IntPtr userToken)
        {
            _processInformation = new NativeMethods.ProcessInformation();
            NativeMethods.StartupInfo startupInfo = new NativeMethods.StartupInfo();
            switch (StartInfo.WindowStyle)
            {
            case ProcessWindowStyle.Hidden:
                startupInfo.wShowWindow = SW_HIDE;
                break;

            case ProcessWindowStyle.Maximized:
                startupInfo.wShowWindow = SW_MAXIMIZE;
                break;

            case ProcessWindowStyle.Minimized:
                startupInfo.wShowWindow = SW_MINIMIZE;
                break;

            case ProcessWindowStyle.Normal:
                startupInfo.wShowWindow = SW_SHOW;
                break;
            }
            CreateStandardPipe(out _stdinReadHandle, out _stdinWriteHandle, STD_INPUT_HANDLE, true, StartInfo.RedirectStandardInput);
            CreateStandardPipe(out _stdoutReadHandle, out _stdoutWriteHandle, STD_OUTPUT_HANDLE, false, StartInfo.RedirectStandardOutput);
            CreateStandardPipe(out _stderrReadHandle, out _stderrWriteHandle, STD_ERROR_HANDLE, false, StartInfo.RedirectStandardError);

            startupInfo.dwFlags    = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
            startupInfo.hStdInput  = _stdinReadHandle;
            startupInfo.hStdOutput = _stdoutWriteHandle;
            startupInfo.hStdError  = _stderrWriteHandle;

            NativeMethods.CreateProcessFlags createFlags = NativeMethods.CreateProcessFlags.CreateNewConsole | NativeMethods.CreateProcessFlags.CreateNewProcessGroup | NativeMethods.CreateProcessFlags.CreateDefaultErrorMode;
            if (StartInfo.CreateNoWindow)
            {
                startupInfo.wShowWindow = SW_HIDE;
                createFlags            |= NativeMethods.CreateProcessFlags.CreateNoWindow;
            }

            // Create process as user, fail hard if this is unsuccessful so it can be caught in EncoderUnit
            if (!NativeMethods.CreateProcessAsUserW(userToken, null, GetCommandLine(), IntPtr.Zero, IntPtr.Zero, true, createFlags, IntPtr.Zero, null, startupInfo, out _processInformation))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "ImpersonationProcess: CreateProcessAsUser failed");
            }

            if (_processInformation.hThread != (IntPtr)(-1))
            {
                ImpersonationHelper.SafeCloseHandle(ref _processInformation.hThread);
                _processInformation.hThread = IntPtr.Zero;
            }

            if (StartInfo.RedirectStandardInput)
            {
                ImpersonationHelper.SafeCloseHandle(ref _stdinReadHandle);
                StreamWriter standardInput = new StreamWriter(new FileStream(_stdinWriteHandle, FileAccess.Write, 4096), Console.Out.Encoding)
                {
                    AutoFlush = true
                };
                SetField("standardInput", standardInput);
            }

            if (StartInfo.RedirectStandardOutput)
            {
                ImpersonationHelper.SafeCloseHandle(ref _stdoutWriteHandle);
                StreamReader standardOutput = new StreamReader(new FileStream(_stdoutReadHandle, FileAccess.Read, 4096), StartInfo.StandardOutputEncoding);
                SetField("standardOutput", standardOutput);
            }

            if (StartInfo.RedirectStandardError)
            {
                ImpersonationHelper.SafeCloseHandle(ref _stderrWriteHandle);
                StreamReader standardError = new StreamReader(new FileStream(_stderrReadHandle, FileAccess.Read, 4096), StartInfo.StandardErrorEncoding);
                SetField("standardError", standardError);
            }

            // Workaround to get process handle as non-public SafeProcessHandle
            Assembly processAssembly   = typeof(System.Diagnostics.Process).Assembly;
            Type     processManager    = processAssembly.GetType("System.Diagnostics.ProcessManager");
            object   safeProcessHandle = processManager.InvokeMember("OpenProcess", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, this, new object[] { _processInformation.dwProcessId, 0x100000, false });

            InvokeMethod("SetProcessHandle", safeProcessHandle);
            InvokeMethod("SetProcessId", _processInformation.dwProcessId);

            return(true);
        }
예제 #11
0
        public MatchResult Run()
        {
            const string robotBattleExePath = @"C:\Program Files (x86)\Robot Battle\winrob32.exe";

            var loadListFile = Path.GetTempPath() + "loadlist.ll";
            var scoreLogFile = Path.GetTempPath() + "score.log";
            var statsLogFile = Path.GetTempPath() + "stats.log";

            using (var writer = XmlWriter.Create(loadListFile, new XmlWriterSettings {
                Indent = true
            })) {
                matchBuilder.ToXml().WriteTo(writer);
            }


            if (hideWindow)
            {
                var desktopName = "RobotBattle.Automation." + Guid.NewGuid();
                var desktopPtr  = NativeMethods.CreateDesktop(desktopName, null, null, 0, 0xff, IntPtr.Zero);
                try {
                    if (desktopPtr == IntPtr.Zero)
                    {
                        throw new InvalidOperationException("Failed to create the secondary desktop");
                    }

                    // set startup parameters.
                    var si = new NativeMethods.StartupInfo();
                    si.cb        = Marshal.SizeOf(si);
                    si.lpDesktop = desktopName;

                    var pi = new NativeMethods.ProcessInformation();

                    var path = string.Format(
                        "\"{0}\" \"{1}\" /t /lf \"{2}\" /slf \"{3}\" /slg 1 /lo 1 /slo 1",
                        robotBattleExePath,
                        loadListFile,
                        scoreLogFile,
                        statsLogFile
                        );

                    if (
                        !NativeMethods.CreateProcess(null, path, IntPtr.Zero, IntPtr.Zero, true,
                                                     0x00000020, /*NORMAL_PRIORITY_CLASS*/
                                                     IntPtr.Zero, null, ref si, ref pi))
                    {
                        throw new InvalidOperationException("Failed to launch the Robot Battle process");
                    }

                    Process.GetProcessById(pi.dwProcessId)
                    .WaitForExit();
                } finally {
                    NativeMethods.CloseDesktop(desktopPtr);
                }
            }
            else
            {
                Process.Start(new ProcessStartInfo {
                    FileName  = robotBattleExePath,
                    Arguments = string.Format(
                        "\"{1}\" /t /lf \"{2}\" /slf \"{3}\" /slg 1 /lo 1 /slo 1",
                        robotBattleExePath,
                        loadListFile,
                        scoreLogFile,
                        statsLogFile
                        )
                }).WaitForExit();
            }

            return(MatchResult.FromFiles(loadListFile, scoreLogFile, statsLogFile));
        }