Esempio n. 1
0
        public static Process LaunchGame(string workingDir, string exePath, string arguments, IDictionary <string, string> envVars)
        {
            Process process;

            var userName = Environment.UserName;

            var pExplicitAccess = new PInvoke.EXPLICIT_ACCESS();

            PInvoke.BuildExplicitAccessWithName(
                ref pExplicitAccess,
                userName,
                PInvoke.STANDARD_RIGHTS_ALL | PInvoke.SPECIFIC_RIGHTS_ALL & ~PInvoke.PROCESS_VM_WRITE,
                PInvoke.GRANT_ACCESS,
                0);

            if (PInvoke.SetEntriesInAcl(1, ref pExplicitAccess, IntPtr.Zero, out var newAcl) != 0)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            var secDesc = new PInvoke.SECURITY_DESCRIPTOR();

            if (!PInvoke.InitializeSecurityDescriptor(out secDesc, PInvoke.SECURITY_DESCRIPTOR_REVISION))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            if (!PInvoke.SetSecurityDescriptorDacl(ref secDesc, true, newAcl, false))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            var psecDesc = Marshal.AllocHGlobal(Marshal.SizeOf <PInvoke.SECURITY_DESCRIPTOR>());

            Marshal.StructureToPtr <PInvoke.SECURITY_DESCRIPTOR>(secDesc, psecDesc, true);


            var lpProcessInformation = new PInvoke.PROCESS_INFORMATION();
            var lpEnvironment        = IntPtr.Zero;

            try
            {
                if (envVars.Count > 0)
                {
                    string envstr = string.Join("\0", envVars.Select(entry => entry.Key + "=" + entry.Value));

                    lpEnvironment = Marshal.StringToHGlobalAnsi(envstr);
                }

                var lpProcessAttributes = new PInvoke.SECURITY_ATTRIBUTES
                {
                    nLength = Marshal.SizeOf <PInvoke.SECURITY_ATTRIBUTES>(),
                    lpSecurityDescriptor = psecDesc,
                    bInheritHandle       = false
                };

                var lpStartupInfo = new PInvoke.STARTUPINFO
                {
                    cb = Marshal.SizeOf <PInvoke.STARTUPINFO>()
                };

                if (!PInvoke.CreateProcess(
                        null,
                        exePath + " " + arguments,
                        ref lpProcessAttributes,
                        IntPtr.Zero,
                        false,
                        PInvoke.CREATE_SUSPENDED,
                        IntPtr.Zero,
                        workingDir,
                        ref lpStartupInfo,
                        out lpProcessInformation))
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }

                DisableSeDebug(lpProcessInformation.hProcess);

                process = new ExistingProcess(lpProcessInformation.hProcess);
                PInvoke.ResumeThread(lpProcessInformation.hThread);

                process.WaitForInputIdle();

                if (PInvoke.GetSecurityInfo(
                        PInvoke.GetCurrentProcess(),
                        PInvoke.SE_OBJECT_TYPE.SE_KERNEL_OBJECT,
                        PInvoke.SECURITY_INFORMATION.DACL_SECURITY_INFORMATION,
                        IntPtr.Zero, IntPtr.Zero,
                        out var pACL,
                        IntPtr.Zero, IntPtr.Zero) != 0)
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }

                if (PInvoke.SetSecurityInfo(
                        lpProcessInformation.hProcess,
                        PInvoke.SE_OBJECT_TYPE.SE_KERNEL_OBJECT,
                        PInvoke.SECURITY_INFORMATION.DACL_SECURITY_INFORMATION | PInvoke.SECURITY_INFORMATION.UNPROTECTED_DACL_SECURITY_INFORMATION,
                        IntPtr.Zero, IntPtr.Zero, pACL, IntPtr.Zero) != 0)
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }
            }
            finally
            {
                Marshal.FreeHGlobal(psecDesc);

                if (!IntPtr.Equals(lpEnvironment, IntPtr.Zero))
                {
                    Marshal.FreeHGlobal(lpEnvironment);
                }

                PInvoke.CloseHandle(lpProcessInformation.hThread);
            }

            return(process);
        }
        public static Process LaunchGame(string workingDir, string exePath, string arguments, IDictionary <string, string> envVars, DpiAwareness dpiAwareness, Action <Process> beforeResume)
        {
            Process process = null;

            var userName = Environment.UserName;

            var pExplicitAccess = new PInvoke.EXPLICIT_ACCESS();

            PInvoke.BuildExplicitAccessWithName(
                ref pExplicitAccess,
                userName,
                PInvoke.STANDARD_RIGHTS_ALL | PInvoke.SPECIFIC_RIGHTS_ALL & ~PInvoke.PROCESS_VM_WRITE,
                PInvoke.GRANT_ACCESS,
                0);

            if (PInvoke.SetEntriesInAcl(1, ref pExplicitAccess, IntPtr.Zero, out var newAcl) != 0)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            var secDesc = new PInvoke.SECURITY_DESCRIPTOR();

            if (!PInvoke.InitializeSecurityDescriptor(out secDesc, PInvoke.SECURITY_DESCRIPTOR_REVISION))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            if (!PInvoke.SetSecurityDescriptorDacl(ref secDesc, true, newAcl, false))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            var psecDesc = Marshal.AllocHGlobal(Marshal.SizeOf <PInvoke.SECURITY_DESCRIPTOR>());

            Marshal.StructureToPtr <PInvoke.SECURITY_DESCRIPTOR>(secDesc, psecDesc, true);


            var lpProcessInformation = new PInvoke.PROCESS_INFORMATION();
            var lpEnvironment        = IntPtr.Zero;

            try
            {
                if (envVars.Count > 0)
                {
                    string envstr = string.Join("\0", envVars.Select(entry => entry.Key + "=" + entry.Value));

                    lpEnvironment = Marshal.StringToHGlobalAnsi(envstr);
                }

                var lpProcessAttributes = new PInvoke.SECURITY_ATTRIBUTES
                {
                    nLength = Marshal.SizeOf <PInvoke.SECURITY_ATTRIBUTES>(),
                    lpSecurityDescriptor = psecDesc,
                    bInheritHandle       = false
                };

                var lpStartupInfo = new PInvoke.STARTUPINFO
                {
                    cb = Marshal.SizeOf <PInvoke.STARTUPINFO>()
                };

                var compatLayerPrev = Environment.GetEnvironmentVariable("__COMPAT_LAYER");

                var compat = "RunAsInvoker ";
                compat += dpiAwareness switch
                {
                    DpiAwareness.Aware => "HighDPIAware",
                    DpiAwareness.Unaware => "DPIUnaware",
                    _ => throw new ArgumentOutOfRangeException()
                };
                Environment.SetEnvironmentVariable("__COMPAT_LAYER", compat);

                if (!PInvoke.CreateProcess(
                        null,
                        $"\"{exePath}\" {arguments}",
                        ref lpProcessAttributes,
                        IntPtr.Zero,
                        false,
                        PInvoke.CREATE_SUSPENDED,
                        IntPtr.Zero,
                        workingDir,
                        ref lpStartupInfo,
                        out lpProcessInformation))
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }

                Environment.SetEnvironmentVariable("__COMPAT_LAYER", compatLayerPrev);

                DisableSeDebug(lpProcessInformation.hProcess);

                process = new ExistingProcess(lpProcessInformation.hProcess);

                beforeResume?.Invoke(process);

                PInvoke.ResumeThread(lpProcessInformation.hThread);

                // Ensure that the game main window is prepared
                try
                {
                    do
                    {
                        process.WaitForInputIdle();

                        Thread.Sleep(100);
                    } while (IntPtr.Zero == TryFindGameWindow(process));
                }
                catch (InvalidOperationException)
                {
                    throw new GameExitedException();
                }

                if (PInvoke.GetSecurityInfo(
                        PInvoke.GetCurrentProcess(),
                        PInvoke.SE_OBJECT_TYPE.SE_KERNEL_OBJECT,
                        PInvoke.SECURITY_INFORMATION.DACL_SECURITY_INFORMATION,
                        IntPtr.Zero, IntPtr.Zero,
                        out var pACL,
                        IntPtr.Zero, IntPtr.Zero) != 0)
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }

                if (PInvoke.SetSecurityInfo(
                        lpProcessInformation.hProcess,
                        PInvoke.SE_OBJECT_TYPE.SE_KERNEL_OBJECT,
                        PInvoke.SECURITY_INFORMATION.DACL_SECURITY_INFORMATION |
                        PInvoke.SECURITY_INFORMATION.UNPROTECTED_DACL_SECURITY_INFORMATION,
                        IntPtr.Zero, IntPtr.Zero, pACL, IntPtr.Zero) != 0)
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex, "[NativeAclFix] Uncaught error during initialization, trying to kill process");

                try
                {
                    process?.Kill();
                }
                catch (Exception killEx)
                {
                    Log.Error(killEx, "[NativeAclFix] Could not kill process");
                }

                throw;
            }
            finally
            {
                Marshal.FreeHGlobal(psecDesc);

                if (!IntPtr.Equals(lpEnvironment, IntPtr.Zero))
                {
                    Marshal.FreeHGlobal(lpEnvironment);
                }

                PInvoke.CloseHandle(lpProcessInformation.hThread);
            }

            return(process);
        }