Spying a File System



Click here for a larger image.

Describes how to create the basis for a file system spy application

Introduction

Windows applications can do dynamic monitoring of the specified directory. Once changes occur and are detected, a spy application can run various tasks (run antivirus, log activity, determine more information about changes, or call other tasks).

The Win 32 API provides three functions that are based on the following events:

  • FindFirstChangeNotification
  • FindNextChangeNotification
  • FindCloseChangeNotification
  • ReadDirectoryChangesW

This allows you to create a watchdog or spying application.

How to Create the Application

First of all, a spy application should call FindFirtsChangeNotification to create an event handler to monitor changes specified as the function’s parameters.

HANDLE h = FindFirtsChangeNotification(C:\\Program Files,
                                        TRUE, mask);

This function allows us to handle the following types of notifications:

Notification Description
FILE_NOTIFY_CHANGE_FILE_NAME File creating and deleting, and file name changing
FILE_NOTIFY_CHANGE_DIR_NAME Directory creating and deleting, and file name changing
FILE_NOTIFY_CHANGE_ATTRIBUTES File or Directory attributes changing
FILE_NOTIFY_CHANGE_SIZE File size changing
FILE_NOTIFY_CHANGE_LAST_WRITE Changing time of write of the files
FILE_NOTIFY_CHANGE_SECURITY Changing in security descriptors

The result of FindFirtsChangeNotification can be passed as a parameter in to WaitForSingleObject. When the specified event occurs, the application can do various actions, such as antivirus starting, adding a record to the log file, and so on. Note that this function does not detect changes; it only creates a synchronization event and marks it if changes are made. After our spy application handling changes, it should call FindNextChangeNotification to continue monitoring, or FindCloseChangeNotification to finish it.

The Win32 API also provides ReadDirectoryChangesW that can operate with the following filters (MSDN):

Filter Description
FILE_NOTIFY_CHANGE_FILE_NAME Any file name change in the watched directory or subtree causes a change notification wait operation to return. Changes include renaming, creating, or deleting a file.
FILE_NOTIFY_CHANGE_DIR_NAME Any directory name change in the watched directory or subtree causes a change notification wait operation to return. Changes include creating or deleting a directory.
FILE_NOTIFY_CHANGE_ATTRIBUTES Any attribute change in the watched directory or subtree causes a change notification wait operation to return.
FILE_NOTIFY_CHANGE_SIZE Any file size change in the watched directory or subtree causes a change notification wait operation to return. The operating system detects a change in file size only when the file is written to the disk. For operating systems that use extensive caching, detection occurs only when the cache is sufficiently flushed.
FILE_NOTIFY_CHANGE_LAST_WRITE Any change to the last write-time of files in the watched directory or subtree causes a change notification wait operation to return. The operating system detects a change to the last write-time only when the file is written to the disk. For operating systems that use extensive caching, detection occurs only when the cache is sufficiently flushed.
FILE_NOTIFY_CHANGE_LAST_ACCESS Any change to the last access time of files in the watched directory or subtree causes a change notification wait operation to return.
FILE_NOTIFY_CHANGE_CREATION Any change to the creation time of files in the watched directory or subtree causes a change notification wait operation to return.
FILE_NOTIFY_CHANGE_SECURITY Any security descriptor change in the watched directory or subtree causes a change notification wait operation to return.

Sample

Please pay attention to the following code in the demo project:

void ThreadRoute( void* arg )
  {
  HANDLE file;
  file = FindFirstChangeNotification("c:\\Program Files",
                                     FALSE, (DWORD)
                                     ((Param*)arg)->parameter);
  WaitForSingleObject(file, INFINITE);

  CTime tm = CTime::GetCurrentTime();
  m_Sec.Lock();
  int item = pList->InsertItem(pList->GetItemCount(),
             ((Param*)arg)->message);
  pList->SetItemText(item, 1, tm.Format("%Y/%m/%d - %H:%M:%S"));
  m_Sec.Unlock();

  while (true)
    {
    FindNextChangeNotification(file);
    WaitForSingleObject(file, INFINITE);
    tm = CTime::GetCurrentTime();
    m_Sec.Lock();
    int item = pList->InsertItem(pList->GetItemCount(),
               ((Param*)arg)->message);
    pList->SetItemText(item, 1, tm.Format("%Y/%m/%d/ - %H:%M:%S"));
    m_Sec.Unlock();
    }
  }

and the fragment that uses ReadDirectoryChangesW:

void ThreadRoute1( void* arg )
  {
  USES_CONVERSION;
  HANDLE hDir = CreateFile( CString("c:\\Program Files"),
                                        /* pointer to the file
                                           name */
    FILE_LIST_DIRECTORY,                /* access (read-write)
                                           mode */
    FILE_SHARE_READ|FILE_SHARE_DELETE,  /* share mode */
    NULL,                               /* security descriptor */
    OPEN_EXISTING,                      /* how to create */
    FILE_FLAG_BACKUP_SEMANTICS,         /* file attributes */
    NULL                                /* file with attributes to
                                           copy */
  );

  FILE_NOTIFY_INFORMATION Buffer[1024];
  DWORD BytesReturned;
  while( ReadDirectoryChangesW(
                                hDir,            /* handle to
                                                    directory */
                                &Buffer,         /* read results
                                                    buffer */
                                sizeof(Buffer),  /* length of
                                                    buffer */
                                TRUE,            /* monitoring
                                                    option */
                                FILE_NOTIFY_CHANGE_SECURITY|
                                FILE_NOTIFY_CHANGE_CREATION|
                                FILE_NOTIFY_CHANGE_LAST_ACCESS|
                                FILE_NOTIFY_CHANGE_LAST_WRITE|
                                FILE_NOTIFY_CHANGE_SIZE|
                                FILE_NOTIFY_CHANGE_ATTRIBUTES|
                                FILE_NOTIFY_CHANGE_DIR_NAME|
                                FILE_NOTIFY_CHANGE_FILE_NAME,
                                                 /* filter
                                                    conditions */
                                &BytesReturned,  /* bytes
                                                    returned */
                                NULL,            /* overlapped
                                                    buffer */
                                NULL))...        /* completion
                                                    routine */

These are thread functions that do the described spying actions.

Conclusion

The demo application starts separate threads to monitor all possible changes in the C:\\Program Files directory and shows occurred notifications and their date/time in the List control. The demo applicaton also shows how to use ReadDirectoryChangesW and compare both methods visually.

Functionality of the demo application can be extended to determine concrete changes, to log changes in to file, run external applications or tasks on the specified event, use described methods as system service, and so on. Readers have full spaciousness for demo usage.

Downloads


Download demo project – 30 Kb

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read