c# 当前进程是管理员权限,然后以普通权限启动另一个进程

这2篇文章提到的使用explorer来启动,貌似他们没有考虑到explorer也是管理员权限的情况?

https://blog.lindexi.com/post/dotnet-判断程序当前使用管理员运行降低权使用普通权限运行.html
https://blog.walterlv.com/post/start-process-with-lowered-uac-privileges.html

实际测试可用的:
来自 https://stackoverflow.com/questions/1173630/how-do-you-de-elevate-privileges-for-a-child-process/49997055#49997055

 public static class UnelevatedProcessStarter
 {
    public static void Start(string cmdArgs)
    {
       // 1. Get the shell
       var shell = NativeMethods.GetShellWindow();
       if (shell == IntPtr.Zero)
       {
          throw new Exception("Could not find shell window");
       }

       // 2. Copy the access token of the process
       NativeMethods.GetWindowThreadProcessId(shell, out uint shellProcessId);
       var hShellProcess = NativeMethods.OpenProcess(0x00000400 /* QueryInformation */, false, (int)shellProcessId);
       if (!NativeMethods.OpenProcessToken(hShellProcess, 2 /* TOKEN_DUPLICATE */, out IntPtr hShellToken))
       {
          throw new Win32Exception();
       }

       // 3. Duplicate the acess token
       uint tokenAccess = 8 /*TOKEN_QUERY*/ | 1 /*TOKEN_ASSIGN_PRIMARY*/ | 2 /*TOKEN_DUPLICATE*/ | 0x80 /*TOKEN_ADJUST_DEFAULT*/ | 0x100 /*TOKEN_ADJUST_SESSIONID*/;
       var securityAttributes = new SecurityAttributes();

       NativeMethods.DuplicateTokenEx(
           hShellToken,
           tokenAccess,
           ref securityAttributes,
           2 /* SecurityImpersonation */,
           1 /* TokenPrimary */,
           out IntPtr hToken);

       // 4. Create a new process with the copied token
       var si = new Startupinfo();
       si.cb = Marshal.SizeOf(si);

       if (!NativeMethods.CreateProcessWithTokenW(
           hToken,
           0x00000002 /* LogonNetcredentialsOnly */,
           null,
           cmdArgs,
           0x00000010 /* CreateNewConsole */,
           IntPtr.Zero,
           null,
           ref si,
           out ProcessInformation _))
       {
          throw new Win32Exception();
       }
    }

    public class NativeMethods
    {
       [DllImport("user32.dll")]
       public static extern IntPtr GetShellWindow();
       [DllImport("user32.dll", SetLastError = true)]
       public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
       [DllImport("kernel32.dll", SetLastError = true)]
       public static extern IntPtr OpenProcess(int processAccess, bool bInheritHandle, int processId);
       [DllImport("advapi32.dll", SetLastError = true)]
       [return: MarshalAs(UnmanagedType.Bool)]
       public static extern bool OpenProcessToken(IntPtr processHandle, UInt32 desiredAccess, out IntPtr tokenHandle);
       [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
       public static extern bool DuplicateTokenEx(IntPtr hExistingToken, uint dwDesiredAccess,
           ref SecurityAttributes lpTokenAttributes,
           int impersonationLevel,
           int tokenType,
           out IntPtr phNewToken);
       [DllImport("advapi32", SetLastError = true, CharSet = CharSet.Unicode)]
       public static extern bool CreateProcessWithTokenW(
           IntPtr hToken, int dwLogonFlags,
           string lpApplicationName, string lpCommandLine,
           int dwCreationFlags, IntPtr lpEnvironment,
           string lpCurrentDirectory, [In] ref Startupinfo lpStartupInfo, out ProcessInformation lpProcessInformation);
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct ProcessInformation
    {
       public IntPtr hProcess;
       public IntPtr hThread;
       public int dwProcessId;
       public int dwThreadId;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SecurityAttributes
    {
       public int nLength;
       public IntPtr lpSecurityDescriptor;
       public int bInheritHandle;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct Startupinfo
    {
       public Int32 cb;
       public string lpReserved;
       public string lpDesktop;
       public string lpTitle;
       public Int32 dwX;
       public Int32 dwY;
       public Int32 dwXSize;
       public Int32 dwYSize;
       public Int32 dwXCountChars;
       public Int32 dwYCountChars;
       public Int32 dwFillAttribute;
       public Int32 dwFlags;
       public Int16 wShowWindow;
       public Int16 cbReserved2;
       public IntPtr lpReserved2;
       public IntPtr hStdInput;
       public IntPtr hStdOutput;
       public IntPtr hStdError;
    }
 }
posted @ 2025-05-08 18:06  trykle  阅读(30)  评论(0)    收藏  举报