我有一个在系统帐户中运行的服务,它应该以用户模式启动应用程序。在 c++ 中没有问题,但在 .NET 中我有很多。
最后我复制了当前用户会话的用户令牌(explorer.exe)
该应用程序似乎以用户模式启动,但在到达我的代码的第一行之前直接崩溃;)
当我直接或通过我的服务调用流程时,我使用流程资源管理器检查了差异。
似乎.Net程序集的加载不起作用,但我不知道为什么(或者唯一的原因是因为我复制了一个非.NET令牌,但读取所有应用程序启动为非.NET版本并且Windows正在检测它在 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);
}