为了账号安全,请及时绑定邮箱和手机立即绑定

CreateProcessAsUser 进程以 -1073741502 退出

CreateProcessAsUser 进程以 -1073741502 退出

C#
皈依舞 2021-07-09 16:00:35
我有一个服务,负责在用户登录和控制台会话连接后启动/监视用户会话中的交互过程。服务设置为自动启动,以便在用户登录之前启动并运行。第一次登录时一切正常,我正确启动/重新启动了用户进程。发生的情况是,如果用户退出并重新登录,服务将不再能够正确启动用户进程。CreateProcessAsUser 没有返回错误,但是一旦用户进程启动,它就会以 -1073741502 (0xC0000142) 退出代码退出。如果我重新启动该服务,则它再次能够启动用户进程而不会出现任何错误。如果需要,我可以发布该服务如何创建用户进程的完整来源。
查看完整描述

2 回答

?
开满天机

TA贡献1786条经验 获得超13个赞

我看到您正在启动提升的流程。我将此添加到我的测试服务中,它仍然可以正常工作。


但我认为问题可能出在这一行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;

}



查看完整回答
反对 回复 2021-07-17
?
慕盖茨4494581

TA贡献1850条经验 获得超11个赞

错误是STATUS_DLL_INIT_FAILED这意味着DLL缺少动态加载。也许您指定了错误的工作目录并且某些调用LoadLibrary("lib_with_no_path.dll")失败了?

如果您查看 .dll 文件,您应该能够看到缺少哪个 DLL Event Viewer


查看完整回答
反对 回复 2021-07-17
  • 2 回答
  • 0 关注
  • 496 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信