Search code examples
cwindowsdriverinternals

PsLookupProcessByProcessId is returning STATUS_SUCCESS even if the pid is wrong


I'm checking from my driver if my usermode application is still running, while doing that, I use PsLookupProcessByProcessId to check if the proccess still exists. and it works at the begining but even after I close my process and no other process have the same pid, I still get STATUS_SUCCESS. Anyone has ever encountered this behaviour before? I'm running on Windows 20h2 for testing my driver

Snippet of my code

NTSTATUS status = PsLookupProcessByProcessId((HANDLE)UserModePid, &UserModeProcess);
if (status == STATUS_INVALID_PARAMETER) {
    DbgPrintEx(0, 0, "[Driver] Invalid Process\n");
    ExitKernel();
}
else {
    DbgPrintEx(0, 0, "[Driver] Status : %llx", status);
}

Sorry in advance for my bad english :)


Solution

  • When a process exits, Windows does not free the EPROCESS immediately, but keeps it for a while (because the reference count has not been reduced to 0).

    The following code works well to determine if a process has exited (copied from Blackbone):

    /// <summary>
    /// Check if process is terminating
    /// </summary>
    /// <param name="imageBase">Process</param>
    /// <returns>If TRUE - terminating</returns>
    BOOLEAN BBCheckProcessTermination( PEPROCESS pProcess )
    {
        LARGE_INTEGER zeroTime = { 0 };
        return KeWaitForSingleObject( pProcess, Executive, KernelMode, FALSE, &zeroTime ) == STATUS_WAIT_0;
    }
    

    Combine with your code:

    bool IsTerminated;
    NTSTATUS Status = PsLookupProcessByProcessId((HANDLE)LoaderPid, &LoaderProccess);
    if (!NT_SUCCESS(Status)) {
        IsTerminated = true;
    }
    else {
        IsTerminated = BBCheckProcessTermination(LoaderProccess);
        ObDereferenceObject(LoaderProccess);
    }
    
    if (IsTerminated) {
        DbgPrintEx(0, 0, "[Driver] Invalid Process\n");
        ExitKernel();
    }
    else {
        DbgPrintEx(0, 0, "[Driver] Status : %llx", Status);
    }
    

    If the above code does not work, you can also try:

    IsTerminated = PsGetProcessExitStatus(LoaderProccess) != STATUS_PENDING;
    

    If it still doesn't work, the last solution I can provide is to use ZwQuerySystemInformation to enumerate the processes and check if your process is in the linked list.