Running a Process (WITH GUI) on Windows XP Logon Screen (.NET / Pinvoke)

耗尽温柔 提交于 2020-01-01 16:10:14

问题


I need to write a small service that runs an application (with gui, e.g. calc.exe) on the logon-screen.

I already found this question (and answer): Running a process at the Windows 7 Welcome Screen

please read the code-comments if you don't understand how this works:

        // 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, "calc.exe", null, ref tokenAttributes, ref threadAttributes,
            true, (uint)CreateProcessFlags.CREATE_NEW_CONSOLE | (uint)CreateProcessFlags.INHERIT_CALLER_PRIORITY, IntPtr.Zero,
            "C:\\Windows\\System32", 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");
        }

It works with Windows 7. With XP I get error 1349 ERROR_BAD_TOKEN_TYPE while calling CreateProcessAsUser (MSDN: The type of the token is inappropriate for its attempted use.).

How to realize this in Windows XP? It does not have to be the code from above but it should work as a service (with system-account?).

Thanks for your support Fluxer


回答1:


This definitely has to do with privilege issues (Windows Vista and 7 have notable changes in security). Rather than trying to get token of winlogon.exe and impersonating it, try getting user token via WTSQueryUserToken like this:

WTSQueryUserToken (WTSGetActiveConsoleSessionId(), out userToken);

Replace the OpenProcessToken line which is used to get the token with the above statement.

Your new code should be like this:

//        if (!OpenProcessToken(winLogon.Handle, TOKEN_QUERY | TOKEN_IMPERSONATE | //TOKEN_DUPLICATE, out userToken))
//        {
//            log("ERROR: OpenProcessToken returned false - " + //Marshal.GetLastWin32Error());
//        }

WTSQueryUserToken (WTSGetActiveConsoleSessionId(), out userToken);

Do your dll import like this:

[DllImport("Kernel32.dll", SetLastError = true)]
[return:MarshalAs(UnmanagedType.U4)]
public static extern int WTSGetActiveConsoleSessionId ( );

You need only replace the part I commented out with this code.



来源:https://stackoverflow.com/questions/9868079/running-a-process-with-gui-on-windows-xp-logon-screen-net-pinvoke

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!