CreateProcessAsUser слишком быстрый, чтобы отслеживать процесс - PullRequest
0 голосов
/ 15 января 2020

Мы вызываем CreateProcessAsUser() и, проверив результат, мы начинаем отслеживать (WMI) процесс, который может создавать другие процессы.

В 1 случае первый процесс настолько быстр, что он создает другой обработать и завершить, прежде чем мы сможем начать его отслеживание.

Я даже пытался не проверить результат и сразу начать отслеживать после вызова CreateProcessAsUser(), но это не достаточно быстро.

Моя идея - запустить процесс с launcher.exe, чтобы мы могли отслеживать все сгенерированные процессы.

Есть ли другое альтернативное решение? У нас есть PID завершенного процесса.

Ответы [ 2 ]

1 голос
/ 15 января 2020

если мы запускаем дочерний процесс и хотим, чтобы когда он и все дочерние процессы завершались, мы можем использовать объект задания. общие шаги

  • создание нового объекта задания с помощью CreateJobObjectW
  • set JobObjectAssociateCompletionPortInformation с SetInformationJobObject
  • создание нового процесса в приостановленном состоянии (используйте флаг CREATE_SUSPENDED)
  • добавление процесса в работу с помощью AssignProcessToJobObject
  • возобновить новый процесс с помощью ResumeThread

    теперь система будет отправлять уведомления на наш порт завершения, когда новый процесс будет запущен или завершится. если в работе больше нет процессов - будет JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO сообщение отправлено на порт - Указывает, что счетчик активных процессов был уменьшен до 0

, конечно, нам нужно Также создайте порт завершения ввода / вывода с помощью 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);
    }
}
0 голосов
/ 15 января 2020

Вам необходимо реализовать механизм явной синхронизации ( семафор ). Ниже приведен алгоритм:

В родительском процессе:

semaphore my_semaphore = CreateSemaphore ("my_semphaore");  
args my_arguments ("my_semphaore");  
CreateProcessAsUser (my_arguments); 
Create_Asynchronous_Thread { releasesemaphore (my_semaphore );} // unblock shild process}
waitforSingleObject (shild_process_PID)

В процессе шилда:

// do something ...
semaphore my_semaphore = CreateSemaphore ("my_semphaore");  
// do something (parent is blocked)
waitforsingleobject (my_semaphore);
...