Introduction
Windows applications can do dynamic monitoring of any specified directory.
Once changes have occurred and are detected, the spy application can run
various tasks ( run antivirus, log activity, determine more information about
changes, call other tasks etc).
Win 32 API provides three functions that are based on the events:
FindFirstChangeNotification
FindNextChangeNotification
FindCloseChangeNotification
ReadDirectoryChangesW
These allow creating watchdog or spying applications.
How to create
First of all spy application should call
FindFirstChangeNotification
to create event handler to monitor changes specified as the functions
parameters.
HANDLE h = FindFirtsChangeNotification("C:\\Program Files", TRUE, mask);
This function allows to handle following types of notifications:
-
FILE_NOTIFY_CHANGE_FILE_NAME
– File creating, deleting and file
name changing
-
FILE_NOTIFY_CHANGE_DIR_NAME
– Directories creating, 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 FindFirstChangeNotification
can be passed as
parameter in to WaitForSingleObject
and when specified event has
occurred, application can do various actions such as: antivirus starting, adding
record to the log file, and so on. Note that this function does not detect
changes, it only creates synchronization event and marks it if changes are made.
After our spy application handles changes, it should call
FindNextChangeNotification
to continue monitoring or
FindCloseChangeNotification
to finish it.
Win32 API provides also ReadDirectoryChangesW
that can operate
with following filters (MSDN) :
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
Give your attention to the following code in the demo project:
void ThreadRoute( void* arg )
{
HANDLE 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();
item = pList->InsertItem(pList->GetItemCount(), ((Param*)arg)->message);
pList->SetItemText(item, 1, tm.Format("%Y/%m/%d/ - %H:%M:%S"));
m_Sec.Unlock();
}
}
and here is the fragment using ReadDirectoryChangesW
void ThreadRoute1( void* arg )
{
USES_CONVERSION;
HANDLE hDir = CreateFile(
CString("c:\\Program Files"),
FILE_LIST_DIRECTORY,
FILE_SHARE_READ|FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL
);
FILE_NOTIFY_INFORMATION Buffer[1024];
DWORD BytesReturned;
while( ReadDirectoryChangesW(
hDir,
&Buffer,
sizeof(Buffer),
TRUE,
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,
&BytesReturned,
NULL,
NULL))...
These are thread functions that do the described spying actions.
Conclusion
The attached Demo application starts separate threads to monitor all possible
changes in the "c:\\Program Files" directory and shows occurred
notifications and its date/time in the List control. Demo application shows also
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 freedom to modify and use the demo project.