CreateProcessAsUser 으로 다른 권한으로 실행하기
관련 자료
https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessasusera
CreateProcessAsUserA function (processthreadsapi.h)
Creates a new process and its primary thread. The new process runs in the security context of the user represented by the specified token.
docs.microsoft.com
https://support.microsoft.com/ko-kr/help/165194/createprocessasuser-windowstations-and-desktops
https://support.microsoft.com/ko-kr/help/165194/createprocessasuser-windowstations-and-desktops
쿠키가 사용되고 있지 않습니다. 쿠키를 사용하고 페이지를 새로 고치세요.
support.microsoft.com
https://mynotepad.tistory.com/176
VIsta 이상 버전에서 Windows Service 에 등록된 프로그램에서 다른 프로그램 띄우기
Windows Vista 이상 버전에서는 세션 관리정책으로 인해서 Windows 의 Service 에 등록된 프로그램이 직접 다른 프로그램을 띄우지 못하게 막았다. 보안상의 이유로 이렇게 한 듯 한데. 이로 인해서 서비스로 등록..
mynotepad.tistory.com
아래 코드를 통해서 다른 계정의 UI와 권한으로 실행할 수 있다.
public class ProcessLauncher
{
#region Structures
[StructLayout(LayoutKind.Sequential)]
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 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;
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public Int32 dwProcessID;
public Int32 dwThreadID;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public Int32 Length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
[StructLayout(LayoutKind.Sequential)]
public struct ProfileInfo
{
public int dwSize;
public int dwFlags;
public string lpUserName;
public string lpProfilePath;
public string lpDefaultPath;
public string lpServerName;
public string lpPolicyPath;
public IntPtr hProfile;
}
#endregion
#region Enumerations
public enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous,
SecurityIdentification,
SecurityImpersonation,
SecurityDelegation
}
public enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation
}
#endregion
#region Constants
//Use these for DesiredAccess
private static uint STANDARD_RIGHTS_REQUIRED = 0x000F0000;
private static uint STANDARD_RIGHTS_READ = 0x00020000;
private static uint TOKEN_ASSIGN_PRIMARY = 0x0001;
private static uint TOKEN_DUPLICATE = 0x0002;
private static uint TOKEN_IMPERSONATE = 0x0004;
private static uint TOKEN_QUERY = 0x0008;
private static uint TOKEN_QUERY_SOURCE = 0x0010;
private static uint TOKEN_ADJUST_PRIVILEGES = 0x0020;
private static uint TOKEN_ADJUST_GROUPS = 0x0040;
private static uint TOKEN_ADJUST_DEFAULT = 0x0080;
private static uint TOKEN_ADJUST_SESSIONID = 0x0100;
private static uint TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);
private static uint TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID);
private const int MAXIMUM_ALLOWED = 0x2000000;
//Process Creation Flags
private const uint CREATE_UNICODE_ENVIRONMENT = 0x00000400;
private const uint CREATE_NO_WINDOW = 0x08000000;
private const uint CREATE_NEW_CONSOLE = 0x00000010;
private const uint DETACHED_PROCESS = 0x00000008;
private const UInt32 INFINITE = 0xFFFFFFFF;
private const UInt32 WAIT_ABANDONED = 0x00000080;
private const UInt32 WAIT_OBJECT_0 = 0x00000000;
private const UInt32 WAIT_TIMEOUT = 0x00000102;
#endregion
#region Win32 API Imports
[
DllImport("kernel32.dll",
EntryPoint = "CloseHandle", SetLastError = true,
CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)
]
public static extern bool CloseHandle(IntPtr handle);
[
DllImport("advapi32.dll",
EntryPoint = "CreateProcessAsUser", SetLastError = true,
CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)
]
public static extern bool
CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandle, uint dwCreationFlags, IntPtr lpEnvrionment,
string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo,
ref PROCESS_INFORMATION lpProcessInformation);
[
DllImport("advapi32.dll",
EntryPoint = "DuplicateTokenEx")
]
public static extern bool
DuplicateTokenEx(IntPtr hExistingToken, uint dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
Int32 ImpersonationLevel, Int32 dwTokenType,
ref IntPtr phNewToken);
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, ref IntPtr TokenHandle);
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
private static extern uint WTSGetActiveConsoleSessionId();
[DllImport("wtsapi32.dll", SetLastError = true)]
static extern bool WTSQueryUserToken(UInt32 sessionId, out IntPtr Token);
[DllImport("kernel32.dll")]
static extern bool GetExitCodeProcess(IntPtr hProcess, ref int lpExitCode);
[DllImport("kernel32.dll", SetLastError = true)]
static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);
[DllImport("userenv.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, IntPtr hToken, bool bInherit);
[DllImport("userenv.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment);
[DllImport("userenv.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool LoadUserProfile(IntPtr hToken, ref ProfileInfo lpProfileInfo);
[DllImport("Userenv.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool UnloadUserProfile(IntPtr hToken, IntPtr lpProfileInfo);
#endregion
public static void Start(ProcessStartInfo processStartInfo)
{
var primaryToken = IntPtr.Zero;
var userToken = IntPtr.Zero;
var hProcess = IntPtr.Zero;
var pi = new PROCESS_INFORMATION();
var sa = new SECURITY_ATTRIBUTES();
sa.Length = Marshal.SizeOf(sa);
var profileInfo = new ProfileInfo();
profileInfo.dwSize = Marshal.SizeOf(profileInfo);
profileInfo.lpUserName = Environment.UserName;
profileInfo.dwFlags = 1;
try
{
primaryToken = GetCurrentWinLogonToken();
userToken = GetCurrentUserToken();
var si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = "WinSta0\\Default";
IntPtr lpEnvironment = IntPtr.Zero;
if (!CreateEnvironmentBlock(out lpEnvironment, GetCurrentUserToken(), false))
throw new Win32Exception(Marshal.GetLastWin32Error());
//if (!LoadUserProfile(userToken, ref profileInfo))
// throw new Win32Exception(Marshal.GetLastWin32Error());
if (!CreateProcessAsUser(
primaryToken,
null,
string.Format("\"{0}\" {1}", processStartInfo.FileName.Replace("\"", "\"\""), processStartInfo.Arguments),
ref sa, ref sa,
false, CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, lpEnvironment,
null, ref si, ref pi
))
throw new Win32Exception(Marshal.GetLastWin32Error());
DestroyEnvironmentBlock(lpEnvironment);
}
finally
{
if (pi.hProcess != IntPtr.Zero)
CloseHandle(pi.hProcess);
if (pi.hThread != IntPtr.Zero)
CloseHandle(pi.hThread);
if (primaryToken != IntPtr.Zero)
CloseHandle(primaryToken);
//UnloadUserProfile(userToken, profileInfo.hProfile);
}
}
private static IntPtr GetCurrentWinLogonToken()
{
int winlogonPid = 0;
var hToken = IntPtr.Zero;
var hDupedToken = IntPtr.Zero;
var hProcess = IntPtr.Zero;
var sa = new SECURITY_ATTRIBUTES();
sa.Length = Marshal.SizeOf(sa);
IntPtr pServer = IntPtr.Zero;
uint dwSessionId = GetCurrentUserSessionId();
// obtain the process id of the winlogon process that is running within the currently active session
Process[] processes = Process.GetProcessesByName("winlogon");
foreach (Process p in processes)
{
if (p.SessionId == dwSessionId)
{
winlogonPid = p.Id;
}
}
// obtain a handle to the winlogon process
hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid);
if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hToken))
throw new Win32Exception(Marshal.GetLastWin32Error());
if (!DuplicateTokenEx(
hToken,
TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS,
ref sa,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
(int)TOKEN_TYPE.TokenPrimary,
ref hDupedToken
))
throw new Win32Exception(Marshal.GetLastWin32Error());
return hDupedToken;
}
private static uint GetCurrentUserSessionId()
{
uint dwSessionId = 0;
using (ITerminalServer localServer = (new TerminalServicesManager()).GetLocalServer())
{
foreach (ITerminalServicesSession current in localServer.GetSessions())
{
if (current.ConnectionState == ConnectionState.Active)
{
dwSessionId = (uint)current.SessionId;
break;
}
}
}
return dwSessionId;
}
private static IntPtr GetCurrentUserToken()
{
var hToken = IntPtr.Zero;
var hDupedToken = IntPtr.Zero;
var sa = new SECURITY_ATTRIBUTES();
sa.Length = Marshal.SizeOf(sa);
IntPtr pServer = IntPtr.Zero;
uint dwSessionId = GetCurrentUserSessionId();
if (!WTSQueryUserToken(dwSessionId, out hToken))
throw new Win32Exception(Marshal.GetLastWin32Error());
if (!DuplicateTokenEx(
hToken,
TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS,
ref sa,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
(int)TOKEN_TYPE.TokenPrimary,
ref hDupedToken
))
throw new Win32Exception(Marshal.GetLastWin32Error());
return hDupedToken;
}
}
[코드] 특정 계정의 토큰 값으로 사용자 계정으로 프로세스 실행하는 코드