- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在用 C# 为一套技术支持工具编写一个远程控制应用程序。一切正常,除了我无法使用 SendInput 到 Winlogon 桌面。我成功地检测到从 Default 到 Winlogon 的变化,并且我能够切换到它并捕获屏幕截图。它只是不接受 SendInput 函数。我知道这是可能的,因为 TeamViewer 做到了,而且他们的 list 中没有 uiAccess=true 。他们似乎在使用与我相同的过程。
简而言之,这是我正在做的事情:安装服务。服务监听连接请求。服务使用 CreateProcessAsUser 和来自 winlogon.exe 的复制访问 token 在用户 session 中启动新进程。查看器连接到新进程。
任何人都可以确定缺少什么来让新进程访问 SendInput 到 winlogon 吗?这是我用来从服务启动新进程的代码。接下来是我用来检测 Winlogon 桌面更改并切换到它的代码。
public static bool OpenProcessAsSystem(string applicationName, out PROCESS_INFORMATION procInfo)
{
try
{
uint winlogonPid = 0;
IntPtr hUserTokenDup = IntPtr.Zero, hPToken = IntPtr.Zero, hProcess = IntPtr.Zero;
procInfo = new PROCESS_INFORMATION();
// Obtain session ID for active session.
uint dwSessionId = Kernel32.WTSGetActiveConsoleSessionId();
// Check for RDP session. If active, use that session ID instead.
var rdpSessionID = GetRDPSession();
if (rdpSessionID > 0)
{
dwSessionId = rdpSessionID;
}
// Obtain the process ID of the winlogon process that is running within the currently active session.
Process[] processes = Process.GetProcessesByName("winlogon");
foreach (Process p in processes)
{
if ((uint)p.SessionId == dwSessionId)
{
winlogonPid = (uint)p.Id;
}
}
// Obtain a handle to the winlogon process.
hProcess = Kernel32.OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid);
// Obtain a handle to the access token of the winlogon process.
if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hPToken))
{
Kernel32.CloseHandle(hProcess);
return false;
}
// Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser.
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.Length = Marshal.SizeOf(sa);
// Copy the access token of the winlogon process; the newly created token will be a primary token.
if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary, ref hUserTokenDup))
{
Kernel32.CloseHandle(hProcess);
Kernel32.CloseHandle(hPToken);
return false;
}
// By default, CreateProcessAsUser creates a process on a non-interactive window station, meaning
// the window station has a desktop that is invisible and the process is incapable of receiving
// user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user
// interaction with the new process.
STARTUPINFO si = new STARTUPINFO();
si.cb = (int)Marshal.SizeOf(si);
si.lpDesktop = @"winsta0\default"; // interactive window station parameter; basically this indicates that the process created can display a GUI on the desktop
// flags that specify the priority and creation method of the process
uint dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
// create a new process in the current user's logon session
bool result = CreateProcessAsUser(hUserTokenDup, // client's access token
null, // file to execute
applicationName, // command line
ref sa, // pointer to process SECURITY_ATTRIBUTES
ref sa, // pointer to thread SECURITY_ATTRIBUTES
false, // handles are not inheritable
dwCreationFlags, // creation flags
IntPtr.Zero, // pointer to new environment block
null, // name of current directory
ref si, // pointer to STARTUPINFO structure
out procInfo // receives information about new process
);
// invalidate the handles
Kernel32.CloseHandle(hProcess);
Kernel32.CloseHandle(hPToken);
Kernel32.CloseHandle(hUserTokenDup);
return result;
}
catch
{
procInfo = new PROCESS_INFORMATION() { };
return false;
}
}
public static uint GetRDPSession()
{
IntPtr ppSessionInfo = IntPtr.Zero;
Int32 count = 0;
Int32 retval = WTSAPI32.WTSEnumerateSessions(WTSAPI32.WTS_CURRENT_SERVER_HANDLE, 0, 1, ref ppSessionInfo, ref count);
Int32 dataSize = Marshal.SizeOf(typeof(WTSAPI32.WTS_SESSION_INFO));
var sessList = new List<WTSAPI32.WTS_SESSION_INFO>();
Int64 current = (int)ppSessionInfo;
if (retval != 0)
{
for (int i = 0; i < count; i++)
{
WTSAPI32.WTS_SESSION_INFO sessInf = (WTSAPI32.WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current, typeof(WTSAPI32.WTS_SESSION_INFO));
current += dataSize;
sessList.Add(sessInf);
}
}
uint retVal = 0;
var rdpSession = sessList.Find(ses => ses.pWinStationName.ToLower().Contains("rdp") && ses.State == 0);
if (sessList.Exists(ses => ses.pWinStationName.ToLower().Contains("rdp") && ses.State == 0))
{
retVal = (uint)rdpSession.SessionID;
}
return retVal;
}
这是我用来捕获屏幕、检测桌面变化并切换到它的工具。
var hWnd = User32.GetDesktopWindow();
var hDC = User32.GetWindowDC(hWnd);
var graphDC = graphic.GetHdc();
var copyResult = GDI32.BitBlt(graphDC, 0, 0, totalWidth, totalHeight, hDC, 0, 0, GDI32.TernaryRasterOperations.SRCCOPY | GDI32.TernaryRasterOperations.CAPTUREBLT);
// Change to input desktop if copy fails.
if (!copyResult)
{
var inputDesktop = User32.OpenInputDesktop();
if (User32.SetThreadDesktop(inputDesktop) == false)
{
graphic.Clear(System.Drawing.Color.White);
var font = new Font(FontFamily.GenericSansSerif, 30, System.Drawing.FontStyle.Bold);
graphic.DrawString("Waiting for screen capture...", font, Brushes.Black, new PointF((totalWidth / 2), totalHeight / 2), new StringFormat() { Alignment = StringAlignment.Center });
var error = Marshal.GetLastWin32Error();
writeToErrorLog(new Exception("Failed to open input desktop. Error: " + error.ToString()));
}
var dw = User32.GetDesktopWindow();
User32.SetActiveWindow(dw);
User32.SetForegroundWindow(dw);
User32.CloseDesktop(inputDesktop);
}
graphic.ReleaseHdc(graphDC);
User32.ReleaseDC(hWnd, hDC);
最佳答案
我让 SendInput 在登录桌面(以及 UAC 安全桌面)上工作。 SetThreadDesktop 不得授予您与最初在目标桌面上启动进程相同的权限。
因此,当我检测到桌面发生变化时,我没有调用 SetThreadDesktop,而是使用 CreateProcessAsUser 在新桌面中启动了另一个进程。然后我示意查看器切换并关闭当前进程。
编辑(多年后):我最终错了。您只需要确保当前线程在当前桌面上没有任何打开的窗口或 Hook 。由于这仅为调用线程(而非进程)设置桌面,其他线程也需要调用它。
关于c# - 如何使用 C#/pinvoke 将输入发送到 WinSta0\Winlogon 桌面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41924863/
我正在处理屏幕共享项目。但是我在捕获安全桌面时遇到了麻烦。我已经问过相关问题here也得到了答案 请通过上面的链接 正如 dymanoid 所建议的那样。我正在使用 PsExec exe 来捕获安全桌
我有一个应用程序在 Windows 7 的 Winlogon 桌面上运行。我需要通过单击该应用程序的按钮切换到用户桌面。我们可以通过ctrl+shift+esc手动切换到用户桌面。但是热键被另一个应用
我正在编写一个远程桌面应用程序,如 TeamViewer 在 Windows 7 (x64) 和 Windows 8 (x64) 上使用 C++。 1。是什么让我卡住了 我已经使用 SendInput
我成功使用了SendSAS在服务(本地系统帐户)中。我在服务启动四秒后调用 API。似乎无论启动过程的持续时间如何,Windows 都会设法缓存(某种程度上)调用:相同的代码最终在开机几秒钟后在一台快
我有一个 Windows 服务,我想使用该服务以编程方式解锁工作站,使用帐户用户名和密码。 本文https://technet.microsoft.com/en-us/library/dn751047
我需要在用户解锁计算机时运行应用程序。这可以在 Win 7 中使用常规任务计划程序顺畅地工作。对于 XP——我创建了一个 C++ DLL 来执行此操作。这似乎工作得很好,除了它是在系统帐户下执行的(因
当引导过程完成或用户登录时,我能否获得对内核驱动程序的事件回调? 最佳答案 简单的答案是否定的。 长答案是肯定的,但为什么呢? 我会回答第二部分,因为它更容易。您可以轻松注册以在启动任何进程时接收通知
我一直在创建一个 Credential Provider DLL,它在允许登录之前通过 Internet 进行身份验证。但是,这并没有像我预期的那样有效,因为我的 WinHTTP 请求没有被发送。我已
是否有 API 可用于 Windows 应用程序为登录用户获取 Azure AD token ?那么登录后 token 可以被应用程序访问吗? 最佳答案 是的,如果您正在构建 UWP 应用程序,则可以
是否有 API 可用于 Windows 应用程序为登录用户获取 Azure AD token ?那么登录后 token 可以被应用程序访问吗? 最佳答案 是的,如果您正在构建 UWP 应用程序,则可以
我需要在 WinXP/Win7/10 中捕获 winlogon 屏幕。对于 WinXP,我使用的是镜像驱动程序和标准方法,如下所示: ... extern "C" __declspec(dllexpo
我需要为 Windows 登录创建自己的 UI。我正在使用 Windows 7 Embedded 执行此操作,并且我可以完全访问图像创建和修改。 通过研究我了解到 winlogon.exe 是由 sm
我正在用 C# 为一套技术支持工具编写一个远程控制应用程序。一切正常,除了我无法使用 SendInput 到 Winlogon 桌面。我成功地检测到从 Default 到 Winlogon 的变化,并
我想在系统内运行的任何服务上发生某些事件时自动登录特定用户。CredentialProvider 用于获取用户和密码,但无法完成自动登录。所以我想在凭证提供程序图 block 上的 x,y 位置调用
我正在尝试创建一个进程来启动需要 UI 的应用程序。所以它不能在 session 0 中。我的想法是获取当前登录用户的 winlogon.exe 的进程 ID。通过这种方式,我可以复制 winlogo
我是一名优秀的程序员,十分优秀!