I have a long running Windows Service. In its deployment we often use custom domain user logon credentials to give addition rights to the service. As the service is running the credentials of the user that the service is running as may change or expire. I trying to write a feature to notify users that the service credentials have expired and manual intervention must be taken update the logon credentials.
My question is what is the best way to detect from a service running under an expired context that its context has expired?
Thanks
I would take a different approach and leave the service with a restricted user, such as Network Service.
Then from the service, impersonate the currently logged on user, which is tricky as none or more than one user may be logged in. This answer provides sample code to duplicate the token.
Finally use that duplicated token to access the network share, like here.
EDIT:
The following code works when run as Local System account:
class AccessShareAsLoggedOnUser
{
public static bool CopyAsLocalUser(String sourceFile, string targetFile)
{
uint dwSessionId, winlogonPid = 0;
IntPtr hUserToken = IntPtr.Zero, hUserTokenDup = IntPtr.Zero, hPToken = IntPtr.Zero, hProcess = IntPtr.Zero;
Debug.Print("CreateProcessInConsoleSession");
// Log the client on to the local computer.
dwSessionId = WTSGetActiveConsoleSessionId();
// Find the winlogon process
var procEntry = new PROCESSENTRY32();
uint hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap == INVALID_HANDLE_VALUE)
{
return false;
}
procEntry.dwSize = (uint)Marshal.SizeOf(procEntry); //sizeof(PROCESSENTRY32);
if (Process32First(hSnap, ref procEntry) == 0)
{
return false;
}
String strCmp = "explorer.exe";
do
{
if (strCmp.IndexOf(procEntry.szExeFile) == 0)
{
// We found a winlogon process...make sure it's running in the console session
uint winlogonSessId = 0;
if (ProcessIdToSessionId(procEntry.th32ProcessID, ref winlogonSessId) &&
winlogonSessId == dwSessionId)
{
winlogonPid = procEntry.th32ProcessID;
break;
}
}
}
while (Process32Next(hSnap, ref procEntry) != 0);
//Get the user token used by DuplicateTokenEx
WTSQueryUserToken(dwSessionId, ref hUserToken);
hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid);
if (
!OpenProcessToken(hProcess,
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY
| TOKEN_ADJUST_SESSIONID | TOKEN_READ | TOKEN_WRITE, ref hPToken))
{
Debug.Print(String.Format("CreateProcessInConsoleSession OpenProcessToken error: {0}",
Marshal.GetLastWin32Error()));
}
var sa = new SECURITY_ATTRIBUTES();
sa.Length = Marshal.SizeOf(sa);
if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary,
ref hUserTokenDup))
{
Debug.Print(
String.Format(
"CreateProcessInConsoleSession DuplicateTokenEx error: {0} Token does not have the privilege.",
Marshal.GetLastWin32Error()));
CloseHandle(hProcess);
CloseHandle(hUserToken);
CloseHandle(hPToken);
return false;
}
try
{
using (WindowsImpersonationContext impersonationContext =
new WindowsIdentity(hUserTokenDup).Impersonate())
{
// Put your network Code here.
File.WriteAllText(targetFile // Somewhere with right permissions like #"C:\Users\xxx\output.txt"
, File.ReadAllText(sourceFile)); // like #"\\server\share\existingfile.txt"
impersonationContext.Undo();
}
return true;
}
finally
{
if (hUserTokenDup != IntPtr.Zero)
{
if (!CloseHandle(hUserTokenDup))
{
// Uncomment if you need to know this case.
////throw new Win32Exception();
}
}
//Close handles task
CloseHandle(hProcess);
CloseHandle(hUserToken);
CloseHandle(hUserTokenDup);
CloseHandle(hPToken);
}
}
[DllImport("kernel32.dll")]
private static extern int Process32First(uint hSnapshot, ref PROCESSENTRY32 lppe);
[DllImport("kernel32.dll")]
private static extern int Process32Next(uint hSnapshot, ref PROCESSENTRY32 lppe);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern uint CreateToolhelp32Snapshot(uint dwFlags, uint th32ProcessID);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr hSnapshot);
[DllImport("kernel32.dll")]
private static extern uint WTSGetActiveConsoleSessionId();
[DllImport("Wtsapi32.dll")]
private static extern uint WTSQueryUserToken(uint SessionId, ref IntPtr phToken);
[DllImport("kernel32.dll")]
private static extern bool ProcessIdToSessionId(uint dwProcessId, ref uint pSessionId);
[DllImport("kernel32.dll")]
private static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
[DllImport("advapi32", SetLastError = true)]
[SuppressUnmanagedCodeSecurity]
private static extern bool OpenProcessToken(IntPtr ProcessHandle, // handle to process
int DesiredAccess, // desired access to process
ref IntPtr TokenHandle);
[DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
public static extern bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType,
int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);
#region Nested type: PROCESSENTRY32
[StructLayout(LayoutKind.Sequential)]
private struct PROCESSENTRY32
{
public uint dwSize;
public readonly uint cntUsage;
public readonly uint th32ProcessID;
public readonly IntPtr th32DefaultHeapID;
public readonly uint th32ModuleID;
public readonly uint cntThreads;
public readonly uint th32ParentProcessID;
public readonly int pcPriClassBase;
public readonly uint dwFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public readonly string szExeFile;
}
#endregion
#region Nested type: SECURITY_ATTRIBUTES
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int Length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
#endregion
#region Nested type: SECURITY_IMPERSONATION_LEVEL
private enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3,
}
#endregion
#region Nested type: TOKEN_TYPE
private enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation = 2
}
#endregion
public const int READ_CONTROL = 0x00020000;
public const int STANDARD_RIGHTS_REQUIRED = 0x000F0000;
public const int STANDARD_RIGHTS_READ = READ_CONTROL;
public const int STANDARD_RIGHTS_WRITE = READ_CONTROL;
public const int STANDARD_RIGHTS_EXECUTE = READ_CONTROL;
public const int STANDARD_RIGHTS_ALL = 0x001F0000;
public const int SPECIFIC_RIGHTS_ALL = 0x0000FFFF;
public const int TOKEN_ASSIGN_PRIMARY = 0x0001;
public const int TOKEN_DUPLICATE = 0x0002;
public const int TOKEN_IMPERSONATE = 0x0004;
public const int TOKEN_QUERY = 0x0008;
public const int TOKEN_QUERY_SOURCE = 0x0010;
public const int TOKEN_ADJUST_PRIVILEGES = 0x0020;
public const int TOKEN_ADJUST_GROUPS = 0x0040;
public const int TOKEN_ADJUST_DEFAULT = 0x0080;
public const int TOKEN_ADJUST_SESSIONID = 0x0100;
public const int TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY;
public const int TOKEN_WRITE = STANDARD_RIGHTS_WRITE |
TOKEN_ADJUST_PRIVILEGES |
TOKEN_ADJUST_GROUPS |
TOKEN_ADJUST_DEFAULT;
public const uint MAXIMUM_ALLOWED = 0x2000000;
private const uint TH32CS_SNAPPROCESS = 0x00000002;
public static int INVALID_HANDLE_VALUE = -1;
// handle to open access token
}
Related
I'm making a interactive service on Windows 7, on visual studio 2015, that is able to initialize an application UI but the WTSQueryUserToken method is retuning false.
IntPtr hToken = IntPtr.Zero;
if (WTSQueryUserToken(tSessionInfo.SessionID, out hToken)) //FALSE returned
I really don't have much experience with C# so I've searched online to get an answer and I found that "To call this function (WTSQueryUserToken) successfully, the calling application must be running within the context of the LocalSystem account and have the SE_TCB_NAME privilege", but I don't know how can I give the application SE_TCB_NAME privilege privilege on the code. Does anyone know how can I code this?
Thank you.
You have to do impersonation to launch the application under the user account.
Here is a sample of that, showing also how to get the SE_TCB_NAME privilege.
In this sample we first get the security token for the Current Process and then escalate the privileges to include the SE_TCB_NAME privilege.
Once we are done with that then we take the SessionId of the explorer process, and duplicate the security token associated with it, which we then pass to CreateProcessAsUser.
public class Impersonation
{
#region DLL Imports
internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
internal const int TOKEN_ASSIGN_PRIMARY = 0x0001;
internal const int TOKEN_DUPLICATE = 0x0002;
internal const int TOKEN_IMPERSONATE = 0X00000004;
internal const int TOKEN_ADJUST_DEFAULT = 0x0080;
internal const int TOKEN_ADJUST_SESSIONID = 0x0100;
internal const int MAXIMUM_ALLOWED = 0x2000000;
internal const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
internal const int NORMAL_PRIORITY_CLASS = 0x20;
internal const int CREATE_NEW_CONSOLE = 0x00000010;
internal const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
internal const string SE_TCB_NAME = "SeTcbPrivilege";
internal const string SE_RESTORE_NAME = "SeRestorePrivilege";
private static WindowsImpersonationContext impersonatedUser;
public static IntPtr hToken = IntPtr.Zero;
public static IntPtr dupeTokenHandle = IntPtr.Zero;
const string SE_INCREASE_QUOTA_NAME = "SeIncreaseQuotaPrivilege";
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid
{
public int Count;
public long Luid;
public int Attr;
}
struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
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;
}
[StructLayout(LayoutKind.Sequential)]
struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
public enum ShowCommands : int
{
SW_HIDE = 0,
SW_SHOWNORMAL = 1,
SW_NORMAL = 1,
SW_SHOWMINIMIZED = 2,
SW_SHOWMAXIMIZED = 3,
SW_MAXIMIZE = 3,
SW_SHOWNOACTIVATE = 4,
SW_SHOW = 5,
SW_MINIMIZE = 6,
SW_SHOWMINNOACTIVE = 7,
SW_SHOWNA = 8,
SW_RESTORE = 9,
SW_SHOWDEFAULT = 10,
SW_FORCEMINIMIZE = 11,
SW_MAX = 11
}
[DllImport("shell32.dll")]
static extern IntPtr ShellExecute(
IntPtr hwnd,
string lpOperation,
string lpFile,
string lpParameters,
string lpDirectory,
ShowCommands nShowCmd);
[DllImport("advapi32.dll", SetLastError = true)]
static extern int ImpersonateLoggedOnUser(IntPtr hToken);
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
[DllImport("kernel32", SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
static extern bool CloseHandle(IntPtr handle);
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
[DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
static extern bool DuplicateTokenEx(IntPtr hExistingToken, Int32 dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
Int32 ImpersonationLevel, Int32 dwTokenType,
ref IntPtr phNewToken);
[DllImport("userenv.dll", SetLastError = true)]
static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, IntPtr hToken, bool bInherit);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern bool CreateProcessAsUser(
IntPtr hToken,
string lpApplicationName,
string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
#endregion
private static readonly ILog log = LogManager.GetLogger(typeof(Impersonation));
private static void WriteToLog(string message)
{
log.Debug(message);
}
/// <summary>
/// Duplicates the token information derived
/// from the logged in user's credentials. This
/// is required to run the application on the
/// logged in users desktop.
/// </summary>
/// <returns>Returns true if the application was successfully started in the user's desktop.</returns>
public static bool ExecuteAppAsLoggedOnUser(string AppName, string CmdLineArgs)
{
WriteToLog("In ExecuteAppAsLoggedOnUser for all users.");
IntPtr LoggedInUserToken = IntPtr.Zero;
IntPtr DuplicateToken = IntPtr.Zero;
IntPtr ShellProcessToken = IntPtr.Zero;
if (!OpenProcessToken(Process.GetCurrentProcess().Handle, TOKEN_ADJUST_PRIVILEGES, ref LoggedInUserToken))
{
WriteToLog("OpenProcessToken failed: " + Marshal.GetLastWin32Error());
return false;
}
else
{
//Below part for increasing the UAC previleges to the token.
TokPriv1Luid tp = new TokPriv1Luid();
tp.Count = 1;
tp.Luid = 0;
if (!LookupPrivilegeValue(null, SE_INCREASE_QUOTA_NAME, ref tp.Luid))
{
WriteToLog("LookupPrivilegeValue failed: " + Marshal.GetLastWin32Error());
return false;
}
tp.Attr = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(LoggedInUserToken, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero))
{
WriteToLog("OpenProcessToken failed: " + Marshal.GetLastWin32Error());
return false;
}
CloseHandle(LoggedInUserToken);
}
List<Process> explorerProcessList = new List<Process>();
string trayProcessName = AppName.Substring(AppName.LastIndexOf(#"\") + 1, AppName.Length - AppName.LastIndexOf(#"\") - 5);
foreach (Process explorerProcess in Process.GetProcessesByName("explorer"))
{
bool IsProcessRunningForUser = false;
foreach (Process PHTrayProcess in Process.GetProcessesByName(trayProcessName))
{
if (explorerProcess.SessionId == PHTrayProcess.SessionId)
{
if (log.IsDebugEnabled) log.Debug(trayProcessName + " is already running for user SessionId " + explorerProcess.SessionId);
IsProcessRunningForUser = true;
break;
}
}
if (((Environment.OSVersion.Version.Major > 5 && explorerProcess.SessionId > 0)
|| Environment.OSVersion.Version.Major == 5)
&& !IsProcessRunningForUser)
{
if (log.IsDebugEnabled) log.Debug(trayProcessName + " is not running for user SessionId " + explorerProcess.SessionId);
explorerProcessList.Add(explorerProcess);
}
}
if (null != explorerProcessList && explorerProcessList.Count > 0)
{
foreach (Process explorerProcess in explorerProcessList)
{
Process ShellProcess = explorerProcess;
ShellProcess.StartInfo.LoadUserProfile = true;
try
{
int tokenRights = MAXIMUM_ALLOWED; //TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID;
if (!OpenProcessToken(ShellProcess.Handle, tokenRights, ref ShellProcessToken))
{
WriteToLog("Unable to OpenProcessToken " + Marshal.GetLastWin32Error());
return false;
}
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.nLength = Marshal.SizeOf(sa);
if (!DuplicateTokenEx(ShellProcessToken, tokenRights, ref sa, 2, 1, ref DuplicateToken))
{
WriteToLog("Unable to duplicate token " + Marshal.GetLastWin32Error());
return false;
}
WriteToLog("Duplicated the token " + WindowsIdentity.GetCurrent().Name);
SECURITY_ATTRIBUTES processAttributes = new SECURITY_ATTRIBUTES();
SECURITY_ATTRIBUTES threadAttributes = new SECURITY_ATTRIBUTES();
PROCESS_INFORMATION pi;
STARTUPINFO si = new STARTUPINFO();
si.cb = (uint)Marshal.SizeOf(si);
IntPtr UserEnvironment = IntPtr.Zero;
uint dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
if (!CreateEnvironmentBlock(out UserEnvironment, ShellProcessToken, true))
{
WriteToLog("Unable to create user's enviroment block " + Marshal.GetLastWin32Error());
}
else
{
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
}
//string userName = getUserName(UserEnvironment);
//WriteToLog("UserName:::" + userName);
if (!CreateProcessAsUser(DuplicateToken, AppName, (CmdLineArgs == null) ? string.Empty : CmdLineArgs, ref processAttributes, ref threadAttributes, true, dwCreationFlags, UserEnvironment, AppName.Substring(0, AppName.LastIndexOf('\\')), ref si, out pi))
{
WriteToLog("Unable to create process " + Marshal.GetLastWin32Error());
if (Marshal.GetLastWin32Error() == 740)
{
WriteToLog("Please check the installation as some elevated permissions is required to execute the binaries");
}
return false;
}
Process trayApp = Process.GetProcessById(Convert.ToInt32(pi.dwProcessId));
trayApp.StartInfo.LoadUserProfile = true;
}
finally
{
if (ShellProcessToken != null) CloseHandle(ShellProcessToken);
if (DuplicateToken != null) CloseHandle(DuplicateToken);
}
}
}
else
{
WriteToLog("No user has been identified to have logged into the system.");
return false;
}
WriteToLog("Finished ExecuteAppAsLoggedOnUser for all users.");
return true;
}
/// <summary>
/// Impersonate the user credentials. This would be required by
/// the service applications to impersonate the logged in user
/// credentials to launch certain applications or applying the
/// power scheme.
/// </summary>
/// <returns>Returns true if the impersonation is successful.</returns>
public static bool ImpersonateUser()
{
// For simplicity I'm using the PID of System here
//if (log.IsDebugEnabled) log.Debug("GetaProcess for Explorer");
Process Pname = GetaProcess("explorer");
//This can be null if no user has not logged into the system.
if (Pname == null) return false;
int pid = Pname.Id;
Process proc = Process.GetProcessById(pid);
if (OpenProcessToken(proc.Handle, TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, ref hToken)) // != 0)
{
WindowsIdentity newId = new WindowsIdentity(hToken);
//log.Debug(newId.Owner);
try
{
const int SecurityImpersonation = 2;
dupeTokenHandle = DupeToken(hToken,
SecurityImpersonation);
if (IntPtr.Zero == dupeTokenHandle)
{
string s = String.Format("Dup failed {0}, privilege not held",
Marshal.GetLastWin32Error());
throw new Exception(s);
}
impersonatedUser = newId.Impersonate();
return true;
}
finally
{
CloseHandle(hToken);
}
}
else
{
string s = String.Format("OpenProcess Failed {0}, privilege not held", Marshal.GetLastWin32Error());
throw new Exception(s);
}
}
/// <summary>
/// Duplicate the token for user impersonation.
/// </summary>
/// <param name="token">Token to duplicate for impersonation</param>
/// <param name="Level">Impersonation security level, currently hardcored to 2</param>
/// <returns>Returns duplicated token</returns>
public static IntPtr DupeToken(IntPtr token, int Level)
{
IntPtr dupeTokenHandle = IntPtr.Zero;
bool retVal = DuplicateToken(token, Level, ref dupeTokenHandle);
return dupeTokenHandle;
}
/// <summary>
/// Get the process running locally on the machine.
/// If the specified process does not exists, it
/// returns back the current process.
/// </summary>
/// <param name="processname">Process name to get</param>
/// <returns>Returns back the process</returns>
public static Process GetaProcess(string processname)
{
Process[] aProc = Process.GetProcessesByName(processname);
if (aProc.Length > 0) return aProc[0];
else
{
//if (log.IsDebugEnabled) log.Debug("Explorer is not running");
Process currentProcess = Process.GetCurrentProcess();
return currentProcess;
}
}
/// <summary>
/// Roleback the impersonation if applied previously.
/// </summary>
public static void UndoImpersonate()
{
impersonatedUser.Undo();
if (hToken != IntPtr.Zero) CloseHandle(hToken);
if (dupeTokenHandle != IntPtr.Zero) CloseHandle(dupeTokenHandle);
return;
}
}
And then you can just do
Impersonation.ExecuteAppAsLoggedOnUser("applicationName", null);
You can either set Act as part of the operating system in Local security policy, or you can also set the privileges programmatically using LsaAddAccountRights.
Hi Im trying to open a external .exe in c#.
If i try to open the .exe file in my computer like "C:\programs\test.exe" it works well. but if I try to open it in another machine I have to map the drive
S:\programs\test.exe , is ok but it prompts a message if I wanna run this .exe
I want to avoid this message.
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "S:\\dev_express\\calendario_indar.exe";
psi.Arguments = "arguments"
var p = Process.Start(psi);
I had similar problems about running executable files. I found a class from MSDN and I always use it. But I'm not sure if it hides that window too. But give it a try. After adding this class to your Project you can launch your application like that:
NativeMethods.LaunchProcess("S:\\dev_express\\calendario_indar.exe");
Class is here:
class NativeMethods
{
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public System.UInt32 dwProcessId;
public System.UInt32 dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public System.UInt32 nLength;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
[StructLayout(LayoutKind.Sequential)]
public struct STARTUPINFO
{
public System.UInt32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public System.UInt32 dwX;
public System.UInt32 dwY;
public System.UInt32 dwXSize;
public System.UInt32 dwYSize;
public System.UInt32 dwXCountChars;
public System.UInt32 dwYCountChars;
public System.UInt32 dwFillAttribute;
public System.UInt32 dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct PROFILEINFO
{
public int dwSize;
public int dwFlags;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpUserName;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpProfilePath;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpDefaultPath;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpServerName;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpPolicyPath;
public IntPtr hProfile;
}
internal enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3
}
internal enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation = 2
}
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, ref PROCESS_INFORMATION lpProcessInformation);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool DuplicateTokenEx(IntPtr hExistingToken, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpTokenAttributes, SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, TOKEN_TYPE TokenType, ref IntPtr phNewToken);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle);
[DllImport("userenv.dll", SetLastError = true)]
private static extern bool CreateEnvironmentBlock(ref IntPtr lpEnvironment, IntPtr hToken, bool bInherit);
[DllImport("userenv.dll", SetLastError = true)]
private static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment);
private const short SW_SHOW = 1;
private const short SW_SHOWMAXIMIZED = 7;
private const int TOKEN_QUERY = 8;
private const int TOKEN_DUPLICATE = 2;
private const int TOKEN_ASSIGN_PRIMARY = 1;
private const int GENERIC_ALL_ACCESS = 268435456;
private const int STARTF_USESHOWWINDOW = 1;
private const int STARTF_FORCEONFEEDBACK = 64;
private const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
private const string gs_EXPLORER = "explorer";
public static void LaunchProcess(string Ps_CmdLine)
{
IntPtr li_Token = default(IntPtr);
IntPtr li_EnvBlock = default(IntPtr);
Process[] lObj_Processes = Process.GetProcessesByName(gs_EXPLORER);
// Get explorer.exe id
// If process not found
if (lObj_Processes.Length == 0)
{
// Exit routine
return;
}
// Get primary token for the user currently logged in
li_Token = GetPrimaryToken(lObj_Processes[0].Id);
// If token is nothing
if (li_Token.Equals(IntPtr.Zero))
{
// Exit routine
return;
}
// Get environment block
li_EnvBlock = GetEnvironmentBlock(li_Token);
// Launch the process using the environment block and primary token
LaunchProcessAsUser(Ps_CmdLine, li_Token, li_EnvBlock);
// If no valid enviroment block found
if (li_EnvBlock.Equals(IntPtr.Zero))
{
// Exit routine
return;
}
// Destroy environment block. Free environment variables created by the
// CreateEnvironmentBlock function.
DestroyEnvironmentBlock(li_EnvBlock);
}
private static IntPtr GetPrimaryToken(int Pi_ProcessId)
{
IntPtr li_Token = IntPtr.Zero;
IntPtr li_PrimaryToken = IntPtr.Zero;
bool lb_ReturnValue = false;
Process lObj_Process = Process.GetProcessById(Pi_ProcessId);
SECURITY_ATTRIBUTES lObj_SecurityAttributes = default(SECURITY_ATTRIBUTES);
// Get process by id
// Open a handle to the access token associated with a process. The access token
// is a runtime object that represents a user account.
lb_ReturnValue = OpenProcessToken(lObj_Process.Handle, TOKEN_DUPLICATE, ref li_Token);
// If successfull in opening handle to token associated with process
if (lb_ReturnValue)
{
// Create security attributes to pass to the DuplicateTokenEx function
lObj_SecurityAttributes = new SECURITY_ATTRIBUTES();
lObj_SecurityAttributes.nLength = Convert.ToUInt32(Marshal.SizeOf(lObj_SecurityAttributes));
// Create a new access token that duplicates an existing token. This function
// can create either a primary token or an impersonation token.
lb_ReturnValue = DuplicateTokenEx(li_Token, Convert.ToUInt32(TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY), ref lObj_SecurityAttributes, SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, TOKEN_TYPE.TokenPrimary, ref li_PrimaryToken);
// If un-successful in duplication of the token
if (!lb_ReturnValue)
{
// Throw exception
throw new Exception(string.Format("DuplicateTokenEx Error: {0}", Marshal.GetLastWin32Error()));
}
}
else
{
// If un-successful in opening handle for token then throw exception
throw new Exception(string.Format("OpenProcessToken Error: {0}", Marshal.GetLastWin32Error()));
}
// Return primary token
return li_PrimaryToken;
}
private static IntPtr GetEnvironmentBlock(IntPtr Pi_Token)
{
IntPtr li_EnvBlock = IntPtr.Zero;
bool lb_ReturnValue = CreateEnvironmentBlock(ref li_EnvBlock, Pi_Token, false);
// Retrieve the environment variables for the specified user.
// This block can then be passed to the CreateProcessAsUser function.
// If not successful in creation of environment block then
if (!lb_ReturnValue)
{
// Throw exception
throw new Exception(string.Format("CreateEnvironmentBlock Error: {0}", Marshal.GetLastWin32Error()));
}
// Return the retrieved environment block
return li_EnvBlock;
}
private static void LaunchProcessAsUser(string Ps_CmdLine, IntPtr Pi_Token, IntPtr Pi_EnvBlock)
{
bool lb_Result = false;
PROCESS_INFORMATION lObj_ProcessInformation = default(PROCESS_INFORMATION);
SECURITY_ATTRIBUTES lObj_ProcessAttributes = default(SECURITY_ATTRIBUTES);
SECURITY_ATTRIBUTES lObj_ThreadAttributes = default(SECURITY_ATTRIBUTES);
STARTUPINFO lObj_StartupInfo = default(STARTUPINFO);
// Information about the newly created process and its primary thread.
lObj_ProcessInformation = new PROCESS_INFORMATION();
// Create security attributes to pass to the CreateProcessAsUser function
lObj_ProcessAttributes = new SECURITY_ATTRIBUTES();
lObj_ProcessAttributes.nLength = Convert.ToUInt32(Marshal.SizeOf(lObj_ProcessAttributes));
lObj_ThreadAttributes = new SECURITY_ATTRIBUTES();
lObj_ThreadAttributes.nLength = Convert.ToUInt32(Marshal.SizeOf(lObj_ThreadAttributes));
// To specify the window station, desktop, standard handles, and appearance of the
// main window for the new process.
lObj_StartupInfo = new STARTUPINFO();
lObj_StartupInfo.cb = Convert.ToUInt32(Marshal.SizeOf(lObj_StartupInfo));
lObj_StartupInfo.lpDesktop = null;
lObj_StartupInfo.dwFlags = Convert.ToUInt32(STARTF_USESHOWWINDOW | STARTF_FORCEONFEEDBACK);
lObj_StartupInfo.wShowWindow = SW_SHOW;
// Creates a new process and its primary thread. The new process runs in the
// security context of the user represented by the specified token.
lb_Result = CreateProcessAsUser(Pi_Token, null, Ps_CmdLine, ref lObj_ProcessAttributes, ref lObj_ThreadAttributes, true, CREATE_UNICODE_ENVIRONMENT, Pi_EnvBlock, null, ref lObj_StartupInfo, ref lObj_ProcessInformation);
// If create process return false then
if (!lb_Result)
{
// Throw exception
throw new Exception(string.Format("CreateProcessAsUser Error: {0}", Marshal.GetLastWin32Error()));
}
}
}
I installed a windows service by the following code.
#region Private Variables
#endregion Private Variables
#region DLLImport
[DllImport("advapi32.dll")]
public static extern IntPtr OpenSCManager(string lpMachineName, string lpSCDB, int scParameter);
[DllImport("Advapi32.dll")]
public static extern IntPtr CreateService(IntPtr SC_HANDLE, string lpSvcName, string lpDisplayName,
int dwDesiredAccess, int dwServiceType, int dwStartType, int dwErrorControl, string lpPathName,
string lpLoadOrderGroup, int lpdwTagId, string lpDependencies, string lpServiceStartName, string lpPassword);
[DllImport("advapi32.dll")]
public static extern void CloseServiceHandle(IntPtr SCHANDLE);
[DllImport("advapi32.dll")]
public static extern int StartService(IntPtr SVHANDLE, int dwNumServiceArgs, string lpServiceArgVectors);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern IntPtr OpenService(IntPtr SCHANDLE, string lpSvcName, int dwNumServiceArgs);
[DllImport("advapi32.dll")]
public static extern int DeleteService(IntPtr SVHANDLE);
[DllImport("kernel32.dll")]
public static extern int GetLastError();
#endregion DLLImport
public static bool InstallService(string svcPath, string svcName, string svcDispName)
{
#region Constants declaration.
int SC_MANAGER_CREATE_SERVICE = 0x0002;
int SERVICE_WIN32_OWN_PROCESS = 0x00000010;
//int SERVICE_DEMAND_START = 0x00000003;
int SERVICE_ERROR_NORMAL = 0x00000001;
int STANDARD_RIGHTS_REQUIRED = 0xF0000;
int SERVICE_QUERY_CONFIG = 0x0001;
int SERVICE_CHANGE_CONFIG = 0x0002;
int SERVICE_QUERY_STATUS = 0x0004;
int SERVICE_ENUMERATE_DEPENDENTS = 0x0008;
int SERVICE_START = 0x0010;
int SERVICE_STOP = 0x0020;
int SERVICE_PAUSE_CONTINUE = 0x0040;
int SERVICE_INTERROGATE = 0x0080;
int SERVICE_USER_DEFINED_CONTROL = 0x0100;
int SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED |
SERVICE_QUERY_CONFIG |
SERVICE_CHANGE_CONFIG |
SERVICE_QUERY_STATUS |
SERVICE_ENUMERATE_DEPENDENTS |
SERVICE_START |
SERVICE_STOP |
SERVICE_PAUSE_CONTINUE |
SERVICE_INTERROGATE |
SERVICE_USER_DEFINED_CONTROL);
int SERVICE_AUTO_START = 0x00000002;
#endregion Constants declaration.
try
{
IntPtr sc_handle = OpenSCManager(null, null, SC_MANAGER_CREATE_SERVICE);
if (sc_handle.ToInt32() != 0)
{
IntPtr sv_handle = CreateService(sc_handle, svcName, svcDispName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, svcPath, null, 0, null, null, null);
if (sv_handle.ToInt32() == 0)
{
CloseServiceHandle(sc_handle);
return false;
}
else
{
//now trying to start the service
int i = StartService(sv_handle, 0, null);
// If the value i is zero, then there was an error starting the service.
// note: error may arise if the service is already running or some other problem.
if (i == 0)
{
Console.WriteLine("Couldnt start service");
return false;
}
Console.WriteLine("Service started successfully");
CloseServiceHandle(sc_handle);
return true;
}
}
else
{
Console.WriteLine("SCM not opened successfully");
return false;
}
}
catch (Exception e)
{
throw e;
}
}
But the description is blank in SCM, please don't use ServiceInsatller since I want to modify the existing code in production. Thanks for code contribution.
UPDATE:
If forget the above code and use ManagedInstallerClass or other methods, how?
The answered code does not work. This is a version that does work for me:
const int SERVICE_CONFIG_DESCRIPTION = 0x01;
[DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ChangeServiceConfig2(IntPtr hService, int dwInfoLevel, [MarshalAs(UnmanagedType.Struct)] ref SERVICE_DESCRIPTION lpInfo);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct SERVICE_DESCRIPTION
{
public string lpDescription;
}
var pinfo = new SERVICE_DESCRIPTION
{
lpDescription = "My Service Description"
};
ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, ref pinfo);
The original answer is located here, and repeated here for convenience.
Call ChangeServiceConfig2 passing SERVICE_CONFIG_DESCRIPTION as the
dwInfoLevel parameter. You will also need a handle to the service, but
CreateService gives you one of those.
As far the DllImport goes, you can find the specification for ChangeServiceConfig2 here.
EDIT:
If you want to abandon the existing approach altogether, using ManagedInstallerClass is not the right way to go because MSDN explicitly says not to use it in your code. The correct way, in my estimation, is to use the ServiceInstaller component, but your original question said you didn't want to use that approach.
Let's say you relented on not using ServiceInstaller. Then I would suggest following the instructions that I provided in my answer here, paying particular attention to steps 6-9. In step #8, you can add whatever description you like to the ServiceInstaller component in the property grid.
If you still don't want to do that approach, then my original answer stands. It would look something like this (mind you, I have not tested this):
[DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ChangeServiceConfig2(
IntPtr hService,
int dwInfoLevel,
IntPtr lpInfo);
int SERVICE_CONFIG_DESCRIPTION = 0x01;
ChangeServiceConfig2(sv_handle, SERVICE_CONFIG_DESCRIPTION, "a test description");
This question already has answers here:
How do I restart a WPF application? [duplicate]
(8 answers)
Closed 9 years ago.
I have a full-screen WPF application which runs at start-up on Windows 7 Ultimate. In case the application crashes/closes in the event of an unhandled exception I need to restart the WPF application automatically.
What is the simplest way to do it?
in above case u can use a windows service to monitor the application. in the processes wether if its running or not. if it has stoped for any reason then the service must start this application again.
Twist: in Windows Vista microsoft changed windows security system. there for Windows Services will start under Session 0. which is a issue to be consider here. but to execute the Windows applicaton from the Window Service you can use below code.
public class ProcessAsUser
{
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool CreateProcessAsUser(
IntPtr hToken,
string lpApplicationName,
string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[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);
[DllImport("userenv.dll", SetLastError = true)]
private static extern bool CreateEnvironmentBlock(
ref IntPtr lpEnvironment,
IntPtr hToken,
bool bInherit);
[DllImport("userenv.dll", SetLastError = true)]
private static extern bool DestroyEnvironmentBlock(
IntPtr lpEnvironment);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(
IntPtr hObject);
private const short SW_SHOW = 5;
private const uint TOKEN_QUERY = 0x0008;
private const uint TOKEN_DUPLICATE = 0x0002;
private const uint TOKEN_ASSIGN_PRIMARY = 0x0001;
private const int GENERIC_ALL_ACCESS = 0x10000000;
private const int STARTF_USESHOWWINDOW = 0x00000001;
private const int STARTF_FORCEONFEEDBACK = 0x00000040;
private const uint CREATE_UNICODE_ENVIRONMENT = 0x00000400;
private static bool LaunchProcessAsUser(string cmdLine, IntPtr token, IntPtr envBlock)
{
bool result = false;
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
SECURITY_ATTRIBUTES saProcess = new SECURITY_ATTRIBUTES();
SECURITY_ATTRIBUTES saThread = new SECURITY_ATTRIBUTES();
saProcess.nLength = (uint)Marshal.SizeOf(saProcess);
saThread.nLength = (uint)Marshal.SizeOf(saThread);
STARTUPINFO si = new STARTUPINFO();
si.cb = (uint)Marshal.SizeOf(si);
//if this member is NULL, the new process inherits the desktop
//and window station of its parent process. If this member is
//an empty string, the process does not inherit the desktop and
//window station of its parent process; instead, the system
//determines if a new desktop and window station need to be created.
//If the impersonated user already has a desktop, the system uses the
//existing desktop.
si.lpDesktop = #"WinSta0\Default"; //Modify as needed
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_FORCEONFEEDBACK;
si.wShowWindow = SW_SHOW;
//Set other si properties as required.
result = CreateProcessAsUser(
token,
null,
cmdLine,
ref saProcess,
ref saThread,
false,
CREATE_UNICODE_ENVIRONMENT,
envBlock,
null,
ref si,
out pi);
if (result == false)
{
int error = Marshal.GetLastWin32Error();
string message = String.Format("CreateProcessAsUser Error: {0}", error);
Debug.WriteLine(message);
}
return result;
}
private static IntPtr GetPrimaryToken(int processId)
{
IntPtr token = IntPtr.Zero;
IntPtr primaryToken = IntPtr.Zero;
bool retVal = false;
Process p = null;
try
{
p = Process.GetProcessById(processId);
}
catch (ArgumentException)
{
string details = String.Format("ProcessID {0} Not Available", processId);
Debug.WriteLine(details);
throw;
}
//Gets impersonation token
retVal = OpenProcessToken(p.Handle, TOKEN_DUPLICATE, ref token);
if (retVal == true)
{
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.nLength = (uint)Marshal.SizeOf(sa);
//Convert the impersonation token into Primary token
retVal = DuplicateTokenEx(
token,
TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY,
ref sa,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
(int)TOKEN_TYPE.TokenPrimary,
ref primaryToken);
//Close the Token that was previously opened.
CloseHandle(token);
if (retVal == false)
{
string message = String.Format("DuplicateTokenEx Error: {0}", Marshal.GetLastWin32Error());
Debug.WriteLine(message);
}
}
else
{
string message = String.Format("OpenProcessToken Error: {0}", Marshal.GetLastWin32Error());
Debug.WriteLine(message);
}
//We'll Close this token after it is used.
return primaryToken;
}
private static IntPtr GetEnvironmentBlock(IntPtr token)
{
IntPtr envBlock = IntPtr.Zero;
bool retVal = CreateEnvironmentBlock(ref envBlock, token, false);
if (retVal == false)
{
//Environment Block, things like common paths to My Documents etc.
//Will not be created if "false"
//It should not adversley affect CreateProcessAsUser.
string message = String.Format("CreateEnvironmentBlock Error: {0}", Marshal.GetLastWin32Error());
Debug.WriteLine(message);
}
return envBlock;
}
public static bool Launch(string appCmdLine /*,int processId*/)
{
bool ret = false;
//Either specify the processID explicitly
//Or try to get it from a process owned by the user.
//In this case assuming there is only one explorer.exe
Process[] ps = Process.GetProcessesByName("explorer");
int processId = -1;//=processId
if (ps.Length > 0)
{
processId = ps[0].Id;
}
if (processId > 1)
{
IntPtr token = GetPrimaryToken(processId);
if (token != IntPtr.Zero)
{
IntPtr envBlock = GetEnvironmentBlock(token);
ret = LaunchProcessAsUser(appCmdLine, token, envBlock);
if (envBlock != IntPtr.Zero)
DestroyEnvironmentBlock(envBlock);
CloseHandle(token);
}
}
return ret;
}
}
[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
}
to use above code.
ProcessAsUser.Launch("applicationlocation.exe");
or Simply you can try this.
In your Wpf App.cs code file.
protected override void OnExit(ExitEventArgs e)
{
base.OnExit(e);
System.Windows.Forms.Application.Restart();
}
But this solution will not guarentee that application will start again if closed. so i haved used the Windows Service one.
I tried to run clac.exe process before(or exactly when) windows(7 and xp) logon screen is shown.
I tried the gpedit.msc method(add calc.exe to Startup), onLogin/onLogout works only.
Then I created a new windows service,
code (most of my code from: Running a Form in Windows Logon Screen C#):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Runtime.InteropServices;
namespace WindowsService2
{
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
[DllImport("Kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.U4)]
public static extern int WTSGetActiveConsoleSessionId();
[DllImport("wtsapi32.dll", SetLastError = true)]
static extern bool WTSQueryUserToken(UInt32 sessionId, out IntPtr Token);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private extern static bool DuplicateTokenEx(
IntPtr hExistingToken,
uint dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpTokenAttributes,
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
TOKEN_TYPE TokenType,
out IntPtr phNewToken);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool CreateProcessAsUser(
IntPtr hToken,
string lpApplicationName,
string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool AdjustTokenPrivileges(IntPtr tokenhandle,
[MarshalAs(UnmanagedType.Bool)] bool disableAllPrivileges,
[MarshalAs(UnmanagedType.Struct)]ref TOKEN_PRIVILEGES newstate,
uint bufferlength, IntPtr previousState, IntPtr returnlength);
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool OpenProcessToken(IntPtr ProcessHandle,
UInt32 DesiredAccess, out IntPtr TokenHandle);
public const UInt32 STANDARD_RIGHTS_REQUIRED = 0x000F0000;
public const UInt32 STANDARD_RIGHTS_READ = 0x00020000;
public const UInt32 TOKEN_ASSIGN_PRIMARY = 0x0001;
public const UInt32 TOKEN_DUPLICATE = 0x0002;
public const UInt32 TOKEN_IMPERSONATE = 0x0004;
public const UInt32 TOKEN_QUERY = 0x0008;
public const UInt32 TOKEN_QUERY_SOURCE = 0x0010;
public const UInt32 TOKEN_ADJUST_PRIVILEGES = 0x0020;
public const UInt32 TOKEN_ADJUST_GROUPS = 0x0040;
public const UInt32 TOKEN_ADJUST_DEFAULT = 0x0080;
public const UInt32 TOKEN_ADJUST_SESSIONID = 0x0100;
public const UInt32 TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);
public const UInt32 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);
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous,
SecurityIdentification,
SecurityImpersonation,
SecurityDelegation
}
public enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation
}
[StructLayout(LayoutKind.Sequential)]
public struct TOKEN_PRIVILEGES
{
public UInt32 PrivilegeCount;
public LUID Luid;
public UInt32 Attributes;
public LUID_AND_ATTRIBUTES[] Privileges;
}
[StructLayout(LayoutKind.Sequential)]
public struct LUID
{
public uint LowPart;
public int HighPart;
}
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool LookupPrivilegeValue(string lpSystemName, string lpName,
out LUID lpLuid);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
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;
}
[StructLayout(LayoutKind.Sequential)]
internal struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[Flags]
enum CreateProcessFlags : uint
{
DEBUG_PROCESS = 0x00000001,
DEBUG_ONLY_THIS_PROCESS = 0x00000002,
CREATE_SUSPENDED = 0x00000004,
DETACHED_PROCESS = 0x00000008,
CREATE_NEW_CONSOLE = 0x00000010,
NORMAL_PRIORITY_CLASS = 0x00000020,
IDLE_PRIORITY_CLASS = 0x00000040,
HIGH_PRIORITY_CLASS = 0x00000080,
REALTIME_PRIORITY_CLASS = 0x00000100,
CREATE_NEW_PROCESS_GROUP = 0x00000200,
CREATE_UNICODE_ENVIRONMENT = 0x00000400,
CREATE_SEPARATE_WOW_VDM = 0x00000800,
CREATE_SHARED_WOW_VDM = 0x00001000,
CREATE_FORCEDOS = 0x00002000,
BELOW_NORMAL_PRIORITY_CLASS = 0x00004000,
ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000,
INHERIT_PARENT_AFFINITY = 0x00010000,
INHERIT_CALLER_PRIORITY = 0x00020000,
CREATE_PROTECTED_PROCESS = 0x00040000,
EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
PROCESS_MODE_BACKGROUND_BEGIN = 0x00100000,
PROCESS_MODE_BACKGROUND_END = 0x00200000,
CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
CREATE_DEFAULT_ERROR_MODE = 0x04000000,
CREATE_NO_WINDOW = 0x08000000,
PROFILE_USER = 0x10000000,
PROFILE_KERNEL = 0x20000000,
PROFILE_SERVER = 0x40000000,
CREATE_IGNORE_SYSTEM_DEFAULT = 0x80000000,
}
[StructLayout(LayoutKind.Sequential)]
public struct LUID_AND_ATTRIBUTES
{
public LUID Luid;
public UInt32 Attributes;
}
public class RunProcess
{
public void log(string error)
{
throw new Exception(error);
}
public void StartProcess(string pathOrName)
{
Process winLogon = null;
foreach (Process p in Process.GetProcesses())
{
if (p.ProcessName.Contains("winlogon"))
{
winLogon = p;
break;
}
}
// grab the winlogon's token
IntPtr userToken = IntPtr.Zero;
if (!OpenProcessToken(winLogon.Handle, TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, out userToken))
{
log("ERROR: OpenProcessToken returned false - " + Marshal.GetLastWin32Error());
}
WTSQueryUserToken((uint)WTSGetActiveConsoleSessionId(), out userToken);
// create a new token
IntPtr newToken = IntPtr.Zero;
SECURITY_ATTRIBUTES tokenAttributes = new SECURITY_ATTRIBUTES();
tokenAttributes.nLength = Marshal.SizeOf(tokenAttributes);
SECURITY_ATTRIBUTES threadAttributes = new SECURITY_ATTRIBUTES();
threadAttributes.nLength = Marshal.SizeOf(threadAttributes);
// duplicate the winlogon token to the new token
if (!DuplicateTokenEx(userToken, 0x10000000, ref tokenAttributes, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
TOKEN_TYPE.TokenImpersonation, out newToken))
{
log("ERROR: DuplicateTokenEx returned false - " + Marshal.GetLastWin32Error());
}
TOKEN_PRIVILEGES tokPrivs = new TOKEN_PRIVILEGES();
tokPrivs.PrivilegeCount = 1;
LUID seDebugNameValue = new LUID();
if (!LookupPrivilegeValue(null, "SeDebugPrivilege", out seDebugNameValue))
{
log("ERROR: LookupPrivilegeValue returned false - " + Marshal.GetLastWin32Error());
}
tokPrivs.Privileges = new LUID_AND_ATTRIBUTES[1];
tokPrivs.Privileges[0].Luid = seDebugNameValue;
tokPrivs.Privileges[0].Attributes = 0x00000002;
if (!AdjustTokenPrivileges(newToken, false, ref tokPrivs, 0, IntPtr.Zero, IntPtr.Zero))
{
log("ERROR: AdjustTokenPrivileges returned false - " + Marshal.GetLastWin32Error());
}
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = "Winsta0\\Winlogon";
// start the process using the new token
if (!CreateProcessAsUser(newToken, "calc.exe", null, ref tokenAttributes, ref threadAttributes,true, (uint)CreateProcessFlags.CREATE_NEW_CONSOLE | (uint)CreateProcessFlags.INHERIT_CALLER_PRIORITY, IntPtr.Zero,"C:\\Windows\\System32", ref si, out pi))
{
log("ERROR: CreateProcessAsUser returned false - " + Marshal.GetLastWin32Error());
}
Process _p = Process.GetProcessById(pi.dwProcessId);
if (_p != null)
{
log("Process " + _p.Id + " Name " + _p.ProcessName);
}
else
{
log("Not Found");
}
}
}
RunProcess r = new RunProcess();
protected override void OnStart(string[] args)
{
r.StartProcess("calc.exe");
}
protected override void OnStop()
{
r.log("Stoped");
}
}
}
I installed the service by this line:
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\installutil.exe" "c:\myservice.exe"
and now I did restart.
And then I checked if the process in running when the logon screen is shown and then I found out that there is no calculator window and there is no process named calc running.
And then I saw that "WindowsService2" is not running (on the taskmgr).
So I think that it can be fixed (I will not give up so fast, i have to finish it today), the question is:
Why its not working, what i need to do now to check why its not working?
I prefer:
There is any other way(or ways) to run process before logon screen(XP and Windows 7)?
(good answer is good example plus good explanation) :)
Edit:
the solution is in the installtion,
the installation log:
Installing assembly 'c:\WindowsService2.exe'.
Affected parameters are:
logtoconsole =
logfile = c:\WindowsService2.InstallLog
assemblypath = c:\WindowsService2.exe
No public installers with the RunInstallerAttribute.Yes attribute could be found in the c:\WindowsService2.exe assembly.
Committing assembly 'c:\WindowsService2.exe'.
Affected parameters are:
logtoconsole =
logfile = c:\WindowsService2.InstallLog
assemblypath = c:\WindowsService2.exe
No public installers with the RunInstallerAttribute.Yes attribute could be found in the c:\WindowsService2.exe assembly.
Remove InstallState file because there are no installers.
cant install because:
No public installers with the RunInstallerAttribute.Yes attribute could be found in the c:\WindowsService2.exe assembly.
what should i do now? :S
(i tried public static readonly RunInstallerAttribute Yes; and i even tried to run the cmd.exe as administrator)
to start your application before start up there are three options:
you can add a new registry value by using mscorlib.dll(RegistryKey Class) functions and classes:
RegistryKey add = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
add.SetValue("Your App Name", "\"" + Application.ExecutablePath.ToString() + "\"");
other locations:
HKLM\Software\Microsoft\Windows\CurrentVersion\Run
HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce
HKLM\Software\Microsoft\Windows\CurrentVersion\RunServices
HKLM\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce
HKCU\Software\Microsoft\Windows\CurrentVersion\Run
HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce
HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnceEx
you can add youre application manually:
gpedit.msc->windows settings->script files(startup/shutdown)->startup->add..(choose youre application assembly file)
(all gpedit values are saved in the registry, you can also add your application assembly path by using GPMGMTLib(to make youre application more convenient))
you can move or copy youre application assembly file to:
Environment.GetFolderPath(Environment.SpecialFolder.Startup)