ZwQueryDirectoryFile replacement SSDT hook to hide files on Windows system. This code is an evolution of the one written by Bill Blunden in "The Rootkit ARSENAL" book.
License : Copyright Emeric Nasi, some rights reserved
This work is licensed under a Creative Commons Attribution 4.0 International License.
I. Introduction.
I was reading Bill Blunden’s book “The Rootkit ARSENAL”. This book is great to learn the basics of Windows rootkits (more information here). I am not specialist in Windows O.S and using the book, I tried to learn more about this OS security by building my own rootkits.
In chapter 5 Blunden explains how to hide directories by using SSDT hooking and replacing the ZwQueryDirectoryFile kernel function. In fact this code can be used to hide any file. I tried his code and I found a few problems in it (it works only on Windows XP, it does not work when there is only one file in directory, etc).
So I modified the code to correct these problems and I decided to share it here.
II. Headers information.
In this section I am going to describe all the information wee need to write and use the replacement function. The code in this section should be written in a file accessible by the rootkit core and the replacement function. It can be inside the replacement function file like in the book, or in a dedicated header file.
II.1 The needed includes
The replacement function only needs one included file (and it is a big one), the windows driver kit main file.
#include <ntddk.h>
II.2 The original function signature
In order to hook this SSDT entry we need to define the original function in our code so our rootkit can switch safely between the original routine and the replacement one.
II.3 Various FILE_INFORMATION_CLASS structures
When the ZwQueryDirectoryFile routine is called, the returned results are stored in an array of structures representing a file. The first one is accessible using FileInformation OUT parameter. There are several types of structures to describe files, (they can vary depending on the OS version for example).
The FileInformationClass parameter is used to know the type of the FileInformation parameter.
There is a list of structures that can correspond to a file object on the msdn (
http://msdn.microsoft.com/en-us/library/ff728840%28v=vs.85%29.aspx). Here we will concentrate on structures that can be used by the ZwQueryDirectoryFile routine (see http://msdn.microsoft.com/en-us/library/ff567047%28v=vs.85%29.aspx).
We need to redefine these structures in our header’s code :
The interesting thing here is that all the structures have attributes in common, and more precisely the FileName and the NextEntryOffset.
The FileName use is trivial (just return the name of the file...).
The NextEntryOffset is the offset of the next FileInformation structure in the array.
For example, take a directory called foo, containing 2 files, bar1 and bar2.
If you query the next cmd code :
dir ./foo
The ZwQueryDirectoryFile kernel routine will be called and will write into the FileInformation a pointer to an array of two structures, one for bar1 and one for bar2 (in reality it is more complicated than that because . and .. are also in the array...).
We may not be sure about the FILE_INFORMATION_CLASS type but we know that :
The first structure FileName is "bar1" and its NextEntryOffset, when added to FileInformation is the memory address of the next structure.
The second structure FileName is "bar2" and its NextEntryOffset field is set to zero because it is the last structure in the array.>
II.4 Get and set common fields from any structure type
We do not want to write a replacement function for each different structure. So we are going to write functions to get the two common fields we need in any of them.
III. Main code.
III.1 ZwQueryDirectory Replacement routine
Now that we have enough information, we are ready to write a ZwQueryDirectoryFile replacement function that can hide any file we want.
III.2 Check if file should be hide
You should have noticed that hiding functionalities are used only if checkIfHiddenFile(WCHAR fileName) function returns TRUE. You can choose to write whatever you want in that function, if you want to hide several files, depending on what part of their names, etc.
In this code, I choose to stay simple, and just hide any file that starts with a given prefix ("hide_").
IV Conclusion
I am not a WDK specialist and any critics are welcomed. This hook should work nice on Windows XP and Vista 32 bit version. I didn’t test it on other versions. If you do, please give me a feedback.