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


About the Author

Vitali Halershtein

I'm a professional Software Developer with more than 10 years experience. Certifications: MCSD, MCP, Brainbench, Masters Degree in Computer Science. I am open for contacts and interesting ideas. You can write me at: vitali_eh@yahoo.com

Comments

  • Merkt u theMonster hoofdtelefoon die zeker aanzienlijke bescherming heeft

    Posted by mrswanzi on 06/06/2013 02:43pm

    [url=http://koptelefoon-monsterbeats.weebly.com/]beats by dre kopen[/url] Daarom wil je een open koptelefoon Een gesloten koptelefoon zorgt ervoor dat je akoestisch wordt afgesloten van alles wat om je heen gebeurt. Er wordt geen geluid vanuit de hoofdtelefoon naar de omgeving ¡®gelekt¡¯. Een gesloten koptelefoon geeft vaak een wat drukkend en minder natuurgetrouw geluid weer. Een open hoofdtelefoon, zoals deze Beats By Dre Real, heeft echter een open klankkast en laat daardoor meer geluid door en laat de druk 'ontsnappen'. Er ontsnapt letterlijk geluid doordat de oorschelp aan de buitenkant open is. Dit heeft absoluut geen kwaliteitsverlies of een verlies aan bas tot gevolg. Als drager hoor je bij deze constructie ook het omgevingsgeluid. Heeft iemand naast je in de trein een koptelefoon op waarbij jij het geluid hoort, is het heel goed mogelijk dat hij of zij een open hoofdtelefoon heeft. [url=http://koptelefoon-monsterbeats.tumblr.com/]beats by dre[/url] De speakers doen werkelijk waar hun naam aan, want ze lijken inderdaad op een pil. De Beats by Dre Pill speakers werken geheel draadloos en maken gebruik van Bluetooth, maar je kunt ook een kabel erin pluggen. Een andere feature is de mogelijkheid een telefoongesprek te voeren via de Beats by Dre Pill speakers door de ingebouwde microfoon.De Beats by Dre Pill en Beats Executive zijn nog niet gelanceerd in Nederland, maar al wel in de Verenigde Staten. De Pill speaker is verkrijgbaar in drie soorten uitvoeringen: wit, rood en zwart. De hoge kwaliteit koptelefoons¡ª¡ªBeats by Dr Dre Studio koptelefoon [url=http://monsterbeats.webgarden.es/]beats by dre[/url] De samenwerking met LeBron James past perfect in de endorsement marketing strategie die Monster Cable en Beats Electronics, het bedrijf van Dr. Dre en muziekproducent Jimmy Iovine, hebben uitgedacht. Nog voor de headphones voor de consument op de markt verschenen, liepen verschillende grote artiesten uit de Amerikaanse hip hop- en rapscene al met een Beats by Dr. Dre rond.

    Reply
  • ghd fladjern er meget populær i Danmark, kan vi tilbyde autentiske ghd glattejern 2011

    Posted by motherdhmm on 05/30/2013 07:59pm

    [url=http://www.blog.cheapbeatsbydre.co.nz/beats-by-dre-headphones]beats by dre headphones[/url] du købe vores produkter ghd glattejern, du markere din nøgle personlige oplysninger. For nærmere oplysninger se vores FAQ og så [url=http://www.blog.cheapbeatsbydre.co.nz/]beats by dre nz[/url] maj menneskelige modstander i planeten væsentligt flere personer ofte nå udfordringer på indersiden tab af hår, for folk se, hår [url=http://www.blog.cheapbeatsbydre.co.nz/monster-headphone]monster beats headphone[/url] ghd fladjern også kendt som elektriske krydsfiner, er krydsfiner populært kaldes, er opvarmet af aktuelle ghd glattejern for MCH eller PTC varmelegeme eller varmt wire, aluminium eller keramik plade til at overføre varme. ghd glattejern, Guming Si Yi er at glatte håret, håret gennem varmeelement for varme, blødgøre, og derefter afkølet for at opnå formålet med glat hår. Nu ghd glattejern, glatte begge dele, og kan trække lydstyrken. Ghd glattejern før, den største bruger er en professionel salon barber, Europa og Amerika fra 2007 personer er kommet på hjemmemarkedet, til hår derhjemme kan være en SPA. Ghd glattejern vil nu ind på det danske hjemmemarked, vil være en væsentlig produkter til personlig pleje, ligesom kamme den samme popularitet.

    Reply
  • PocketPC/WindowsMobile

    Posted by badzio on 10/23/2008 03:44am

    Is similar solution for PocketPC/WindowsMobile (but not based on CF .Net)?

    Reply
  • I'm Can't change file name

    Posted by baby999 on 04/23/2008 06:10am

    I'm Can't change file name 
    
    void ThreadRoute1( void* arg )	
    	{
      USES_CONVERSION;
      TCHAR szDir[MAX_PATH];
      GetCurrentDirectory(sizeof(szDir)/sizeof(TCHAR),szDir); 
    
      HANDLE hDir = CreateFile( CString(szDir), // 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
      );
    Should change to 
    
    void ThreadRoute1( void* arg )	
    	{
      USES_CONVERSION;
      TCHAR szDir[MAX_PATH];
      GetCurrentDirectory(sizeof(szDir)/sizeof(TCHAR),szDir); 
    
      HANDLE hDir = CreateFile( CString(szDir), // pointer to the file name
        FILE_LIST_DIRECTORY,                // access (read/write) mode
        FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,  // share mode //add  by xiaobb 
        NULL,                               // security descriptor
        OPEN_EXISTING,                      // how to create
        FILE_FLAG_BACKUP_SEMANTICS,         // file attributes
        NULL                                // file with attributes to copy
      );

    Reply
  • Folder locking & Password protection code

    Posted by c0mgu1 on 08/09/2005 06:59am

    I need a sample code for setting a password for accessing a folder & it contined subfolders/files plz help me

    Reply
  • i need notification message before event occure

    Posted by c0mgu1 on 08/09/2005 06:57am

    Here we are getting notification message after the event happence like after file deletion, but how to get an event before deletion...

    Reply
  • how can i get the last filename after rename?

    Posted by yqzq on 07/15/2005 05:54am

    how can i get the last filename after rename? when i rename the folder,like "AAA" to "BBB" but i can only get the filename from Buffer[i] is "AAA" why?

    Reply
  • how can i get the last filename after rename?

    Posted by yqzq on 07/15/2005 05:47am

    how can i get the last filename after rename? when i rename the folder,like "AAA" to "BBB" but i can only get the filename from Buffer[i] is "AAA" why?

    Reply
  • Beware if you use snippets from this sample code.

    Posted by HSmith on 05/07/2005 08:43am

    The following segment of code is invalid. I used this snippet of code in my application and it took quite some time to track down the defect. I have found other samples on the net that use they same method, they are also incorrect.
    
        do
          {
          m_Sec.Lock();
          int item = pList1->InsertItem(pList1->GetItemCount(), CString(Buffer[i].FileName).Left(Buffer[i].FileNameLength / 2) + " - " + helper_txt );
    		  pList1->SetItemText(item, 1, tm.Format("%Y/%m/%d/ - %H:%M:%S"));
          i++;
          m_Sec.Unlock();
          }
        while (!Buffer[i].NextEntryOffset);
    
    In the loop, Buffer[i] is accessed. This is only valid for the first record returned (and yes, multiple records are returned sometimes). 
    
    The list of file notification records cannot be accessed as an array, you should use a pointer instead. When advancing to the next record, you need to add pBuffer->NextEntryOffset to the pointer to access the next record.
    
    See the definition of:
    
    typedef struct _FILE_NOTIFY_INFORMATION {
       DWORD NextEntryOffset;
       DWORD Action;
       DWORD FileNameLength;
       WCHAR FileName[1];
    } FILE_NOTIFY_INFORMATION;
    
    Also note that the string returned is not null terminated. The file length is returned in bytes, not character counts. You should perform a wide character string copy as follows:
    
    wchar_t WideStringFileName[MAX_STRING_LENGTH * sizeof(wchar_t)];
    
    // The filenames returned are not null terminated. Copy the characters and null terminate the string.
    
    if (pBuffer->FileNameLength < sizeof(WideStringFileName)) {
      // Copy the filename.
      wcsncpy(WideStringFileName,pBuffer->FileName,pBuffer->FileNameLength/sizeof(wchar_t));
      // Null Terminate the string.
      WideStringFileName[pBuffer->FileNameLength/sizeof(wchar_t)]=L'\0';
     }
     else
       WideStringFileName[0]=L'\0';
    
    ---

    Reply
  • The file changed can't be renamed?

    Posted by leaflau on 09/14/2004 10:54pm

    What results this "bug"?

    • Upate

      Posted by Don Luis Perenna on 06/19/2005 09:06am

      Good Code, but it could be a good thing to update it . I had the same prb than leaflau...

      Reply
    • Thanks

      Posted by Vitali on 09/16/2004 07:30am

      Thank you too for the good question.

      Reply
    • I c

      Posted by leaflau on 09/16/2004 05:25am

      I'm sorry for my mistake.I missed out another thread in my program. Thanks.

      Reply
    • Just add FILE_SHARE_WRITE to allow rename files

      Posted by Vitali on 09/16/2004 04:00am

      You wrote:
      for example, a new file was created in the folder i spying. I found this event, but unable to rename the file anyway now. Just have a try!
      Solution:
      Just use FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE
      instead FILE_SHARE_READ|FILE_SHARE_DELETE to solve it.

      Reply
    • It's not the case i refered

      Posted by leaflau on 09/15/2004 12:50pm

      Assume that your program is running and spying the folder "c:\Program Files" all along. And now, create a new file in this folder, not through your program, but windows Explorer, then try to rename it. No problem?

      Reply
    • ok, no problems

      Posted by Vitali on 09/15/2004 06:18am

      Please pay attention on the following code fragment:

      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
      );

      in the demo project I was specify only FILE_SHARE_READ|FILE_SHARE_DELETE

      To solve this problem in yours projects just add FILE_SHARE_WRITE.

      Hope this will helpful.

      Reply
    • That is

      Posted by leaflau on 09/15/2004 04:59am

      for example, a new file was created in the folder i spying. I found this event, but unable to rename the file anyway now. Just have a try!

      Reply
    • What does you mean?

      Posted by Vitali on 09/15/2004 03:56am

      Please describe what exactly you mean when writing this question?

      Reply
    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

  • On-demand Event Event Date: October 23, 2014 Despite the current "virtualize everything" mentality, there are advantages to utilizing physical hardware for certain tasks. This is especially true for backups. In many cases, it is clearly in an organization's best interest to make use of physical, purpose-built backup appliances rather than relying on virtual backup software (VBA - Virtual Backup Appliances). Join us for this webcast to learn why physical appliances are preferable to virtual backup appliances, …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds