ZwQuerySystemInformation无法正常工作

时间:2017-12-18 20:40:07

标签: winapi

我尝试使用内核模式驱动程序查找FindProcessidByName,有时ImageName.Buffer变为NULL,因此,当ImageName.Buffer变为NULL时,我无法找到进程ID。你有没有想过ImageName.Buffer有时为什么会变成NULL,先生?

 typedef struct _SYSTEM_PROCESS_INFO_L
    {
        ULONG                   NextEntryOffset;
        ULONG                   NumberOfThreads;
        LARGE_INTEGER           Reserved[3];
        LARGE_INTEGER           CreateTime;
        LARGE_INTEGER           UserTime;
        LARGE_INTEGER           KernelTime;
        UNICODE_STRING          ImageName;
        ULONG                   BasePriority;
        HANDLE                  ProcessId;
        HANDLE                  InheritedFromProcessId;
    }_SYSTEM_PROCESS_INFO_L, *P_SYSTEM_PROCESS_INFO_L;

HANDLE LSFindProcess(LPSTR name)
{
    NTSTATUS durum;
    ULONG retsize;
    HANDLE hProcid = -1;
    P_SYSTEM_PROCESS_INFO_L pi;
    durum = ZwQuerySystemInformation(SystemProcessInformation, NULL, NULL, &retsize); // request how much memory size we need.
    if (!NT_SUCCESS(durum) && durum !=STATUS_INFO_LENGTH_MISMATCH)
    {
        DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "LS : ZwQuerySystemInformation Failed 1 durum : %p \n",durum);
        return -1;
    }
    PVOID    memPtr;
    memPtr = ExAllocatePool(PagedPool, retsize);
    if (!memPtr)
    {
        DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "LS : ExAllocatePool Failed \n");
        return -1;
    }
    memset(memPtr, 0, retsize);// zero mem

    durum = ZwQuerySystemInformation(SystemProcessInformation, memPtr, retsize, NULL);
    pi = (P_SYSTEM_PROCESS_INFO_L)memPtr; // parselliyorz
    if (!NT_SUCCESS(durum))
    {
        DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "LS : ZwQuerySystemInformation Failed 2 durum : %p \n", durum);
        return -1;
    }
    while (pi->NextEntryOffset)
    {
        if (pi->ImageName.Buffer) //some process null if I dont use this I am getting BSOD.
        { 
            if (!_stricmp(pi->ImageName.Buffer, name))
            {
                DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "LS : name %ws , pid : %d  \n", pi->ImageName.Buffer, pi->ProcessId);
                hProcid = pi->ProcessId; // pid
                break; // foundedd
            }
        }

        pi = (P_SYSTEM_PROCESS_INFO_L)((unsigned char*)pi + pi->NextEntryOffset);
    }
    DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "LS :  LSFindProcess bitti \n");
    return hProcid;
}

3 个答案:

答案 0 :(得分:2)

ZwQuerySystemInformation is Not working Properly

this is of course false. api working properly. if you got wrong results, this is only due errors in code. in concrete code spinet exist several errors.

in kernel mode exist difference between Zw and Nt api - need understand which version need call, if both (like in this concrete case) is exported. if you know that previous mode is kernel mode - need use Nt version. if you don't know previous mode in this point(at compile time) or previous mode user mode - need use Zw version. however this is general note and will be not error always call Zw

the first serious error - this is how ZwQuerySystemInformation called - first time for query requested buffer size retsize (in code) and second time already with this buffer size. but between this calls new threads and processes can be spawn in system. as result returned buffer size can be already not large enough. correct solution - call this api in loop, while it return STATUS_INFO_LENGTH_MISMATCH

the second - memory always must be free. especially in kernel mode. say that code incomplete - no excuse. code can be incomplete and intermediate, but free memory after allocation always must be immediately inserted

else one critical error - while (pi->NextEntryOffset) loop - with this loop we always lost (not process) the last entry (last created process). need change this.

if (pi->ImageName.Buffer) //some process null if I dont use this I am getting BSOD.

the ImageName is UNICODE_STRING and need work with it respectively. in case ImageName.Buffer the ImageName.Length is also 0. the UNICODE_STRING ImageName; is correct. incorrect only how you use it.

!_stricmp(pi->ImageName.Buffer, name); // ??

the pi->ImageName.Buffer is PWSTR so it can not be used with _stricmp as a matter of principle. think you use c compiler - c++ simply give you error here. but even use _wcsicmp is incorrect here - again pi->ImageName is UNICODE_STRING and need use RtlEqualUnicodeString(&pi->ImageName, name, TRUE) where name must be of course PCUNICODE_STRING but not PCSTR or PSTR or even PCWSTR. if you have PCWSTR name as input - you need wrap it to UNICODE_STRING before call this api. example of code:

NTSTATUS LSFindProcess(PCUNICODE_STRING ImageName, PHANDLE UniqueProcessId)
{
    ULONG cb = 0x20000;

    PVOID buf;
    NTSTATUS status;
    do 
    {
        status = STATUS_INSUFFICIENT_RESOURCES;

        if (buf = ExAllocatePool(PagedPool, cb))
        {
            if (0 <= (status = NtQuerySystemInformation(SystemProcessInformation, buf, cb, &cb)))
            {
                union {
                    PVOID pv;
                    PBYTE pb;
                    PSYSTEM_PROCESS_INFORMATION pspi;
                };

                pv = buf;
                ULONG NextEntryOffset;

                goto __0;

                do 
                {
                    pb += NextEntryOffset;
__0:
                    if (RtlEqualUnicodeString(&pspi->ImageName, ImageName, TRUE))
                    {
                        *UniqueProcessId = pspi->UniqueProcessId;
                        break;
                    }

                } while (NextEntryOffset = pspi->NextEntryOffset);
            }
            ExFreePool(buf);
        }

    } while (status == STATUS_INFO_LENGTH_MISMATCH);

    return status;
}
NTSTATUS LSFindProcess(PCWSTR ImageName, PHANDLE UniqueProcessId)
{
    UNICODE_STRING us;
    RtlInitUnicodeString(&us, ImageName);

    return LSFindProcess(&us, UniqueProcessId);
}

答案 1 :(得分:-1)

你不应该调用ZwQuerySystemInformation,它不容易在Windows操作系统上移植,甚至可能在其中一些上不可用。 MSDN documentation for this function建议您使用其他功能。

答案 2 :(得分:-1)

感谢大家特别是@RbMm感谢信息。  完成的代码我希望这篇文章可以帮助别人..

/// <summary>
/// Struct SystemProcessInformation
/// </summary>

typedef struct _SYSTEM_PROCESS_INFO_L
{
    ULONG                   NextEntryOffset;
    ULONG                   NumberOfThreads;
    LARGE_INTEGER           Reserved[3];
    LARGE_INTEGER           CreateTime;
    LARGE_INTEGER           UserTime;
    LARGE_INTEGER           KernelTime;
    UNICODE_STRING          ImageName;
    ULONG                   BasePriority;
    HANDLE                  ProcessId;
    HANDLE                  InheritedFromProcessId;
}_SYSTEM_PROCESS_INFO_L, *P_SYSTEM_PROCESS_INFO_L;

/// <summary>
/// Find Process ID By Name , thanks @RbMm
/// </summary>
/// <param name="imagename">Process name </param>
/// <param name="pid">Output Process id</param>
/// <returns>NTSTATUS.</returns>

NTSTATUS LSFindProcessIdByName(IN PCWSTR imagename, OUT PHANDLE pid)
{

    NTSTATUS durum = STATUS_UNSUCCESSFUL;
    ULONG qmemsize = 0x1024;
    PVOID qmemptr = 0;
    P_SYSTEM_PROCESS_INFO_L spi;
    UNICODE_STRING uimagename;
    RtlInitUnicodeString(&uimagename, imagename); // @RbMm
    *pid = -1;
    do
    {
        qmemptr = ExAllocatePool(PagedPool, qmemsize); // alloc memory for spi
        if (qmemptr == NULL) // check memory is allocated or not.
        {
            return STATUS_UNSUCCESSFUL;
        }
        durum = ZwQuerySystemInformation(SystemProcessInformation,qmemptr, qmemsize, NULL);
        if (durum == STATUS_INFO_LENGTH_MISMATCH)
        {
            qmemsize = qmemsize * 2; // increase qmemsize for next memory alloc
            ExFreePool(qmemptr); // free memory
        }
    } while (durum == STATUS_INFO_LENGTH_MISMATCH); // resize memory
    spi = (P_SYSTEM_PROCESS_INFO_L)qmemptr;

    while(1)
    {

        if (RtlEqualUnicodeString(&uimagename, &spi->ImageName, TRUE)) // @RbMm
        {
            *pid = spi->ProcessId;
            break;
        }

        if (spi->NextEntryOffset == 0)
            break;

        spi = (P_SYSTEM_PROCESS_INFO_L)((unsigned char*)spi + spi->NextEntryOffset); // next info 
    }

    if (!NT_SUCCESS(durum))
    {
        ExFreePool(qmemptr); // free memory
        return STATUS_UNSUCCESSFUL;
    }
    ExFreePool(qmemptr); // free memory 
    return STATUS_SUCCESS; 
}