首页 > 解决方案 > CreateProcessAsUser 太快无法跟踪进程

问题描述

我们调用CreateProcessAsUser()并在检查结果后开始跟踪 (WMI) 可能创建其他进程的进程。

在一种情况下,第一个进程非常快,以至于它创建了另一个进程并在我们开始跟踪它之前终止。

我什至尝试检查结果并在调用后立即开始跟踪CreateProcessAsUser(),但这还不够快。

我的想法是从 a 开始这个过程,launcher.exe这样我们就可以跟踪所有生成的过程。

还有其他替代解决方案吗?我们有终止进程的PID。

标签: c++windowswmicreateprocessasuser

解决方案


如果我们启动子进程并在它和所有子进程终止时想要方法,我们可以使用作业对象。一般步骤

当然,我们也需要创建 I/O 完成端口CreateIoCompletionPort,一个或多个(如果仅用于此任务 - 单线程绰绰有余)线程将GetQueuedCompletionStatus在端口上调用直到结束信号。

例如,我们可以使用lpCompletionKey作为指向具有虚函数的对象的指针,并且每个对象都知道如何处理动作事件。演示代码:

struct __declspec(novtable) PortTask 
{
    virtual bool OnIoCompletion(OVERLAPPED* lpOverlapped, ULONG NumberOfBytesTransferred) = 0;
};

struct EndTask : public PortTask 
{
    virtual bool OnIoCompletion(OVERLAPPED* /*lpOverlapped*/, ULONG /*NumberOfBytesTransferred*/)
    {
        DbgPrint("%s<%p>\n", __FUNCTION__, this);
        delete this;
        return false;
    }
};

struct IOPort 
{
    HANDLE CompletionPort;
    LONG dwRefCount;

    IOPort() : dwRefCount(1), CompletionPort(0) {
        DbgPrint("%s<%p>\n", __FUNCTION__, this);
    }

    ~IOPort(){
        if (CompletionPort) CloseHandle(CompletionPort);
        DbgPrint("%s<%p>\n", __FUNCTION__, this);
    }

    void AddRef(){
        InterlockedIncrementNoFence(&dwRefCount);
    }

    void Release(){
        if (!InterlockedDecrement(&dwRefCount)) {
            delete this;
        }
    }

    static ULONG WINAPI PortThread(PVOID This)
    {
        union {
            ULONG_PTR CompletionKey;
            PortTask* pTask;
        };

        ULONG NumberOfBytesTransferred;
        OVERLAPPED* lpOverlapped;

        HANDLE CompletionPort = reinterpret_cast<IOPort*>(This)->CompletionPort;

        while (GetQueuedCompletionStatus(CompletionPort, &NumberOfBytesTransferred, &CompletionKey, &lpOverlapped, INFINITE) &&
            pTask->OnIoCompletion(lpOverlapped, NumberOfBytesTransferred)) continue;

        reinterpret_cast<IOPort*>(This)->Release();
        return 0;
    }

    ULONG Create()
    {
        if (CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1))
        {
            AddRef();

            if (HANDLE hThread = CreateThread(0, 0, PortThread, this, 0, 0))
            {
                CloseHandle(hThread);
                return NOERROR;
            }
            Release();
        }

        return GetLastError();
    }

    ULONG Stop()
    {
        if (EndTask* pTask = new EndTask)
        {
            if (!PostQueuedCompletionStatus(CompletionPort, 0, (ULONG_PTR)pTask, 0))
            {
                ULONG dwError = GetLastError();
                delete pTask;
                return dwError;
            }
            return NOERROR;
        }

        return ERROR_NO_SYSTEM_RESOURCES;
    }
};

struct ActiveProcessZeroTask : public PortTask 
{
    //HWND hwnd; // in real code you send some message to hwnd instead thread
    HANDLE _hJob;
    ULONG _dwThreadId;

    ActiveProcessZeroTask() : _hJob(0), _dwThreadId(GetCurrentThreadId()) { }

    ~ActiveProcessZeroTask() {
        CloseHandle(_hJob);
        PostThreadMessageW(_dwThreadId, WM_QUIT, 0, 0);
    }

    virtual bool OnIoCompletion(OVERLAPPED* dwProcessId, ULONG MessageId)
    {
        DbgPrint("%s<%p>(%x %p)\n", __FUNCTION__, this, MessageId, dwProcessId);
        switch (MessageId)
        {
        case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO:
            DbgPrint("%p - ACTIVE_PROCESS_ZERO\n", dwProcessId);
            delete this;
            break;
        case JOB_OBJECT_MSG_NEW_PROCESS:
            DbgPrint("%p - NEW_PROCESS\n", dwProcessId);
            break;
        case JOB_OBJECT_MSG_EXIT_PROCESS:
            DbgPrint("%p - EXIT_PROCESS\n", dwProcessId);
            break;
        case JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS:
            DbgPrint("%p - ABNORMAL_EXIT_PROCESS\n", dwProcessId);
            break;
        }
        return true;
    }

    ULONG Create(HANDLE CompletionPort, PCWSTR ApplicationName)
    {
        if (HANDLE hJob = CreateJobObjectW(0, 0))
        {
            _hJob = hJob;

            JOBOBJECT_ASSOCIATE_COMPLETION_PORT jacp = { this, CompletionPort };

            if (SetInformationJobObject(hJob, JobObjectAssociateCompletionPortInformation, &jacp, sizeof(jacp)))
            {
                STARTUPINFO si = { sizeof(si)};
                PROCESS_INFORMATION pi;
                if (CreateProcessW(ApplicationName, 0, 0, 0, 0, CREATE_SUSPENDED, 0, 0, &si, &pi))
                {
                    ULONG dwError = NOERROR;

                    if (!AssignProcessToJobObject(hJob, pi.hProcess) || 
                        !ResumeThread(pi.hThread))
                    {
                        dwError = GetLastError();
                        TerminateProcess(pi.hProcess, 0);
                    }
                    CloseHandle(pi.hThread);
                    CloseHandle(pi.hProcess);

                    return dwError;
                }
            }
        }

        return GetLastError();
    }
};

void demo()
{
    if (IOPort* port = new IOPort)
    {
        if (port->Create() == NOERROR)
        {
            MessageBoxW(0, 0, L"just for demo #1", MB_ICONINFORMATION);

            // exec cmd for demo
            WCHAR ApplicationName[MAX_PATH];
            if (GetEnvironmentVariableW(L"ComSpec", ApplicationName, RTL_NUMBER_OF(ApplicationName)))
            {
                if (ActiveProcessZeroTask* pTask = new ActiveProcessZeroTask)
                {
                    if (pTask->Create(port->CompletionPort, ApplicationName) != NOERROR)
                    {
                        delete pTask;
                    }
                }
            }

            // wait all childs exit
            MessageBoxW(0, 0, L"Wait for MSG_ACTIVE_PROCESS_ZERO", MB_ICONINFORMATION);

            // stop track thread

            if (port->Stop() != NOERROR) __debugbreak();

        }

        port->Release();
    }

    {
        MSG msg;
        // remove Wm_QUIT
        while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) continue;
        MessageBoxW(0, 0, L"just for demo #2", MB_ICONINFORMATION);
    }
}

推荐阅读