我有一个以普通用户身份运行的应用程序,以及作为本地系统运行的服务.我希望应用程序能够告诉服务再次启动应用程序,一旦服务完成了其他一些事情.(因此,当服务正在执行"事物"时,应用程序将不会运行.)为了使服务能够以首次启动它的用户启动应用程序,它需要一个用户令牌.应用程序在退出之前将令牌发送到服务,但是当服务尝试使用它时,令牌/句柄无效.(它首先使用DuplicateTokenEx来获取主令牌.)
用户令牌是否始终仅在调用OpenProcessToken的进程中有效?
还有其他方法可以做到吗?我不希望用户必须使用logonuser"登录"应用程序.那只是愚蠢的.我想我可以将"explorer.exe"的进程句柄从应用程序移交给服务,该服务可以用来获取用户令牌,但这需要PROCESS DUP HANDLE访问权限.我对这个解决方案并不感到兴奋,但也许是这样做的方法呢?
在服务中,我尝试使用以下代码来启动程序:
HANDLE hPipe;
HANDLE hToken;
PROFILEINFO stProfileInfo;
char szUserName[64];
DWORD dwUserNameSize = 64;
// Take the identity of the client
ImpersonateNamedPipeClient(hPipe);
// Retrieve the user name (DOMAIN\USER)
GetUserNameEx(NameSamCompatible,szUserName,&dwUserNameSize);
// Get the impersonation token
OpenThreadToken(GetCurrentThread(),TOKEN_ALL_ACCESS,TRUE,&hToken);
// Load the user's profile
ZeroMemory(&stProfileInfo,sizeof(PROFILEINFO));
stProfileInfo.dwSize = sizeof(PROFILEINFO);
stProfileInfo.dwFlags = PI_NOUI;
stProfileInfo.lpUserName = szUserName;
LoadUserProfile(hToken,&stProfileInfo);
Run Code Online (Sandbox Code Playgroud)
不幸的是,电话LoadUserProfile失败了GetLastError=5 (access denied).在userenv.log中,我可以找到:
USERENV LoadUserProfile: Yes, we can impersonate the user. Running as self
USERENV LoadUserProfile: Entering, hToken = <0xc8>, lpProfileInfo = 0xb30aa4
USERENV LoadUserProfile: lpProfileInfo->dwFlags …Run Code Online (Sandbox Code Playgroud) 我正在使用 CreateProcessAsUser 从服务运行进程,并将标准输出重定向到命名管道。但是当我尝试从命名管道中读取时,它会挂在读取上并且永远不会返回。我在一个单独的任务中尝试了这个(目前在下面实现)并且只是在主进程中读取它。我还尝试使用 C# AnonymousPipeServerStream 类(请参阅下面注释掉的代码),但还是挂起。
任何想法我缺少什么?谢谢!
Native.SECURITY_ATTRIBUTES sa = new Native.SECURITY_ATTRIBUTES();
processAttributes.nLength = Marshal.SizeOf(sa);
processAttributes.lpSecurityDescriptor = IntPtr.Zero;
processAttributes.bInheritHandle = 0;
//AnonymousPipeServerStream pipeServer = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable);
IntPtr readPipe = IntPtr.Zero;
IntPtr subProcessPipe = IntPtr.Zero;
if(!Native.CreatePipe(out readPipe, out subProcessPipe,ref sa, 0x0001))
{
throw new Exception("createpipe gave error: " + Marshal.GetLastWin32Error());
}
log.InfoFormat("pipe created");
Task readPipeTask = Task.Factory.StartNew(() =>
{
log.InfoFormat("startingtask");
var readBuff = new byte[BufferSize];
uint bytesRead = 0;
bool retval;
while (true)
{
retval = Native.ReadFile(readPipe, readBuff, BufferSize, out …Run Code Online (Sandbox Code Playgroud) 我使用 LogonUser 获取主用户令牌,然后使用 CreateProcessAsUser API 来创建进程。但我收到错误代码 6。不确定是什么问题。下面是代码。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LogOnUserTestWindows
{
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Principal;
class Program
{
// Define the Windows LogonUser and CloseHandle functions.
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool LogonUser(String username, String domain, IntPtr password,
int logonType, int logonProvider, ref IntPtr token);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);
private enum SW
{
SW_HIDE …Run Code Online (Sandbox Code Playgroud) 我们有一个作为 LocalSystem 运行的服务。我们使用 CreateProcessAsUser 和 LoadUserProfile 以特定用户的身份启动工作应用程序。效果很好。但是如果我们尝试使用 CreateProcessWithTokenW 来避免显式加载和管理用户配置文件,则会失败,并且会在事件日志中记录以下内容:
Faulting application name: SomeApp.exe, version: 1.0.0.0, time stamp: 0x578a7819
Faulting module name: KERNELBASE.dll, version: 10.0.10586.494, time stamp: 0x5775e4c5
Exception code: 0xc06d007e
Fault offset: 0x0000000000071f28
Faulting process id: 0x24e4
Faulting application start time: 0x01d1df8d223316a6
Faulting application path: C:\SomePath\SomeApp.exe
Faulting module path: C:\Windows\system32\KERNELBASE.dll
Report Id: a2310c0d-7ddf-4241-92c9-de03e8de71e8
Faulting package full name:
Faulting package-relative application ID:
Run Code Online (Sandbox Code Playgroud)
有没有让 CreateProcessWithTokenW 工作的技巧?