簡體   English   中英

CreateProcessAsUser進程退出-1073741502

[英]CreateProcessAsUser process exits with -1073741502

我有一項服務,負責在用戶登錄和控制台會話連接后啟動/監控用戶會話中的交互過程。 服務設置為自動啟動,以便在用戶登錄前啟動並運行。 首次登錄時一切正常,我可以正確啟動/重啟用戶進程。

如果用戶注銷並重新登錄服務,則無法再正確啟動用戶進程。 CreateProcessAsUser不返回任何錯誤,但是一旦用戶進程啟動,它將退出-1073741502(0xC0000142)退出代碼。

如果我重新啟動該服務,那么它再次能夠啟動用戶進程而沒有任何錯誤。

如果需要,我可以發布服務如何創建用戶進程的完整源代碼。

編輯

    try
            {
                //WE ALREADY HAVE A CLIENT ATTACHED , DONT START A NEW ONE
                if (ClientProcessId != null)
                    return;

                var ACTIVE_CONSOLE_SESSION = ListSessions()
                    .Where(SESSION => SESSION.State == WTS_CONNECTSTATE_CLASS.WTSActive)
                    .FirstOrDefault();

                if (ACTIVE_CONSOLE_SESSION == null)
                    return;

                CONSOLE_SESSION_ID = (uint)ACTIVE_CONSOLE_SESSION.Id;

                IntPtr USER_TOKEN = IntPtr.Zero;
                IntPtr ENVIRONMENT = IntPtr.Zero;
                IntPtr LINKED_TOKEN = IntPtr.Zero;

                try
                {
                    try
                    {
                        if (!Wtsapi32.WTSQueryUserToken(CONSOLE_SESSION_ID.Value, out USER_TOKEN))
                            throw new Win32Exception();
                    }
                    catch (Win32Exception wex)
                    {
                        EntryPoint.TryWriteToCacheLog($"{nameof(Wtsapi32.WTSQueryUserToken)} : console session id {CONSOLE_SESSION_ID} error {wex.ErrorCode} , native error {wex.NativeErrorCode}");
                        throw;
                    }

                    try
                    {
                        if (!Userenv.CreateEnvironmentBlock(out ENVIRONMENT, USER_TOKEN, true))
                            throw new Win32Exception();
                    }
                    catch (Win32Exception wex)
                    {
                        EntryPoint.TryWriteToCacheLog($"{nameof(Userenv.CreateEnvironmentBlock)} : error {wex.ErrorCode} , native error {wex.NativeErrorCode}");
                        throw;
                    }

                    try
                    {
                        LINKED_TOKEN = CoreProcess.GetLinkedTokeIfRequiered(USER_TOKEN);
                    }
                    catch (Win32Exception wex)
                    {
                        EntryPoint.TryWriteToCacheLog($"{nameof(CoreProcess.GetLinkedTokeIfRequiered)} : error {wex.ErrorCode} , native error {wex.NativeErrorCode}");
                        throw;
                    }

                    //GET PROCESS PATHS
                    string FILE_NAME = EntryPoint.PROCESS_FULL_FILE_NAME;
                    string WORKING_DIRECTORY = EntryPoint.PROCESS_DIRECTORY;

                    //GET CURRENT COMMAND LINE ARGUMENTS
                    var CMD_ARGS = Environment.GetCommandLineArgs();

                    //FIRST ARGUMENT WILL ALWAYS HAVE FULL PROCESS PATH,OTHER ARGUMENTS ARE OPTIONAL
                    var ARGUMENTS_STRING = CMD_ARGS
                        .Skip(1)
                        .DefaultIfEmpty()
                        .Aggregate((first, next) => ' ' + first + ' ' + next);

                    var ARGUMENTS = new StringBuilder(ARGUMENTS_STRING);

                    var START_INFO = new STARTUPINFO();
                    START_INFO.cb = Marshal.SizeOf(START_INFO);
                    START_INFO.lpDesktop = @"winsta0\default";

                    var PROCESS_INFO = new PROCESS_INFORMATION();
                    uint dwCreationFlags = NORMAL_PRIORITY_CLASS | (int)(PROCESS_CREATE_FLAG.CREATE_NEW_CONSOLE | PROCESS_CREATE_FLAG.CREATE_UNICODE_ENVIRONMENT);

                    try
                    {
                        if (!AdvApi32.CreateProcessAsUser(LINKED_TOKEN,
                            FILE_NAME,
                            ARGUMENTS,
                            IntPtr.Zero,
                            IntPtr.Zero,
                            true,
                            dwCreationFlags,
                            ENVIRONMENT,
                            WORKING_DIRECTORY,
                            ref START_INFO,
                            out PROCESS_INFO))
                            throw new Win32Exception();

                        if (PROCESS_INFO.hThread != IntPtr.Zero)
                        {
                            ClientProcessId = PROCESS_INFO.dwProcessId;
                            ClientSessionId = CONSOLE_SESSION_ID;

                            EntryPoint.TryWriteToCacheLog($"{nameof(AdvApi32.CreateProcessAsUser)} : Created porocess {ClientProcessId} in session {CONSOLE_SESSION_ID}.");
                        }
                    }
                    catch (Win32Exception wex)
                    {
                        EntryPoint.TryWriteToCacheLog($"{nameof(AdvApi32.CreateProcessAsUser)} : error {wex.ErrorCode} , native error {wex.NativeErrorCode}");
                        throw;
                    }
                }
                catch (Win32Exception wex)
                {
                    switch (wex.NativeErrorCode)
                    {
                        case 5:
                        case 1008:

                            tryCount++;
                            if (tryCount >= START_RETRIES)
                                throw;

                            Thread.Sleep(RETRY_WAIT_SPAN);

                            if (DisableCallBacks)
                                return;

                            CreateProcess(tryCount);

                            break;
                        default:
                            throw;
                    }
                }
                catch
                {
                    throw;
                }
                finally
                {
                    Userenv.DestroyEnvironmentBlock(ENVIRONMENT);
                    Kernel32.CloseHandle(USER_TOKEN);
                    if (USER_TOKEN != LINKED_TOKEN)
                        Kernel32.CloseHandle(LINKED_TOKEN);
                }
            }
            catch (Exception ex)
            {
                EntryPoint.TryWriteToCacheLog($"{nameof(CreateProcess)} failed after {tryCount} retries, console seesion id {(CONSOLE_SESSION_ID != null ? CONSOLE_SESSION_ID.ToString() : "Unobtained")}.", ex.ToString());
            }
            finally
            {
                Monitor.Exit(CREATE_LOCK);
            }

  public static TOKEN_ELEVATION_TYPE GetTokenElevationLevel(IntPtr hToken)
    {
        int TOKEN_INFO_LENGTH = Marshal.SizeOf(typeof(int));
        IntPtr TOKEN_INFO_POINTER = Marshal.AllocHGlobal(TOKEN_INFO_LENGTH);

        try
        {
            if (!AdvApi32.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenElevationType, TOKEN_INFO_POINTER, TOKEN_INFO_LENGTH, out TOKEN_INFO_LENGTH))
                throw Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error());

            return (TOKEN_ELEVATION_TYPE)Marshal.ReadInt32(TOKEN_INFO_POINTER);
        }
        catch
        {
            throw;
        }
        finally
        {
            if (TOKEN_INFO_POINTER != IntPtr.Zero)
                Marshal.FreeHGlobal(TOKEN_INFO_POINTER);
        }
    }

 public static IntPtr GetLinkedTokeIfRequiered(IntPtr hToken)
    {
        var TOKEN_ELEVATION = GetTokenElevationLevel(hToken);

        if (TOKEN_ELEVATION != TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited)
            return hToken;

        int TOKEN_INFO_LENGHT = Marshal.SizeOf(typeof(IntPtr));
        IntPtr LINKED_TOKEN_INFO = Marshal.AllocHGlobal(TOKEN_INFO_LENGHT);

        try
        {
            if (!AdvApi32.GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenLinkedToken, LINKED_TOKEN_INFO, TOKEN_INFO_LENGHT, out TOKEN_INFO_LENGHT))
                throw new Win32Exception();

            return Marshal.ReadIntPtr(LINKED_TOKEN_INFO);
        }
        finally
        {
            if (LINKED_TOKEN_INFO != IntPtr.Zero)
                Marshal.Release(LINKED_TOKEN_INFO);
        }
    }

感謝您發布其余代碼。 我看到你正在推動升級過程。 我將此添加到我的測試服務中,它仍然可以正常工作。

但我認為問題可能是GetLinkedTokeIfRequiered()這一行:

Marshal.Release(LINKED_TOKEN_INFO);

那顯然應該是:

Marshal.FreeHGlobal(LINKED_TOKEN_INFO);

修復它,它可能只是工作。 事實上,我很驚訝它不會崩潰。

對我來說不容易,挖掘這個。 C#互操作不是我的強項。


為了OP的好處,我的測試服務的完整源代碼,用C ++編寫,可以工作:

#include <windows.h>
#include <wtsapi32.h>
#include <userenv.h>
#include <tchar.h>
#include <stdio.h>

#pragma comment (lib, "user32.lib")
#pragma comment (lib, "wtsapi32.lib")
#pragma comment (lib, "userenv.lib")
#pragma comment (lib, "advapi32.lib")

DWORD report_error (const char *operation)
{
    DWORD err = GetLastError ();
    return err;
}

// Launch notepad as currently logged-on user
DWORD LaunchProcess (DWORD SessionId, const char **failed_operation)
{
    HANDLE hToken;
    BOOL ok = WTSQueryUserToken (SessionId, &hToken);
    if (!ok)
        return report_error (*failed_operation = "WTSQueryUserToken");

    void *environment = NULL;
    ok = CreateEnvironmentBlock (&environment, hToken, TRUE);

    if (!ok)
    {
        CloseHandle (hToken);
        return report_error (*failed_operation = "CreateEnvironmentBlock");
    }

    TOKEN_LINKED_TOKEN lto;
    DWORD nbytes;
    ok = GetTokenInformation (hToken, TokenLinkedToken, &lto, sizeof (lto), &nbytes);

    if (ok)
    {
        CloseHandle (hToken);
        hToken = lto.LinkedToken;
    }

    STARTUPINFO si = { sizeof (si) } ;
    PROCESS_INFORMATION pi = { } ;
    si.lpDesktop = "winsta0\\default";

    // Do NOT want to inherit handles here, surely
    DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS | /* CREATE_NEW_CONSOLE | */ CREATE_UNICODE_ENVIRONMENT;
    ok = CreateProcessAsUser (hToken, "c:\\windows\\system32\\notepad.exe", NULL, NULL, NULL, FALSE,
        dwCreationFlags, environment, NULL, &si, &pi);

    DestroyEnvironmentBlock (environment);
    CloseHandle (hToken);

    if (!ok)
        return report_error (*failed_operation = "CreateProcessAsUser");

    CloseHandle (pi.hThread);
    CloseHandle (pi.hProcess);
    return 0;
}

// Determine the session ID of the currently logged-on user
DWORD GetCurrentSessionId ()
{
    WTS_SESSION_INFO *pSessionInfo;
    DWORD n_sessions = 0;
    BOOL ok = WTSEnumerateSessions (WTS_CURRENT_SERVER, 0, 1, &pSessionInfo, &n_sessions);
    if (!ok)
        return 0;

    DWORD SessionId = 0;

    for (DWORD i = 0; i < n_sessions; ++i)
    {
        if (pSessionInfo [i].State == WTSActive)
        {
            SessionId = pSessionInfo [i].SessionId;
            break;
        }
    }

    WTSFreeMemory (pSessionInfo);
    return SessionId;
}


#define SERVICE_NAME __T ("demo_service")

bool quit;

// CtrlHandler callback
DWORD WINAPI CtrlHandler (DWORD dwControl, DWORD  dwEventType, LPVOID lpEventData, LPVOID lpContext)
{
    if (dwControl == SERVICE_CONTROL_STOP)
        quit = true;
    return NO_ERROR;
}

// SvcMain callback
VOID WINAPI SvcMain (DWORD dwArgc, LPTSTR *lpszArgv)
{
    // Register for callbacks
    SERVICE_STATUS_HANDLE sh = RegisterServiceCtrlHandlerEx (SERVICE_NAME, CtrlHandler, NULL);

    // Tell the SCM that we are up and running
    SERVICE_STATUS ss = { };
    ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    ss.dwCurrentState = SERVICE_RUNNING;
    ss.dwControlsAccepted = SERVICE_ACCEPT_STOP;
    SetServiceStatus (sh, &ss);

    TCHAR buf [256];
    const TCHAR *title = __T ("(c) 2018 Contoso Corporation");

    while (!quit)
    {
        DWORD response = IDOK;

        DWORD SessionId = GetCurrentSessionId ();
        if (SessionId == 0)
        {
            Sleep (2000);
            continue;
        }

        // Pop-up a message on the screen of the currently logged-on user (session 1)
        _stprintf (buf, __T ("Ready to launch..., SessionId = %d"), SessionId);
        WTSSendMessage (WTS_CURRENT_SERVER_HANDLE, SessionId, (TCHAR *) title, _tcslen (title),
            buf, _tcslen (buf), MB_OKCANCEL, 0, &response, TRUE);
        if (response == IDCANCEL)
            break;

        const char *failed_operation = "";
        DWORD dwResult = LaunchProcess (SessionId, &failed_operation);

        // Report results
        _stprintf (buf, __T ("LaunchProcess returned %lx from %s"), dwResult, failed_operation);
        WTSSendMessage (WTS_CURRENT_SERVER_HANDLE, SessionId, (char *) title, _tcslen (title),
            buf, _tcslen (buf), MB_OK, 0, &response, TRUE);

        FILE *logfile = fopen ("g:\\temp\\service.log", "at");
        if (logfile)
        {
            fprintf (logfile, "%s\n", buf);
            fclose (logfile);
        }
    }

    // Tell the SCM we are going away and exit
    ss.dwCurrentState = SERVICE_STOPPED;
    SetServiceStatus (sh, &ss);
}


// main
int main (void)
{
    SERVICE_TABLE_ENTRY DispatchTable [] = 
    { 
        { SERVICE_NAME, SvcMain }, 
        { NULL, NULL } 
    }; 

    // This call returns when the service has stopped. 
    // The process should simply terminate when the call returns.
    StartServiceCtrlDispatcher (DispatchTable);
    return 0;
}

錯誤是STATUS_DLL_INIT_FAILED ,這意味着缺少動態加載的DLL 也許您指定了錯誤的工作目錄,並且對LoadLibrary("lib_with_no_path.dll")某些調用失敗了?

如果查看Event Viewer您應該能夠看到丟失了哪個DLL。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM