fardjad fardjad - 1 month ago 22
C++ Question

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

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

I've hooked

ZwOpenFile()
and used
PsGetCurrentProcess()
to get a handle to the caller process.

It returns a PEPROCESS structure:

PEPROCESS proc = PsGetCurrentProcess();


I'm using
ZwQueryInformationProcess()
to get the
PID
and
ImageFileName
:

DbgPrint("ZwOpenFile Called...\n");
DbgPrint("PID: %d\n", PsGetProcessId(proc));
DbgPrint("ImageFileName: %.16s\n", PsGetProcessImageFileName(proc));


and trying to get the process
FullPath
this way (but I get BSOD):

WCHAR strBuffer[260];
UNICODE_STRING str;

//initialize
str.Buffer = strBuffer;
str.Length = 0x0;
str.MaximumLength = sizeof(strBuffer);

//note that the seconds arg (27) is ProcessImageFileName
ZwQueryInformationProcess(proc, 27, &str, sizeof(str), NULL);

DbgPrint("FullPath: %wZ\n", str.Buffer);


DbgView Output

As you see
str.Buffer
is empty or filled with garbage. Perhaps a buffer overflow while filling the
str
via
ZwQueryInformationProcess()
triggers the BSOD.

alt text

Any help would be appreciated.

Answer

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.