转自
http://www.codeproject.com/KB/system/hide-driver.aspx
Introduction
We are glad to introduce our project "The Hide Driver project".
The main idea of this work is to create a driver for hiding selected processes and files.
The processes selected by the user should be invisible for such applications as the Task Manager, Process Explorer, and others. In addition, they should not be available for such Windows API functions as EnumProcesses()
, OpenProcess()
, EnumProcessModules()
, and other Process APIs. The files selected by the user should be invisible for such file managers as Windows Explorer, Far, Total Commander, etc. In addition, they should not be available for such Windows API functions as FindFile()
, OpenFile()
, and other File API functions.
Basic knowledge
We recommend the article "Driver Development" by Toby Opferman:
It would also be useful to look through the other articles in the series (parts 2, 3, 4, 5, 6).
Also, a lot of knowledge that helped us develop this project was obtained here:
For Russian speaking readers, we recommend these sources:
Project structure
Collapse Copy Code
.\bin - folder with binary files
.\obj - folder with intermediate files
.\src - folder with sources
|
|-> drvCppLib - Kernel library to develop driver in C++
|-> Gui - Win32 Application used to communicate with driver
|-> HideDriver - Kernel driver installed by Gui App. Performs main
work.
|-> TestDriver - Kernel library to run test code
How to build this solution
- Install the Windows Driver Developer Kit 2003: http://www.microsoft.com/whdc/devtools/ddk/default.mspx.
- Set the global environment variable "BASEDIR" to the path of the installed DDK.
Computer Properties -> Advanced -> Environment Variables ->System Variables -> New.
Like this: BASEDIR -> c:\winddk\3790. (You have to restart your computer after this.)
VS2003
If you choose Visual Studio 2003, then you can simply open HideDriver_vs7.sln and Build All.
VS2005 & VS2008
If you choose Visual Studio 2005 or 2008, you need to copy the contents of the folder C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\crt\src\intel\st_lib\ (the path depends on the Visual Studio install path) to the project folder HideDriver_source\src\drvCppLib\lib_copy\. After this, you can use HideDriver_vs8.sln in Visual Studio 2005 and HideDriver_vs9.sln Visual Studio 2008.
Project implementation
The task described in the Introduction was resolved by using one of the general ways - Hooking SSDT. A lot of information about this technology can be found in the articles mentioned in the Basic knowledge section.
Process hiding
To hide processes, we need to cut them from the list returned by NtQuerySystemInformation()
.
[Code from HookProcess.cpp] From Line # 451 to 512
Collapse Copy Code
NTSTATUS NewNtQuerySystemInfo(
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
IN OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength OPTIONAL
)
{
NTSTATUS status=TrueNtQuerySystemInfo(SystemInformationClass,
SystemInformation, SystemInformationLength, ReturnLength);
if(!NT_SUCCESS(status))return status;
if( SystemInformationClass == SystemProcessesAndThreadsInformation )
{
SYSTEM_PROCESSES_INFORMATION*
pSystemInfo=static_cast<system_processes_information*>(SystemInformation);
ULONG PreviousDelta=0;
while( pSystemInfo->NextEntryDelta != 0 )
{
PreviousDelta = pSystemInfo->NextEntryDelta;
pSystemInfo = (SYSTEM_PROCESSES_INFORMATION*)
(((PUCHAR)pSystemInfo)+PreviousDelta);
if( CheckProcess(&(pSystemInfo->ProcessName)) )
{
ULONG curentDelta=pSystemInfo->NextEntryDelta;
pSystemInfo =
(SYSTEM_PROCESSES_INFORMATION*)(((PUCHAR)pSystemInfo)-PreviousDelta);
if(curentDelta == 0 )
PreviousDelta=0;
pSystemInfo->NextEntryDelta = PreviousDelta + curentDelta;
}
}
}
return status;
}
File hiding
To hide a file, we need to cut it from the list returned by NtQueryDirectoryFile()
.
First, we choose what type of information is requested.
[Code from HookFile.cpp] From Line # 672 to 719
Collapse Copy Code
NTSTATUS NewNtQueryDirectoryFile(
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG FileInformationLength,
IN FILE_INFORMATION_CLASS FileInformationClass,
IN BOOLEAN ReturnSingleEntry,
IN PUNICODE_STRING FileName OPTIONAL,
IN BOOLEAN RestartScan
)
{
NTSTATUS status=TrueNtQueryDirectoryFile(FileHandle,Event,
ApcRoutine,ApcContext,IoStatusBlock,
FileInformation,FileInformationLength,FileInformationClass,
ReturnSingleEntry, FileName , RestartScan);
if(!NT_SUCCESS(status))return status;
switch(FileInformationClass)
{
case FileDirectoryInformation:
return HideFile<pfile_directory_information>(FileHandle,FileInformation);
case FileFullDirectoryInformation:
return HideFile<pfile_full_directory_information>(FileHandle,FileInformation);
case FileBothDirectoryInformation:
return HideFile<pfile_both_directory_information>(FileHandle,FileInformation);
case FileNamesInformation:
return HideFile<pfile_names_information>(FileHandle,FileInformation);
case FileIdBothDirectoryInformation:
return HideFile<pfile_id_both_dir_information>(FileHandle,FileInformation);
case FileIdFullDirectoryInformation:
return HideFile<pfile_id_full_dir_information>(FileHandle,FileInformation);
default:return status;
}
}
When we know what type of information is requested, we can cut the process from the list.
[Code from HookFile.cpp] From Line # 572 - 719
Collapse Copy Code
template<class>
NTSTATUS HideFile(HANDLE FileHandle,PVOID FileInformation)
{
ULONG PreviousDelta=0;
UNICODE_STRING UnicodeFileName;
RtlInitUnicodeString(&UnicodeFileName,NULL);
T pFileInfo=reinterpret_cast<t>(FileInformation);
bool pass_me_once=true;
while( (pFileInfo->NextEntryOffset != 0) || pass_me_once)
{
if(pass_me_once)
pass_me_once=false;
else
{
PreviousDelta = pFileInfo->NextEntryOffset;
pFileInfo = (T)(((PUCHAR)pFileInfo)+pFileInfo->NextEntryOffset);
}
UnicodeFileName.Buffer = pFileInfo->FileName;
UnicodeFileName.Length = pFileInfo->FileNameLength;
UnicodeFileName.MaximumLength = pFileInfo->FileNameLength;
if(!CheckFile(&UnicodeFileName,FileHandle))
continue;
if(PreviousDelta == 0)
{
if( pFileInfo->NextEntryOffset == 0 )
return STATUS_NO_MORE_FILES;
ULONG shift = pFileInfo->NextEntryOffset;
ULONG totalSize=0;
T ptempFileInfo=(T)pFileInfo;
while(ptempFileInfo->NextEntryOffset != 0)
{
totalSize+=ptempFileInfo->NextEntryOffset;
ptempFileInfo = (T)(((PUCHAR)ptempFileInfo)+
ptempFileInfo->NextEntryOffset);
}
size_t MoveSize = (size_t)(totalSize-shift);
MoveSize += sizeof(*ptempFileInfo);
MoveSize += ptempFileInfo->FileNameLength;
MoveSize -= 2;
memcpy((PVOID)pFileInfo,(PUCHAR)pFileInfo+(size_t)(shift),MoveSize);
pass_me_once=true;
PreviousDelta = 0;
continue;
}
ULONG curentDelta=pFileInfo->NextEntryOffset;
pFileInfo = (T)(((PUCHAR)pFileInfo)-PreviousDelta);
if(curentDelta == 0 )
{
pFileInfo->NextEntryOffset = 0;
break;
}
pFileInfo->NextEntryOffset = PreviousDelta + curentDelta;
}
return STATUS_SUCCESS;
}
GUI application
The GUI application enables a user to choose processes or/and files for hiding in an easy way. In the attached file, you can find a sample of such an application. It was developed using MFC.
But, it should be mentioned here that you can create your own GUI application. IOCTLs and the DeviceIoCotrol()
routine should be used for communication between the user-mode application and the driver.
You can find additional information about such communication implementations in the article: Driver Development Part 2: Introduction to Implementing IOCTLs.
In the code below, all IOCTLs which can be used have been mentioned:
Collapse Copy Code
#define IOCTL_ADD_PROCESS_NAME CTL_CODE( \
FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
Format of input string must be ¬process_name_to_hide;user_name;process_name
or ¬process_name_to_hide;*;*
where:
process_name_to_hide – process name to hide; can be for ex. *.*
user_name - user' name, which mustn’t see process
process_name - process' name, which mustn’t see process
#define IOCTL_DEL_PROCESS_NAME CTL_CODE( \
FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)
Format of input string must be process_name
where:
process_name - process' name, which should be deleted from the list
#define IOCTL_CLEAR_PROCESS_NAME CTL_CODE( \
FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)
Input string should be empty.
#define IOCTL_QUERY_PROCESS_NAME CTL_CODE( \
FILE_DEVICE_UNKNOWN, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS)
Format of output string is process prosess_name\nprocess_name\n…\0
// File hooks IOCTLs
#define IOCTL_ADD_FILE_NAME CTL_CODE( \
FILE_DEVICE_UNKNOWN, 0x901, METHOD_BUFFERED, FILE_ANY_ACCESS)
Format of input string must be file_name_to_hide;user_name;process_name
or file_name_to_hide;*;*
where:
file_name_to_hide – file name to hide; can be for ex. *.*
user_name - user' name, which mustn’t see process
process_name - process' name, which mustn’t see process
#define IOCTL_DEL_FILE_NAME CTL_CODE( \
FILE_DEVICE_UNKNOWN, 0x902, METHOD_BUFFERED, FILE_ANY_ACCESS)
Format of input string must be file_name
where:
file_name - file' name, which should be deleted from the list
#define IOCTL_CLEAR_FILE_NAME CTL_CODE( \
FILE_DEVICE_UNKNOWN, 0x903, METHOD_BUFFERED, FILE_ANY_ACCESS)
Input string should be empty.
#define IOCTL_QUERY_FILE_NAME CTL_CODE( \
FILE_DEVICE_UNKNOWN, 0x904, METHOD_BUFFERED, FILE_ANY_ACCESS)
Format of output string is process file_name\nfile_name\n…\0
Documentation and additional info
Documentation for the project as well as additional information can be found at the Apriorit Education page.
History
21/01/2009
- Initial version of this article.
12/02/2009
- Added possibility to build the solution in VS2003, VS2005, and VS2008.
- Added the topic "How to build this solution".