基于@NtFreX的解决方案,我创建了另一个解决方案,它:
从当前标识中获取令牌(似乎有效且需要较少的代码), - 抱歉,这并不总是有效的
- 处理从已经取消提升的进程运行的情况(因为在这种情况下,
CreateProcessWithTokenW
将失败,并显示错误代码1314-“客户端未持有所需特权”)和
- 返回进程ID,以便调用代码可以等待它等。
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.Principal;
public static class UnelevatedProcessStarter
{
public static int Start(string cmdArgs)
{
var shell = NativeMethods.GetShellWindow();
if (shell == IntPtr.Zero)
{
throw new Exception("Could not find shell window");
}
uint shellProcessId;
NativeMethods.GetWindowThreadProcessId(shell, out shellProcessId);
var hShellProcess = NativeMethods.OpenProcess(0x00000400 , false, (int)shellProcessId);
IntPtr hShellToken;
if (!NativeMethods.OpenProcessToken(hShellProcess, 2 , out hShellToken))
{
throw new Win32Exception();
}
uint tokenAccess = 8 | 1 | 2 | 0x80 | 0x100 ;
var securityAttributes = new SecurityAttributes();
IntPtr hToken;
if (!NativeMethods.DuplicateTokenEx(
hShellToken,
tokenAccess,
ref securityAttributes,
2 ,
1 ,
out hToken))
{
throw new Win32Exception();
}
var si = new Startupinfo();
si.cb = Marshal.SizeOf(si);
ProcessInformation processInfo;
if (!NativeMethods.CreateProcessWithTokenW(
hToken,
0x00000002 ,
null,
cmdArgs,
0x00000010 ,
IntPtr.Zero,
null,
ref si,
out processInfo))
{
if (Marshal.GetLastWin32Error() == 1314)
{
SecurityAttributes processSecurityAttributes = new SecurityAttributes();
SecurityAttributes threadSecurityAttributes = new SecurityAttributes();
if (!NativeMethods.CreateProcessAsUser(
IntPtr.Zero,
null,
cmdArgs,
ref processSecurityAttributes,
ref threadSecurityAttributes,
true,
0x00000010 ,
IntPtr.Zero,
null,
ref si,
out processInfo))
{
throw new Win32Exception();
}
}
else
{
throw new Win32Exception();
}
}
return processInfo.dwProcessId;
}
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);
[DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
public static extern bool CreateProcessAsUser(
IntPtr hToken,
string lpApplicationName,
string lpCommandLine,
ref SecurityAttributes lpProcessAttributes,
ref SecurityAttributes lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
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;
}
}