在Windows 7欢迎屏幕上运行进程

pee*_*man 11 login-script windows-7

所以这是独家新闻:

我在前一段时间写了一个小小的C#应用​​程序,显示主机名,IP地址,图像日期,解冻状态(我们使用DeepFreeze),当前域和当前日期/时间,以显示在我们的Windows 7实验室机器的欢迎屏幕上.这是为了取代我们以前的信息块,它是在启动时静态设置的,实际上是嵌入到背景中的文本,带有更多动态和功能.该应用程序使用Timer来每秒更新IP地址,deepfreeze状态和时钟,并检查用户是否已登录并在检测到此类情况时自行终止.

如果我们只是通过我们的启动脚本(通过组策略设置)运行它,它会保持脚本打开,并且机器永远不会进入登录提示.如果我们使用类似start或cmd命令的东西在单独的shell /进程下启动它,它将运行直到启动脚本完成,此时Windows似乎清理脚本的所有子进程.我们现在能够绕过它psexec -s -d -i -x来启动它,这使得它在启动脚本完成后仍然存在,但可能非常慢,在我们的启动时间增加了5秒到一分钟之间.

我们已经尝试使用另一个C#应用程序来启动进程,通过Process类,使用WMI调用(Win32_Process和Win32_ProcessStartup)以及各种启动标志等,但所有结束都与脚本完成和信息块进程获得相同的结果杀害.我修改了将应用程序重写为服务,但服务从未设计为与桌面交互,更不用说登录窗口,并且在正确的上下文中运行操作似乎从未真正解决过.

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

小智 12

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

简短的摘要:

  1. 抓取Winlogon.exe进程(作为进程)
  2. 使用Process的.handle使用OpenProcessToken获取winlogon的标记
  3. 创建一个新令牌并将winlogon令牌复制到它
  4. 提升令牌的权限
  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");
        }
Run Code Online (Sandbox Code Playgroud)


Rei*_*man 6

这是"你真的需要一个很好的理由来做这个"问题之一.Microsoft非常努力地阻止在启动屏幕上运行的应用程序 - Windows中与登录屏幕交互的每一段代码都经过仔细的代码审查,因为在登录屏幕上运行的代码中的错误的安全后果是可怕的 - 如果你搞砸了甚至稍微提高,你将允许恶意软件进入计算机.

为什么要在登录屏幕上运行程序?也许有一种记录在案的方式并没有风险.

  • 以下是您运行的风险:您可以在桌面上运行UI,而一些聪明的学生会知道如何利用您的UI.他们现在在你的桌面上.他们重复实验室中的每台机器,现在它们都在你的实验室里.现在,一些域管理员在实验室中登录到计算机.现在,你聪明的学生0wns你的领域.一旦这个聪明的学生失去了你的领域,就会结束游戏.有解决方案:例如,我知道大学(和公司)每晚重新映像每台实验室计算机.但这些补救措施往往相当严苛. (3认同)
  • 他们需要什么样的信息,无法通过WMI远程检索?Windows拥有大量的管理信息,可以使用适用于支持和操作人员的WMI API来读取.他们需要的信息是否仅在物理控制台上可用? (2认同)
  • 从我坐的地方,我*试图帮助你解决问题.没有可靠的方法来做你想做的事情而不会给系统带来潜在的安全威胁,所以我试图找到一种替代机制,让你可以在不破坏系统安全功能的情况下检索所需的信息.大约每3个月,从内MSFT有人问我们内部的"窗口招数"别名类似的问题,答案总是一样的一个,我给 - 找到做你想要的东西,因为它是更安全的另一种方式*所有*我们的客户. (2认同)
  • 当用户对机器具有物理访问权限时,您的安全性已经受到损害.这个应用程序不会给我们带来*重大*网络威胁,这就是我们真正关心的.如果你说的话实际上是真的,那么无法以安全的方式运行这样的流程的事实真的说明了Windows安全性的"改进".不要让它变得更好,而只是限制人们可以做什么.这是一个让机器更加安全的想法:我们只需将它们从网络中拔出并取走键盘和鼠标即可. (2认同)

Sim*_*mon 6

我在C++中翻译了上面的代码,如果其他人需要它...注意我的代码部分有引用,但它可能有所帮助:

static bool StartProcess(LPCTSTR lpApplicationPath)
{
    CAutoGeneralHandle hWinlogonProcess = FindWinlogonProcess();
    if (hWinlogonProcess == INVALID_HANDLE_VALUE) 
    {
        DU_OutputDebugStringff(L"ERROR: Can't find the 'winlogon' process");
        return false;
    }

    CAutoGeneralHandle hUserToken;
    if (!OpenProcessToken(hWinlogonProcess, TOKEN_QUERY|TOKEN_IMPERSONATE|TOKEN_DUPLICATE, &hUserToken)) 
    {
        DU_OutputDebugStringff(L"ERROR: OpenProcessToken returned false (error %u)", GetLastError());
        return false;
    }

    // Create a new token
    SECURITY_ATTRIBUTES tokenAttributes = {0};
    tokenAttributes.nLength = sizeof tokenAttributes;

    SECURITY_ATTRIBUTES threadAttributes = {0};
    threadAttributes.nLength = sizeof threadAttributes;

    // Duplicate the winlogon token to the new token
    CAutoGeneralHandle hNewToken;
    if (!DuplicateTokenEx(hUserToken, 0x10000000, &tokenAttributes, 
            SECURITY_IMPERSONATION_LEVEL::SecurityImpersonation,
            TOKEN_TYPE::TokenImpersonation, &hNewToken)) 
    {
        DU_OutputDebugStringff(L"ERROR: DuplicateTokenEx returned false (error %u)", GetLastError());
        return false;
    }

    TOKEN_PRIVILEGES tokPrivs = {0};
    tokPrivs.PrivilegeCount = 1;

    LUID seDebugNameValue = {0};
    if (!LookupPrivilegeValue(nullptr, SE_DEBUG_NAME, &seDebugNameValue)) 
    {
        DU_OutputDebugStringff(L"ERROR: LookupPrivilegeValue returned false (error %u)", GetLastError());
        return false;
    }

    tokPrivs.Privileges[0].Luid = seDebugNameValue;
    tokPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    // Escalate the new token's privileges
    if (!AdjustTokenPrivileges(hNewToken, false, &tokPrivs, 0, nullptr, nullptr))
    {
        DU_OutputDebugStringff(L"ERROR: AdjustTokenPrivileges returned false (error %u)", GetLastError());
        return false;
    }

    PROCESS_INFORMATION pi = {0};
    STARTUPINFO si = {0};
    si.cb = sizeof si;
    si.lpDesktop = L"Winsta0\\Winlogon";

    // Start the process using the new token
    if (!CreateProcessAsUser(hNewToken, lpApplicationPath, nullptr, &tokenAttributes, &threadAttributes,
        true, CREATE_NEW_CONSOLE|INHERIT_CALLER_PRIORITY, nullptr, nullptr, &si, &pi)) 
    {
        DU_OutputDebugStringff(L"ERROR: CreateProcessAsUser returned false (error %u)", GetLastError());
        return false;
    }

    return true;
}
Run Code Online (Sandbox Code Playgroud)