Introduction

This article is the continue of the previously posted article
HideDriver.
Initially the first article was an experiment and the result of it exceeded all my expectations. I want to thank all readers who left comments and wrote emails, your opinions were really important for me! I hope that we will continue working together.

Like the first article this one doesn't pretend to be full and original. The main purpose of it is to represent the complicated info in some more popular way.

The method of hiding described in the previous article is very simple and widely known. Now I pretend to describe the method of detection of such hidden files and processes in simple and easy to understand way. This method is accompanied by the code developed to illustrate the words.

I plan to develop this topic by describing more complicated methods of hiding and detection in the new articles. I want to make each of the methods described as clear as possible - so if you have some questions or something is hard to understand then contact me and I'll update the corresponding article with the additional info.

There are a lot of code fragments in this article because I believe that it's better to see once than to hear for 100 times.

Projects used

I would like to thank the people who developed the projects listed below - they made the implementation of this project easier:

Levels of hiding

So let's start. First of all we should consider where the interception can be performed and how it can be avoided.

In this exapmle I described levels of file hiding, but it is valid for process hiding too, with a little correction.

Method described in this article works at the SSDT level. It is one of the simpliest level to make some changes (particullary hide objects) and that's why it's natural to consider it first.

Note that to detect a hidden information we should work at the level which is lower than the level where hiding is performed.

Detection method

The hiding method that uses SSDT is based on the fact that all calls in the system come through this table (see more deatils in Hide Driver article).
To avoid the interception at the SSDT level we should understand how this table is used.

System Service Descriptor Table

This table stores pointers to system functions. This table is used to find a function by index.

Thus to avoid SSDT address substitution we should get the original address of nt!NtXXX function, for example by means of MmGetSystemRoutineAddress() function.

Original hadler calls

But before we start with the calls of original functions let's consider how they work.

If you are not acquainted with the driver development for Windows, you may be interested to know that there are functions in kernel mode that differ only by prefix, Zw or Nt.

MSDN says: If the call occurs in user mode, you should use the name "NtCreateFile" instead of "ZwCreateFile".

Diference between ZwXXX and NtXXX functions.

To find difference we can use Windbg.

The most important information is marked in the example. The call in the first case is translated to nt!KiSystemService function, and 25h is the index of this function in SSDT table for test system.
Thus we can conclude that ZwXXX function calls NtXXX function using SSDT.

Proceeding in this way we can discover that the only difference between Nt and Zw functions is in Previous Mode parameter modification.

It means that to call the original function we should not only know its address but also set previous mode = kernel mode beforehand.

Note that Previous Mode affects the level of priveleges. Kernel handles are not accesible for the thread with Previous Mode equal to user mode.

Bypassing ExGetPreviousMode()

To bypass the check of Previous Mode we use the fact that all system threads have Previous Mode equal to kernel mode.

There are two methods to start some code in the system context: Work Items and System Threads. I use both.
Work Items is better for hidden process detection because it is faster, and thus corresponding actions take a very short time.
For hidden file detection it's better to use System Threads because detection can take very long.

Utility for function start in the system context

These utilities start the given function in the system context using Work Items (see IoQueueWorkItem() function).
As soon as С++ is used and exceptions are the essential part of it, these utilities also transmit std::exception and ones inherited from it, which were thrown from Work Item, to the point where the function was called from. The input parameters are function pointer and parameters that should be transmitted to this funcion.

CallFromWorkerThreadEx function is an auxiliary one, its task is to check if the pointer to the function transmitted as the first parameter accepts the parameters transmitted with the second parameter.

Hidden process detection

The detection of the hidden processes on the SSDT level is performed by comparing the obtained results of the original function and the function which address is indicated in the SSDT table.

In general we can divide the hidden process detection into three stages:

Receiving the function pointer.

Function call in the system context.

Analysis of the data obtained from the two functions.

Receiving the function pointer

Receiving the pointer for the function from the SSDT table by its name is implemented in the code below. It should be performed because the function can have different indices in SSDT table in different OS versions.

To minimize the volume of code shown, the content of the ServiceTableDef.h and VersionDependOffsets.h files is omitted.

All main stages of hidden processes detection are shown now.
The rest of stages is gui stuff or translation between user mode and kernel mode.
All of them can be found in sources attached.

Hidden file detection

Hidden file detection is very simular to hidden process detection. The main principle is the same: to compare the call of original function and intercepted one. So, the algorithm of hidden file detection resembles the one for file search on the disk.
We just will have two lists of files and folders obtained by the original function handler and the interceptor.

But there are some essencial differences:

Complication of algorithm for hidden resource search.

One of the pecularities of the kernel mode programming, comparing to user mode programming, is that we should pay attention on the limitation of the stack size, that is 12kb. To avoid this problem I decided to refuse from the recursive algorithm of file search but to use std::stack - container from STL, it transformed the recursive algorithm into the non-recursive one.

The algorithm description will be given in the next topic.

The time of detection is much longer and is not detected in advance.

This problem causes the next one.

Complication of algorithm of data exchange between user application and driver.

When the hidden processes are detected the result is the list of them, which can be returned by user request. When the hidden files are detected the driver cannot act like that as far as the process of hidden file search can take a very long time. Thus it should periodically notify the user part of the application about the state of hidden file detection. This functionality is not described in this article as soon as it's rather simple.

File search architecture

Before I started the development I had researched the solutions of the simular tasks at the user level. I had found that the solution from Microsoft was very suitable. The MFC library contains very useful class CFileFind.
Continuing research I had discovered that there are no functions FindFirstFile and FindNextFile in kernel mode, and there is function ZwQueryDirectoryFile instead.
It meant that I had to develop my own analogues for these functions. And also I had to take into account that there was also NtQueryDirectoryFile function and thus I had to abstruct away from the specific version.

Utils for file search in kernel mode

Now, when we've already considered the auxilary classes, we can proceed to FileSearcher class, which implements non-recursive file search, and FileEnumerator class, which implements the file enumeration in one directory.

it may be not specific to the hiding of drivers but is in the same "research" field: malware/rootkit (detection). My question is: how can I access the page directory entries / page table entries under Windows 7 32 Bit PAE with a kernel driver?

I tried to dumped with my own kernel driver (based on your one and other ones) the values at 0xC0600000, 0xC0000000, 0xC0300000 to DbgView - but got only zeroes and/or unusable results - also by "attaching" with KeStackAttachProcess/KeAttachProcess (The drivers are already in context of System Process). With LiveKd/WinDbg I got correct values. In a driver coding tut of "HolyFather" the driver accessed driectly the area - without attaching. He just only loaded the values into CR3. I thought if I attach to system process the CR3 value will be loaded automatically?

Hi Ivan,First of all thank you for your submissions.I found them very useful and detailed.

And now, there is my question: have you ever done a DLL version of the projects? I'm asking it because even if I had no problem compiling your code (I just followed your instructions!) I'm not so good with C to get a DLL from it by myself.

ThanksNeo F.R.W.

P.S. Binary+Source will be much appreciatedP.P.S. Sorry for my English!!!

I suppose that there are problems with accessing DDK. I use exactly the same DDK and do not have troubles.Please try to repeat all steps from the beginning - if it doesn't work write me back.If problems still exist please write me an output from building single project, for example drvCppLib.

First I was surprised with "and.." in your quote. So I looked at the path from your previous message:c:\documents and settings\administrador\meus documentos\downloads\c++ detect hidden\detectdriversrc\detectdriver\src\detectdrivergui\stdafx.h