У меня есть служба, которая запускается в Системной учетной записи, которая должна запускать приложение в пользовательском режиме. В C++ проблем нет, но в .NET у меня было много.Ошибка приложения .NET после createprocessasuser
В конце я дублировать маркер пользователя текущего сеанса пользователя (explorer.exe)
приложение, кажется, начинается в пользовательском режиме, а непосредственно падает до первой строки моего кода достигается;)
Я проверил с исследователем процесса различия, когда я вызываю процесс напрямую или через мой сервис.
Похоже, что загрузка сборок .Net не работает, но я понятия не имею, почему (или единственный из них - это то, что я дублирую нечетный токен .NET, но так как прочитано все приложения запускаются как версии не .NET, окна обнаруживают его во lload, что собрания должны быть загружены)
Моего код:
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);
}
Изображения можно найти здесь: [Нормальный процесс] (http://vqm.funk-informationstechnik.de/Normalprocess.jpg) [Созданный процесс с системной учетной записью] (http://vqm.funk-informationstechnik.de/Createprocessasuser.jpg) –
Используйте переключатель '' '' 'ProcDump' '(https://technet.microsoft.com/en-us/sysinternals/dd996900), чтобы установите его, чтобы выполнить 'dmp', когда процесс выйдет из строя. Открыть в VS или Windbg. – Mitch