Hello friends! Today you will learn one of the most underrated yet powerful APIs from the undocumented set of APIs. In this post, I will guide you on how to get the crucial details like the memory usage of the process along with basic details like PID, Process Name and Session ID using NTQuerySystemInformation function from ntdll.dll library
NTQuerySystemInformation is defined in the low-level library ntdll.dll, which contains the NT kernel functions. These functions are then later used by other high-level APIs like WTS32Api, ToolHelp32 or PSApi with another set of functions to provide required details.
For a long time, this API wasn't documented on MSDN because it's being used internally by the Windows OS and its developers. But later on, some reverse engineers dug deep into the applications and found that it exists and tried creating malware that circumvented the anti-malware software. So, Microsoft decided to document it in order to have the signatures for such malware. Well, this is purely what I think, not from any official resource.
This is widely used in the Sysinternal tools like Process Explorer and the Windows Task Manager. In this post, I will only guide you through its usage, not in conjunction with other functions to enumerate furthermore details of the process. You can use your knowledge from the previous posts and create your own stealthy process explorer tool. I would love to see that, once you do, let me know at [email protected]
C++ is a strictly typed compiled language that validates the parameters and the return type of a program during compile time. The
winternl.h header file does not contain the prototype of this function. So let's have it in our
pch.h header file
This signature is shamelessly copied from the MSDN documentation here. This also contains other rarely used APIs from the ntdll.dll library.
You will see
OUT placeholders before the types of the parameters. They are defined as nothing, so during compile time, nothing will be replaced at that place. This is only used to help developers by giving additional information about how to handle the argument.
Getting an appropriate buffer with a list of all the processes
The NtQuerySystemInformation function requires a pre-allocated buffer to copy the information and its size. Since we don't have the required size, we can use the same function to return the amount of size required and loop until all the process gets copied into the buffer.
Function parameters description for NtQuerySystemInformation are as follows:–
- Pass the value
SYSTEM_INFORMATION_CLASSenumeration class to tell the function that we want to process specific information only.
- Convert the allocated buffer of
LPVOIDand pass its reference here. Once the function will succeed, this will contain all the required information about processes
- Pass the size used while allocating the above buffer.
- Create a
DWORDto contain a number of bytes returned and pass its reference to this parameter. If the function fails with the error code
STATUS_INFO_LENGTH_MISMATCH, this parameter will contain the actual size required to allocate the container buffer.
Traversing the entries from the buffer
The very first thing to print is the unique process identifier. In this, we will get
UniqueProcessId in the form of a
HANDLE object. Luckily there is a macro used to convert the handles to
Now it's time for the image name (aka process's name). It is a
UNICODE_STRING structure containing an optional
Buffer field. To keep things simple and easy, you can use the following ternary syntax directly in the
After printing the number of handles open and threads running, their other set fields left contain the data related to occupied size in bytes. Now printing such a number is pretty boring. We can use the
StrFormatByteSizeW from the
shlwapi.h header file. You can see the usage of this function here, in the code. If the function fails, it will return
- Size in bytes to be converted to human-readable format.
- Create a buffer with size
MAX_PATHand pass its reference here which will contain the contents of the formatted size
- Pass the size of the buffer pointed to by pszBuf, in characters.
Check the video below to know how this function works and what information has been returned by it.
- http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented Functions%2FSystem Information%2FNtQuerySystemInformation.html
- http://undocumented.ntinternals.net/UserMode/Undocumented Functions/System Information/SYSTEM_INFORMATION_CLASS.html
- http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented Functions%2FSystem Information%2FStructures%2FSYSTEM_PROCESS_INFORMATION.html