Skip to content

Instantly share code, notes, and snippets.

@vendettamit
Created May 24, 2013 13:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vendettamit/a518bceef3678963c5fd to your computer and use it in GitHub Desktop.
Save vendettamit/a518bceef3678963c5fd to your computer and use it in GitHub Desktop.
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
namespace Shared.ApplicationLoaderUtil
{
/// <summary>
/// Class that allows running applications with full admin rights. In
/// addition the application launched will bypass the Vista UAC prompt.
/// Windows 8 have two OS modes for running application Windows 8 and Windows Vista mode.
/// </summary>
public class ApplicationLoader
{
/// <summary>
/// The token duplicate.
/// </summary>
private const int TokenDuplicate = 0x0002;
/// <summary>
/// The maximum allowed.
/// </summary>
private const uint MaximumAllowed = 0x2000000;
/// <summary>
/// The create new console.
/// </summary>
private const int CreateNewConsole = 0x00000010;
/// <summary>
/// The idle priority class.
/// </summary>
private const int IdlePriorityClass = 0x40;
/// <summary>
/// The normal priority class.
/// </summary>
private const int NormalPriorityClass = 0x20;
/// <summary>
/// The high priority class.
/// </summary>
private const int HighPriorityClass = 0x80;
/// <summary>
/// The real time priority class.
/// </summary>
private const int RealtimePriorityClass = 0x100;
/// <summary>
/// The win logon process name.
/// </summary>
private const string WinLogonProcessName = "winlogon";
/// <summary>
/// The toke n_ type.
/// </summary>
private enum TokenType
{
/// <summary>
/// The token primary.
/// </summary>
TokenPrimary = 1,
/// <summary>
/// The token impersonation.
/// </summary>
TokenImpersonation = 2
}
/// <summary>
/// The security impersonation level.
/// </summary>
private enum SecurityImpersonationLevel
{
/// <summary>
/// The security anonymous.
/// </summary>
SecurityAnonymous = 0,
/// <summary>
/// The security identification.
/// </summary>
SecurityIdentification = 1,
/// <summary>
/// The security impersonation.
/// </summary>
SecurityImpersonation = 2,
/// <summary>
/// The security delegation.
/// </summary>
SecurityDelegation = 3,
}
/// <summary>
/// Launches the given application with full admin rights, and in addition bypasses the Vista UAC prompt
/// </summary>
/// <param name="applicationName">The name of the application to launch</param>
/// <param name="procInfo">Process information regarding the launched application that gets returned to the caller</param>
/// <returns>true or false</returns>
public static bool StartProcessAndBypassUAC(string applicationName, out ProcessInformation procInfo)
{
uint winlogonPid = 0;
IntPtr userTokenDup = IntPtr.Zero;
IntPtr processPtr = IntPtr.Zero;
IntPtr ptoken = IntPtr.Zero;
procInfo = new ProcessInformation();
// obtain the currently active session id; every logged on user in the system has a unique session id
uint sessionId = WTSGetActiveConsoleSessionId();
// obtain the process id of the winlogon process that is running within the currently active session
Process[] processes = Process.GetProcessesByName(WinLogonProcessName);
foreach (Process p in processes)
{
if ((uint)p.SessionId == sessionId)
{
winlogonPid = (uint)p.Id;
}
}
// obtain a handle to the winlogon process
processPtr = OpenProcess(MaximumAllowed, false, winlogonPid);
// obtain a handle to the access token of the winlogon process
if (!OpenProcessToken(processPtr, TokenDuplicate, ref ptoken))
{
CloseHandle(processPtr);
return false;
}
// Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser
// I would prefer to not have to use a security attribute variable and to just
// simply pass null and inherit (by default) the security attributes
// of the existing token. However, in C# structures are value types and therefore
// cannot be assigned the null value.
SecurityAttributes sa = new SecurityAttributes();
sa.Length = Marshal.SizeOf(sa);
// copy the access token of the winlogon process; the newly created token will be a primary token
if (!DuplicateTokenEx(ptoken, MaximumAllowed, ref sa, (int)SecurityImpersonationLevel.SecurityIdentification, (int)TokenType.TokenPrimary, ref userTokenDup))
{
CloseHandle(processPtr);
CloseHandle(ptoken);
return false;
}
// By default CreateProcessAsUser creates a process on a non-interactive window station, meaning
// the window station has a desktop that is invisible and the process is incapable of receiving
// user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user
// interaction with the new process.
Startupinfo si = new Startupinfo();
si.Cb = (int)Marshal.SizeOf(si);
si.Desktop = @"winsta0\default"; // interactive window station parameter; basically this indicates that the process created can display a GUI on the desktop
// flags that specify the priority and creation method of the process
const int CreationFlags = NormalPriorityClass | CreateNewConsole;
var path = Path.GetFullPath(applicationName);
var dir = Path.GetDirectoryName(path);
// create a new process in the current user's logon session
bool result = CreateProcessAsUser(
userTokenDup, // client's access token
path, // file to execute
string.Format("\"{0}\" {1}", applicationName.Replace("\"", "\"\""), string.Empty), // command line
ref sa, // pointer to process SECURITY_ATTRIBUTES
ref sa, // pointer to thread SECURITY_ATTRIBUTES
false, // handles are not inheritable
CreationFlags, // creation flags
IntPtr.Zero, // pointer to new environment block
dir, // name of current directory
ref si, // pointer to STARTUPINFO structure
out procInfo); // receives information about new process
if (!result)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
// invalidate the handles
CloseHandle(processPtr);
CloseHandle(ptoken);
CloseHandle(userTokenDup);
return result; // return the result
}
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr snapshot);
/// <summary>
/// Creates the process as user.
/// </summary>
/// <param name="token">The token.</param>
/// <param name="applicationName">Name of the application.</param>
/// <param name="commandLine">The command line.</param>
/// <param name="processAttributes">The process attributes.</param>
/// <param name="threadAttributes">The thread attributes.</param>
/// <param name="inheritHandle">if set to <c>true</c> [inherit handle].</param>
/// <param name="creationFlags">The creation flags.</param>
/// <param name="environment">The environment.</param>
/// <param name="currentDirectory">The current directory.</param>
/// <param name="startupInfo">The startup info.</param>
/// <param name="processInformation">The process information.</param>
/// <returns>
/// true or false
/// </returns>
[DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private static extern bool CreateProcessAsUser(
IntPtr token,
string applicationName,
string commandLine,
ref SecurityAttributes processAttributes,
ref SecurityAttributes threadAttributes,
bool inheritHandle,
int creationFlags,
IntPtr environment,
string currentDirectory,
ref Startupinfo startupInfo,
out ProcessInformation processInformation);
/// <summary>
/// Duplicates the token ex.
/// </summary>
/// <param name="existingTokenHandle">The existing token handle.</param>
/// <param name="desiredAccess">The dw desired access.</param>
/// <param name="threadAttributes">The lp thread attributes.</param>
/// <param name="tokenType">Type of the token.</param>
/// <param name="impersonationLevel">The impersonation level.</param>
/// <param name="duplicateTokenHandle">The duplicate token handle.</param>
/// <returns>true or false</returns>
[DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
private static extern bool DuplicateTokenEx(
IntPtr existingTokenHandle,
uint desiredAccess,
ref SecurityAttributes threadAttributes,
int tokenType,
int impersonationLevel,
ref IntPtr duplicateTokenHandle);
[DllImport("kernel32.dll")]
private static extern uint WTSGetActiveConsoleSessionId();
/// <summary>
/// Opens the process.
/// </summary>
/// <param name="desiredAccess">The dw desired access.</param>
/// <param name="inheritHandle">if set to <c>true</c> [b inherit handle].</param>
/// <param name="processId">The dw process id.</param>
/// <returns>integer pointer</returns>
[DllImport("kernel32.dll")]
private static extern IntPtr OpenProcess(uint desiredAccess, bool inheritHandle, uint processId);
/// <summary>
/// Opens the process token.
/// </summary>
/// <param name="processHandle">The process handle.</param>
/// <param name="desiredAccess">The desired access.</param>
/// <param name="tokenHandle">The token handle.</param>
/// <returns>true or false</returns>
[DllImport("advapi32", SetLastError = true), SuppressUnmanagedCodeSecurity]
private static extern bool OpenProcessToken(IntPtr processHandle, int desiredAccess, ref IntPtr tokenHandle);
/// <summary>
/// The process information.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct ProcessInformation
{
/// <summary>
/// The process.
/// </summary>
public IntPtr Process;
/// <summary>
/// The thread.
/// </summary>
public IntPtr Thread;
/// <summary>
/// The process id.
/// </summary>
public uint ProcessId;
/// <summary>
/// The thread id.
/// </summary>
public uint ThreadId;
}
/// <summary>
/// The security attributes.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct SecurityAttributes
{
/// <summary>
/// The length.
/// </summary>
public int Length;
/// <summary>
/// The lp security descriptor.
/// </summary>
public IntPtr SecurityDescriptor;
/// <summary>
/// The b inherit handle.
/// </summary>
public bool InheritHandle;
}
/// <summary>
/// The startupinfo.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct Startupinfo
{
/// <summary>
/// The cb.
/// </summary>
public int Cb;
/// <summary>
/// The lp reserved.
/// </summary>
public string Reserved;
/// <summary>
/// The desktop.
/// </summary>
public string Desktop;
/// <summary>
/// The title.
/// </summary>
public string Title;
/// <summary>
/// The dw x.
/// </summary>
public uint X;
/// <summary>
/// The y.
/// </summary>
public uint Y;
/// <summary>
/// The x size.
/// </summary>
public uint XSize;
/// <summary>
/// The y size.
/// </summary>
public uint YSize;
/// <summary>
/// The x count chars.
/// </summary>
public uint XCountChars;
/// <summary>
/// The y count chars.
/// </summary>
public uint YCountChars;
/// <summary>
/// The fill attribute.
/// </summary>
public uint FillAttribute;
/// <summary>
/// The flags.
/// </summary>
public uint Flags;
/// <summary>
/// The show window.
/// </summary>
public short ShowWindow;
/// <summary>
/// The reserved 2.
/// </summary>
public short Reserved2;
/// <summary>
/// The lp reserved 2.
/// </summary>
public IntPtr LpReserved2;
/// <summary>
/// The std input.
/// </summary>
public IntPtr StdInput;
/// <summary>
/// The std output.
/// </summary>
public IntPtr StdOutput;
/// <summary>
/// The std error.
/// </summary>
public IntPtr StdError;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment