ZwQuerySystemInformation is Not working Properly
Emily Wong
I tried FindProcessidByName with Kernel Mode Driver, sometimes ImageName.Buffer goes to NULL , because of this , when ImageName.Buffer goes to NULL I can not find process ids. Do you have any idea why ImageName.Buffer goes to NULL sometimes, sir ?
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;
} 9 3 Answers
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);
} 0 thanks for everyone especially @RbMm thanks for informations. Finished code I hope this post help someone..
/// <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;
} 1 You should not be calling ZwQuerySystemInformation, it's not easily portable across Windows OS's and may not even be available on some of them. The MSDN documentation for this function recommends alternate functions for your particular usage.
15