i have a service which is running in the System account, which should start a application in user mode. In c++ no problem but in .NET i had a lot.
At the end i duplicate the user token of the current user session (explorer.exe)
The application seems to start in user mode but directly crashes before the first line of my code is reached;)
I checked with process explorer the differences when i call the process directly or over my service.
It seems that the loading of the .Net assemblies does not work but i have no idea why (or the only one is because i duplicate a not .NET token, but as read all application start as non .NET versions and windows is detecting it during lload that the assemblies has to be loaded)
My code:
var adjustToken = IntPtr.Zero;
int lastError;
if (
!NativeMethods.OpenProcessToken(
NativeMethods.GetCurrentProcess(),
ProcessTools.TokenAdjustPrivileges | ProcessTools.TokenQuery,
ref adjustToken))
{
lastError = Marshal.GetLastWin32Error();
throw new Exception($"OpenProcessToken() failed, error = {lastError}.");
}
try
{
Luid luidSeDebugNameValue;
if (!NativeMethods.LookupPrivilegeValue(null, ProcessTools.SeDebugName, out luidSeDebugNameValue))
{
lastError = Marshal.GetLastWin32Error();
throw new Exception(
$"LookupPrivilegeValue() failed, error = {lastError}. SeDebugPrivilege is not available");
}
var tokenPrivileges = new TokenPrivileges
{
PrivilegeCount = 1,
Luid = luidSeDebugNameValue,
Attributes = ProcessTools.SePrivilegeEnabled
};
if (
!NativeMethods.AdjustTokenPrivileges(
adjustToken,
false,
ref tokenPrivileges,
0,
IntPtr.Zero,
IntPtr.Zero))
{
lastError = Marshal.GetLastWin32Error();
throw new Exception($"AdjustTokenPrivileges() failed, error = {lastError}.");
}
else
{
var userTokenDup = IntPtr.Zero;
var token = IntPtr.Zero;
var processes = Process.GetProcessesByName("explorer");
var process = ProcessTools.OpenProcess(
processes.FirstOrDefault(),
ProcessAccessFlags.All,
out lastError);
if (process == IntPtr.Zero)
{
throw new Exception($"Can't open process. Last error = {lastError}.");
}
try
{
if (!NativeMethods.OpenProcessToken(process, ProcessTools.TokenDuplicate, ref token))
{
lastError = Marshal.GetLastWin32Error();
throw new Exception($"Can't open process token. Last error = {lastError}.");
}
var sa = new SecurityAttributes();
sa.Length = Marshal.SizeOf(sa);
try
{
if (
!NativeMethods.DuplicateTokenEx(
token,
ProcessTools.TokenAllAccess,
ref sa,
(int)
SecurityImpersonationLevel
.SecurityImpersonation,
(int) TokenType.TokenPrimary,
ref userTokenDup))
{
lastError = Marshal.GetLastWin32Error();
throw new Exception($"Can't duplicate process token. Last error = {lastError}.");
}
var si = new Startupinfo();
si.Cbyte = Marshal.SizeOf(si);
si.Desktop = @"winsta0\default";
var inputHandle =
NativeMethods.GetStdHandle(NativeMethods.ConsoleStandardHandle.StandardInputHandle);
var outputHandle =
NativeMethods.GetStdHandle(NativeMethods.ConsoleStandardHandle.StandardInputHandle);
var errHandle =
NativeMethods.GetStdHandle(NativeMethods.ConsoleStandardHandle.StandardInputHandle);
if (errHandle != IntPtr.Zero)
{
si.StandardError = errHandle;
}
if (outputHandle != IntPtr.Zero)
{
si.StandardOutput = outputHandle;
}
if (inputHandle != IntPtr.Zero)
{
si.StandardInput = inputHandle;
}
const int CreationFlags = ProcessTools.NormalPriorityClass | ProcessTools.CreateNewConsole;
var file = new FileInfo(applicationName);
var dir = file.Directory?.FullName;
ProcessInformation procInfo;
var result = NativeMethods.CreateProcessAsUser(
userTokenDup,
file.FullName,
arguments,
ref sa,
ref sa,
false,
CreationFlags,
IntPtr.Zero,
dir,
ref si,
out procInfo);
lastError = Marshal.GetLastWin32Error();
NativeMethods.CloseHandle(userTokenDup);
if (!result)
{
throw new Exception(
$"Could not create process in user interactive mode. Last error = {lastError}.");
}
if (milliseconds == 0)
{
return;
}
var res = NativeMethods.WaitForSingleObject(procInfo.Process, milliseconds);
if (res == ProcessTools.WaitTimeOut)
{
throw new Exception(
$"Process not started within = {milliseconds} seconds.");
}
}
finally
{
NativeMethods.CloseHandle(token);
}
}
finally
{
NativeMethods.CloseHandle(process);
}
}
}
finally
{
NativeMethods.CloseHandle(adjustToken);
}