网上有很多CreateProcessAsUser的方法。但是这个受限于执行者的权限,如果执行者是RunAsAdministrator,则会出现ERROR 1314(权限不足)的问题。所以采用了CreateProcessWithTokenW方法
public class RunProcessAsCommonUser
{
#region 自己根据网上改的简单粗暴版
[StructLayout(LayoutKind.Sequential)]
internal struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
internal struct SECURITY_ATTRIBUTES
{
public uint nLength;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
[StructLayout(LayoutKind.Sequential)]
public struct STARTUPINFO
{
public uint cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
internal enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous,
SecurityIdentification,
SecurityImpersonation,
SecurityDelegation
}
internal enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation
}
[DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx", SetLastError = true)]
private static extern bool DuplicateTokenEx(
IntPtr hExistingToken,
uint dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
Int32 ImpersonationLevel,
Int32 dwTokenType,
ref IntPtr phNewToken);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool OpenProcessToken(
IntPtr ProcessHandle,
UInt32 DesiredAccess,
ref IntPtr TokenHandle);
/// <summary>
/// 具体参考https://docs.microsoft.com/zh-cn/windows/desktop/api/winbase/nf-winbase-createprocesswithtokenw
/// </summary>
/// <param name="hToken">用户的主令牌的句柄</param>
/// <param name="dwLogonFlags">登录选项</param>
/// <param name="lpApplicationName">模块名称</param>
/// <param name="lpCommandLine">要执行的命令行,注意这里和上面的参数的区别</param>
/// <param name="dwCreationFlags">控制进程创建方式的标志,一般情况下CREATE_UNICODE_ENVIRONMENT 0x00000400就行</param>
/// <param name="lpEnvironment">如果此参数为NULL,则新进程使用从lpUsername指定的用户的配置文件创建的环境</param>
/// <param name="lpCurrentDirectory">如果此参数为NULL,则新进程将具有与调用进程相同的当前驱动器和目录</param>
/// <param name="lpStartupInfo"></param>
/// <param name="lpProcessInformation"></param>
/// <returns></returns>
[DllImport("advapi32.dll", EntryPoint = "CreateProcessWithTokenW", SetLastError = true,
CharSet = CharSet.Unicode,
CallingConvention = CallingConvention.StdCall)]
private extern static bool CreateProcessWithTokenW(
IntPtr hToken,
uint dwLogonFlags,
String lpApplicationName,
String lpCommandLine,
uint dwCreationFlags,
IntPtr lpEnvironment,
String lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(
IntPtr hObject);
private const uint TOKEN_DUPLICATE = 0x0002;
private const int GENERIC_ALL_ACCESS = 0x10000000;
public const uint LOGON_WITH_PROFILE = 00000001;
public const uint NORMAL_PRIORITY_CLASS = 0x00000020;
private const uint CREATE_UNICODE_ENVIRONMENT = 0x00000400;
/// <summary>
/// 进程的路径
/// </summary>
/// <param name="processpath"></param>
public static void CreateProcess(string processpath)
{
IntPtr token = IntPtr.Zero;
Process[] ps = Process.GetProcessesByName("explorer");
int processId = -1;//=processId
if (ps.Length > 0)
{
processId = ps[0].Id;
}
bool result = false;
Process p = Process.GetProcessById(processId);
OpenProcessToken(p.Handle, TOKEN_DUPLICATE, ref token);
CloseHandle(p.Handle);
IntPtr primaryToken = IntPtr.Zero;
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.nLength = (uint)Marshal.SizeOf(sa);
result = DuplicateTokenEx(
token,
GENERIC_ALL_ACCESS,//使用允许所有权限,否则会报error:5的错误
ref sa,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
(int)TOKEN_TYPE.TokenPrimary,
ref primaryToken);
if (result == false)
{
int error = Marshal.GetLastWin32Error();
string message = String.Format("DuplicateTokenEx Error: {0}", error);
Debug.WriteLine(message);
}
CloseHandle(token);
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
STARTUPINFO si = new STARTUPINFO();
result = CreateProcessWithTokenW(
primaryToken,
LOGON_WITH_PROFILE,
null,
processpath,
NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT,
IntPtr.Zero,
null,
ref si,
out pi);
if (result == false)
{
int error = Marshal.GetLastWin32Error();
string message = String.Format("CreateProcessAsUser Error: {0}", error);
Debug.WriteLine(message);
}
}
#endregion
}
参考文档
CreateProcessWithTokenW介绍
https://docs.microsoft.com/zh-cn/windows/desktop/api/winbase/nf-winbase-createprocesswithtokenw
DuplicateTokenEx介绍(注意权限那里)