Archive

Posts Tagged ‘NtQueryDirectoryFile’

Usermode File Hiding

April 25th, 2009

This is just a small snippet from one of my projects, designed to hide the presence of specific files at a process-local usermode level. It works by detouring NtQueryDirectoryFile in ntdll.dll (implementation of a detour engine is left as an exercise for the reader) and unlinking files from the linked list by their name.

Code tested and working on both x86 and x64 builds of Windows (Vista x86, Server 2008 x64).

// Generic file hiding function. Takes a pointer to a known file information
// linked list and unlinks (hides) arbitrary files
template <typename T>
void UnlinkFileEntries(PVOID pTemp)
{
// Pointers to the linked list
T* pCurrent = static_cast<T*>(pTemp);
T* pPrev = static_cast<T*>(pTemp);

// Loop until there are no more files to process
for (;;)
{
// Wide string to store the file name (initialized in case the given
// file name in the structure is empty or otherwise invalid)
std::wstring FileName(L”");
// Set the file name string to the string in the structure if it’s valid.
// Buffer not guaranteed to be zero terminated so the string length in
// the structure needs to be used (size is stored in bytes not chars)
if (pCurrent->FileNameLength)
FileName = std::wstring(pCurrent->FileName,pCurrent->FileNameLength / 2);
// Make checks case insensitive
std::transform(FileName.begin(),FileName.end(),FileName.begin(),tolower);

// Check if file should be hidden
if (Config::Get()->ShouldHideFile(FileName))
{
// Debug output
WDBGOUT(L”NtQueryDirectoryFile called! Hiding file: \”" << FileName
<< L”\”.”);

// Check for EOL
if (pCurrent->NextEntryOffset == 0)
{
// Hide file
pPrev->NextEntryOffset = pCurrent->NextEntryOffset;
// No files left to process
break;
}
else
{
// Hide file
pPrev->NextEntryOffset += pCurrent->NextEntryOffset;
}
}
else
{
// Check for EOL
if (pCurrent->NextEntryOffset == 0)
{
// No Files left to process
break;
}

// Next file
pPrev = pCurrent;
}

// Next file
pCurrent = reinterpret_cast<T*>(reinterpret_cast<PBYTE>(pCurrent)
+ pCurrent->NextEntryOffset);
}
}

// Detour function for NtQueryDirectoryFile.
// TODO: Add code to log any unknown file information classes (i.e. ones not
// being specifically ignored)
// TODO: Fix return value in cases where all the files on the list are hidden
NTSTATUS NTAPI NtQueryDirectoryFile_Hook(IN HANDLE FileHandle,
IN HANDLE EventHandle OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass,
IN BOOLEAN ReturnSingleEntry,
IN PUNICODE_STRING FileName OPTIONAL,
IN BOOLEAN RestartScan)
{
// Call the original function to get the needed data
NTSTATUS RetVal = ((tNtQueryDirectoryFile)(PROC)(g_NtQueryDirectoryFile))(FileHandle,EventHandle,ApcRoutine,
ApcContext,IoStatusBlock,FileInformation,Length,FileInformationClass,
ReturnSingleEntry,FileName,RestartScan);

// If function fails don’t bother trying to use the data
if (RetVal != STATUS_SUCCESS)
return RetVal;

// Handle all known and relevant file information classes and unlink
// any entries that shouldn’t be seen.
switch (static_cast<FILE_INFORMATION_CLASS_C>(FileInformationClass))
{
case FileDirectoryInformation_C:
UnlinkFileEntries<FILE_DIRECTORY_INFORMATION_C>(FileInformation);
break;

case FileFullDirectoryInformation_C:
UnlinkFileEntries<FILE_FULL_DIRECTORY_INFORMATION_C>(FileInformation);
break;

case FileBothDirectoryInformation_C:
UnlinkFileEntries<FILE_BOTH_DIRECTORY_INFORMATION_C>(FileInformation);
break;

case FileNamesInformation_C:
UnlinkFileEntries<FILE_NAMES_INFORMATION_C>(FileInformation);
break;

case FileIdBothDirectoryInformation_C:
UnlinkFileEntries<FILE_ID_BOTH_DIR_INFO>(FileInformation);
break;

default:
break;
}

// Return value from trampoline
return RetVal;
}

Notes:

  • Still needs minor improvements, but should be a decent starting ground for most.
  • WDBGOUT is a macro, feel free to remove the lines using it or provide your own implementation, it won’t break anything.
  • If you find any bugs or have any comments I’d love to hear them.
  • To use the code you will need to provide your own implementation of the required (undocumented) enums and structures.