在 Windows 7 欢迎屏幕上运行进程 [英] Running a process at the Windows 7 Welcome Screen

查看:28
本文介绍了在 Windows 7 欢迎屏幕上运行进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以这是独家新闻:

不久前我编写了一个小型 C# 应用程序,它显示主机名、IP 地址、成像日期、解冻状态(我们使用 DeepFreeze)、当前域和当前日期/时间,以显示在我们 Windows 的欢迎屏幕上7台实验室机器.这是为了替换我们之前在启动时静态设置并实际将文本嵌入到背景中的信息块,用一些更动态和更实用的东西.该应用使用 Timer 每秒更新 ip 地址、deepfreeze 状态和时钟,并检查用户是否已登录并在检测到此类情况时自行杀死.

I wrote a tiny C# app a while back that displays the hostname, ip address, imaged date, thaw status (we use DeepFreeze), current domain, and the current date/time, to display on the welcome screen of our Windows 7 lab machines. This was to replace our previous information block, which was set statically at startup and actually embedded text into the background, with something a little more dynamic and functional. The app uses a Timer to update the ip address, deepfreeze status, and clock every second, and it checks to see if a user has logged in and kills itself when it detects such a condition.

如果我们只是运行它,通过我们的启动脚本(通过组策略设置),它会保持脚本打开并且机器永远不会进入登录提示.如果我们使用诸如 start 或 cmd 命令之类的命令在单独的 shell/进程下启动它,它会一直运行直到启动脚本完成,此时 Windows 似乎会清理脚本的所有子进程.我们目前可以绕过使用 psexec -s -d -i -x 将其关闭,这让它在启动脚本完成后持续存在,但速度可能非常慢,添加之间的任何位置比我们的启动时间快 5 秒和 1 多分钟.

If we just run it, via our startup script (set via group policy), it holds the script open and the machine never makes it to the login prompt. If we use something like the start or cmd commands to start it off under a separate shell/process, it runs until the startup script finishes, at which point Windows seems to clean up any and all child processes of the script. We're currently able to bypass that using psexec -s -d -i -x to fire it off, which lets it persist after the startup script is completed, but can be incredibly slow, adding anywhere between 5 seconds and over a minute to our startup time.

我们已经尝试使用另一个 C# 应用程序来启动进程,通过 Process 类,使用 WMI 调用(Win32_Process 和 Win32_ProcessStartup)和各种启动标志等,但都以相同的脚本完成结果和信息结束阻止进程被杀死.我尝试将应用重写为服务,但服务从未设计为与桌面交互,更不用说与登录窗口交互了,而且让事情在正确的上下文中运行似乎从未真正奏效.

We have experimented with using another C# app to start the process, via the Process class, using WMI Calls (Win32_Process and Win32_ProcessStartup) with various startup flags, etc, but all end with the same result of the script finishing and the info block process getting killed. I tinkered with rewriting the app as a service, but services were never designed to interact with the desktop, let alone the login window, and getting things operating in the right context never really seemed to work out.

所以对于这个问题:有没有人有一个很好的方法来完成这个?启动一个任务,使其独立于启动脚本并在欢迎屏幕上运行?

So for the question: Does anybody have a good way to accomplish this? Launch a task so that it would be independent of the startup script and run on top of the welcome screen?

推荐答案

这可以通过大量的 Win32 API 调用来完成.我已经设法在 Winlogon 桌面上安装了一个带有 GUI 的程序(在有人问之前,它不是交互式 GUI).基本上,您需要以 SYSTEM 身份运行加载程序进程,然后它会生成新进程.由于您很可能希望此进程在启动时运行,因此您可以使用任务调度程序以 SYSTEM 身份运行加载程序,也可以使用服务来执行相同的操作.我目前正在使用一项服务,但我尝试使用任务调度程序,它确实工作得很好.

This can be done through a lot of Win32 API calls. I have managed to get a program with a GUI onto the Winlogon desktop (before anyone asks, it's not an interactive GUI). Basically you need to run a loader process as SYSTEM, which will then spawn the new process. Since you most likely want this process to run on start up, you can either use the task scheduler to run the loader as SYSTEM or you can use a service to do the same thing. I'm currently using a service, but I tried using the task scheduler and it did work just fine.

简短摘要:

  1. 获取 Winlogon.exe 进程(作为进程)
  2. 使用进程的 .handle 使用 OpenProcessToken 获取 winlogon 的令牌
  3. 创建一个新令牌并将 winlogon 令牌复制到它
  4. 提升token的权限
  5. 使用 CreateProcessAsUser 创建进程,确保将 lpDesktop 设置为Winsta0\Winlogon"并使用您创建的令牌.

代码示例:

        // grab the winlogon process
        Process winLogon = null;
        foreach (Process p in Process.GetProcesses()) {
            if (p.ProcessName.Contains("winlogon")) {
                winLogon = p;
                break;
            }
        }
        // grab the winlogon's token
        IntPtr userToken = IntPtr.Zero;
        if (!OpenProcessToken(winLogon.Handle, TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, out userToken)) {
            log("ERROR: OpenProcessToken returned false - " + Marshal.GetLastWin32Error());
        }

        // create a new token
        IntPtr newToken = IntPtr.Zero;
        SECURITY_ATTRIBUTES tokenAttributes = new SECURITY_ATTRIBUTES();
        tokenAttributes.nLength = Marshal.SizeOf(tokenAttributes);
        SECURITY_ATTRIBUTES threadAttributes = new SECURITY_ATTRIBUTES();
        threadAttributes.nLength = Marshal.SizeOf(threadAttributes);
        // duplicate the winlogon token to the new token
        if (!DuplicateTokenEx(userToken, 0x10000000, ref tokenAttributes, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
            TOKEN_TYPE.TokenImpersonation, out newToken)) {
            log("ERROR: DuplicateTokenEx returned false - " + Marshal.GetLastWin32Error());
        }
        TOKEN_PRIVILEGES tokPrivs = new TOKEN_PRIVILEGES();
        tokPrivs.PrivilegeCount = 1;
        LUID seDebugNameValue = new LUID();
        if (!LookupPrivilegeValue(null, SE_DEBUG_NAME, out seDebugNameValue)) {
            log("ERROR: LookupPrivilegeValue returned false - " + Marshal.GetLastWin32Error());
        }
        tokPrivs.Privileges = new LUID_AND_ATTRIBUTES[1];
        tokPrivs.Privileges[0].Luid = seDebugNameValue;
        tokPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        // escalate the new token's privileges
        if (!AdjustTokenPrivileges(newToken, false, ref tokPrivs, 0, IntPtr.Zero, IntPtr.Zero)) {
            log("ERROR: AdjustTokenPrivileges returned false - " + Marshal.GetLastWin32Error());
        }
        PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
        STARTUPINFO si = new STARTUPINFO();
        si.cb = Marshal.SizeOf(si);
        si.lpDesktop = "Winsta0\\Winlogon";
        // start the process using the new token
        if (!CreateProcessAsUser(newToken, process, process, ref tokenAttributes, ref threadAttributes,
            true, (uint)CreateProcessFlags.CREATE_NEW_CONSOLE | (uint)CreateProcessFlags.INHERIT_CALLER_PRIORITY, IntPtr.Zero,
            logInfoDir, ref si, out pi)) {
            log("ERROR: CreateProcessAsUser returned false - " + Marshal.GetLastWin32Error());
        }

        Process _p = Process.GetProcessById(pi.dwProcessId);
        if (_p != null) {
            log("Process " + _p.Id + " Name " + _p.ProcessName);
        } else {
            log("Process not found");
        }

这篇关于在 Windows 7 欢迎屏幕上运行进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆