How to use ZwQueryInformationProcess to get ProcessImageFileName in a kernel driver?

后端 未结 3 561
逝去的感伤
逝去的感伤 2021-02-14 07:49

I\'m writing a simple kernel driver for my application (think of a very simple anti-malware application.)

I\'ve hooked ZwOpenFile() and used PsGetCurr

相关标签:
3条回答
  • 2021-02-14 08:31

    ZwQueryInformationProcess needs a HANDLE, not a PROCESS! You need to use ObOpenObjectByPointer to get the handle first.

    0 讨论(0)
  • 2021-02-14 08:44

    The MSDN docs for this API indicate that

    When the ProcessInformationClass parameter is ProcessImageFileName, the buffer pointed to by the ProcessInformation parameter should be large enough to hold a UNICODE_STRING structure as well as the string itself. The string stored in the Buffer member is the name of the image file.file.

    With this in mind, I suggest you try modifying your buffer structure like this:

    WCHAR strBuffer[(sizeof(UNICODE_STRING) / sizeof(WCHAR)) + 260];
    UNICODE_STRING str;
    str = (UNICODE_STRING*)&strBuffer;
    
    //initialize
    str.Buffer = &strBuffer[sizeof(UNICODE_STRING) / sizeof(WCHAR)];
    str.Length = 0x0;
    str.MaximumLength = 260 * sizeof(WCHAR);
    
    //note that the seconds arg (27) is ProcessImageFileName
    ZwQueryInformationProcess(proc, 27, &strBuffer, sizeof(strBuffer), NULL);
    

    Additionally, your code needs to check and handle the error case described in the docs here. This may be why you missed the BSOD trigger case.

    If the buffer is too small, the function fails with the STATUS_INFO_LENGTH_MISMATCH error code and the ReturnLength parameter is set to the required buffer size.

    0 讨论(0)
  • 2021-02-14 08:47

    //Declare this piece of code in header file if available otherwise before the Function definition..

    typedef NTSTATUS (*QUERY_INFO_PROCESS) (
    __in HANDLE ProcessHandle,
    __in PROCESSINFOCLASS ProcessInformationClass,
    __out_bcount(ProcessInformationLength) PVOID ProcessInformation,
    __in ULONG ProcessInformationLength,
    __out_opt PULONG ReturnLength
    );
    
    QUERY_INFO_PROCESS ZwQueryInformationProcess;
    

    //Function Definition

    NTSTATUS GetProcessImageName(HANDLE processId, PUNICODE_STRING ProcessImageName)
    {
    NTSTATUS status;
    ULONG returnedLength;
    ULONG bufferLength;
    HANDLE hProcess;
    PVOID buffer;
    PEPROCESS eProcess;
    PUNICODE_STRING imageName;
    
    PAGED_CODE(); // this eliminates the possibility of the IDLE Thread/Process
    
    status = PsLookupProcessByProcessId(processId, &eProcess);
    
    if(NT_SUCCESS(status))
    {
        status = ObOpenObjectByPointer(eProcess,0, NULL, 0,0,KernelMode,&hProcess);
        if(NT_SUCCESS(status))
        {
        } else {
            DbgPrint("ObOpenObjectByPointer Failed: %08x\n", status);
        }
        ObDereferenceObject(eProcess);
    } else {
        DbgPrint("PsLookupProcessByProcessId Failed: %08x\n", status);
    }
    
    
    if (NULL == ZwQueryInformationProcess) {
    
        UNICODE_STRING routineName;
    
        RtlInitUnicodeString(&routineName, L"ZwQueryInformationProcess");
    
        ZwQueryInformationProcess =
               (QUERY_INFO_PROCESS) MmGetSystemRoutineAddress(&routineName);
    
        if (NULL == ZwQueryInformationProcess) {
            DbgPrint("Cannot resolve ZwQueryInformationProcess\n");
        }
    }
    
    /* Query the actual size of the process path */
    status = ZwQueryInformationProcess( hProcess,
                                        ProcessImageFileName,
                                        NULL, // buffer
                                        0, // buffer size
                                        &returnedLength);
    
    if (STATUS_INFO_LENGTH_MISMATCH != status) {
        return status;
    }
    
    /* Check there is enough space to store the actual process
       path when it is found. If not return an error with the
       required size */
    bufferLength = returnedLength - sizeof(UNICODE_STRING);
    if (ProcessImageName->MaximumLength < bufferLength)
    {
        ProcessImageName->MaximumLength = (USHORT) bufferLength;
        return STATUS_BUFFER_OVERFLOW;   
    }
    
    /* Allocate a temporary buffer to store the path name */
    buffer = ExAllocatePoolWithTag(NonPagedPool, returnedLength, 'uLT1');
    
    if (NULL == buffer) 
    {
        return STATUS_INSUFFICIENT_RESOURCES;   
    }
    
    /* Retrieve the process path from the handle to the process */
    status = ZwQueryInformationProcess( hProcess,
                                        ProcessImageFileName,
                                        buffer,
                                        returnedLength,
                                        &returnedLength);
    
    if (NT_SUCCESS(status)) 
    {
        /* Copy the path name */
        imageName = (PUNICODE_STRING) buffer;
        RtlCopyUnicodeString(ProcessImageName, imageName);
    }
    
    /* Free the temp buffer which stored the path */
    ExFreePoolWithTag(buffer, 'uLT1');
    
    return status;
    }
    

    //Function Call.. Write this piece of code in PreOperation Call back and IRQ should be PASSIVE_LEVEL

    PEPROCESS objCurProcess=NULL;
    HANDLE hProcess;
    UNICODE_STRING fullPath;
    
    objCurProcess=IoThreadToProcess(Data->Thread);//Note: Date is type of FLT_CALLBACK_DATA which is in PreOperation Callback as argument
    
    hProcess=PsGetProcessID(objCurProcess);
    
    fullPath.Length=0;
    fullPath.MaximumLength=520;
    fullPath.Buffer=(PWSTR)ExAllocatePoolWithTag(NonPagedPool,520,'uUT1');
    
    GetProcessImageName(hProcess,&fullPath);
    

    in fullPath variable there is Full Path of Process .. Like if the process is explorer.exe then path will be look like this:-

    \Device\HarddiskVolume3\Windows\explorer.exe
    

    Note:- \Device\HarddiskVolume3 Path might be changed due to Machine and different volume in hard disk this is an example in my case.

    0 讨论(0)
提交回复
热议问题