WDK Mini Filter Example
scan.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) 2011 Microsoft Corporation
4 
5 Module Name:
6 
7  scan.c
8 
9 Abstract:
10 
11  This modules wraps the scanning routines.
12 
13 Environment:
14 
15  Kernel mode
16 
17 --*/
18 
19 #include "avscan.h"
20 
21 //
22 // Local routines prototypes.
23 //
24 
27  _In_reads_bytes_(Size) PVOID StartingAddress,
28  _In_ SIZE_T Size,
29  _In_ PBOOLEAN OperationCanceled
30  );
31 
32 NTSTATUS
34  _Inout_ PAV_SECTION_CONTEXT SectionContext,
35  _Out_ AVSCAN_RESULT *ScanResult
36  );
37 
38 //
39 // Routine implementaions
40 //
41 
44  _In_reads_bytes_(Size) PVOID StartingAddress,
45  _In_ SIZE_T Size,
46  _In_ PBOOLEAN OperationCanceled
47  )
48 /*++
49 
50 Routine Description
51 
52  A helper function to scan the memory starting at StartingAddress.
53  This function is only called if the scan mode is AvKernelMode.
54 
55 Arguments
56 
57  StartingAddress - The starting memory address to be scanned.
58 
59  Size - The size of the memory to be scanned.
60 
61  OperationCanceled - In the scan loop, it is supposed to poll this flag,
62  to see if the operation has been canceled.
63 
64 Return Value
65 
66  The scan result
67 
68 --*/
69 {
70  UCHAR targetString[AV_DEFAULT_SEARCH_PATTERN_SIZE] = {0};
71  SIZE_T searchStringLength = AV_DEFAULT_SEARCH_PATTERN_SIZE-1;
72  ULONG ind;
73  PUCHAR p;
74  PUCHAR start = StartingAddress;
75  PUCHAR end = start + Size - searchStringLength;
76 
77  //
78  // Decode the target pattern.
79  //
80 
81  RtlCopyMemory( (PVOID) targetString,
84 
85  for (ind = 0;
86  ind < searchStringLength;
87  ind++) {
88 
89  targetString[ind] = ((UCHAR)targetString[ind]) ^ AV_DEFAULT_PATTERN_XOR_KEY;
90  }
91  targetString[searchStringLength] = '\0';
92 
93  //
94  // Scan the memory stream for the target pattern.
95  //
96 
97  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
98  ("[Av]: ASMS: %p, %p, %llu, %llu\n",
99  start,
100  end,
101  Size,
102  searchStringLength) );
103 
104  for (p = start; p <= end; p++) {
105 
106  // if not canceled, continue to search for pattern
107  if((*OperationCanceled)) {
108 
110  }
111 
112  if (RtlEqualMemory( p, targetString, searchStringLength )) {
113 
114  return AvScanResultInfected;
115  }
116  }
117 
118  *OperationCanceled = FALSE; // Reset the cancel flag, after breaks out the loop.
119 
120  return AvScanResultClean;
121 }
122 
123 NTSTATUS
125  _Inout_ PAV_SECTION_CONTEXT SectionContext,
126  _Out_ AVSCAN_RESULT *ScanResult
127  )
128 /*++
129 
130 Routine Description
131 
132  A helper function to map the section object and scan the mapped memory.
133 
134 Arguments
135 
136  SectionContext - Section context containing section object and handle.
137 
138  Infected - Return TRUE if the file is infected.
139 
140 Return Value
141 
142  Returns the status of this operation.
143 
144 --*/
145 {
146  NTSTATUS status;
147  CLIENT_ID clientId;
148  OBJECT_ATTRIBUTES objAttribs;
149  HANDLE processHandle = NULL;
150  PVOID scanAddress = NULL;
151  SIZE_T scanSize = 0;
152  AVSCAN_RESULT scanResult;
153 
154  clientId.UniqueThread = PsGetCurrentThreadId();
155  clientId.UniqueProcess = PsGetCurrentProcessId();
156 
157  InitializeObjectAttributes(&objAttribs,
158  NULL,
159  OBJ_KERNEL_HANDLE,
160  NULL,
161  NULL );
162 
163  status = ZwOpenProcess( &processHandle,
164  PROCESS_ALL_ACCESS,
165  &objAttribs,
166  &clientId );
167 
168  if (!NT_SUCCESS( status )) {
169 
170  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
171  ("[Av]: AvMapSectionAndScan: Failed to open the process, 0x%08x\n",
172  status) );
173  goto Cleanup;
174  }
175 
176  status = ZwMapViewOfSection( SectionContext->SectionHandle,
177  processHandle,
178  &scanAddress,
179  0,
180  0,
181  NULL,
182  &scanSize,
183  ViewUnmap,
184  0,
185  PAGE_READONLY );
186  if (!NT_SUCCESS(status)) {
187 
188  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
189  ("[Av]: AvMapSectionAndScan: Failed to map the view of the section, 0x%08x\n",
190  status) );
191 
192  goto Cleanup;
193  }
194 
195  //
196  // The size here may have truncation.
197  //
198  scanResult = AvScanMemoryStream( scanAddress,
199  (SIZE_T)min((LONGLONG)scanSize, SectionContext->FileSize),
200  &SectionContext->Aborted );
201 
202  *ScanResult = scanResult;
203 
204 Cleanup:
205 
206  if (scanAddress != NULL) {
207 
208  ZwUnmapViewOfSection( processHandle, scanAddress );
209  }
210 
211  if (processHandle != NULL) {
212 
213  ZwClose( processHandle );
214  }
215 
216  return status;
217 }
218 
219 NTSTATUS
221  _In_ PCFLT_RELATED_OBJECTS FltObjects,
222  _In_ UCHAR IOMajorFunctionAtScan,
223  _In_ BOOLEAN IsInTxWriter,
224  _In_ PAV_STREAM_CONTEXT StreamContext
225  )
226 /*++
227 
228 Routine Description
229 
230  This function is a high level function which
231  will do the kernel-mode data scan.
232 
233 Arguments
234 
235  FltObjects - related objects for the IO operation.
236 
237  IOMajorFunctionAtScan - The major function of the IRP that issues this scan.
238 
239  IsInTxWriter - If this file is enlisted in a transacted writer.
240 
241  StreamContext - The stream context of this data stream.
242 
243 Return Value
244 
245  Returns the status of this operation.
246 
247 --*/
248 {
249  NTSTATUS status = STATUS_SUCCESS;
250  OBJECT_ATTRIBUTES objAttribs;
251  PAV_SECTION_CONTEXT sectionContext;
253 
254  status = AvCreateSectionContext( FltObjects->Instance,
255  FltObjects->FileObject,
256  &sectionContext );
257 
258  if (!NT_SUCCESS( status )) {
259 
260  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
261  ("[AV] AvScanInKernel: failed to create section context.\n") );
262 
263  return status;
264  }
265 
266  sectionContext->CancelableOnConflictingIo = (IOMajorFunctionAtScan == IRP_MJ_CLEANUP);
267 
268  InitializeObjectAttributes(&objAttribs,
269  NULL,
270  OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
271  NULL,
272  NULL );
273 
274  status = FltCreateSectionForDataScan( FltObjects->Instance,
275  FltObjects->FileObject,
276  sectionContext,
277  SECTION_MAP_READ,
278  &objAttribs,
279  NULL,
280  PAGE_READONLY,
281  SEC_COMMIT,
282  0,
283  &sectionContext->SectionHandle,
284  &sectionContext->SectionObject,
285  NULL );
286  if (!NT_SUCCESS( status )) {
287 
288  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
289  ("[Av]: AvScanInKernel: Failed to create section for data scan.\n, 0x%08x\n",
290  status) );
291  return status;
292  }
293 
294  status = AvMapSectionAndScan( sectionContext, &scanResult );
295 
296  if (!NT_SUCCESS( status )) {
297 
298  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
299  ("[Av]: AvScanInKernel: Failed to scan the view of the section.\n, 0x%08x\n",
300  status) );
301  }
302 
303  if (scanResult == AvScanResultClean) {
304 
305  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
306  ("[AV] AvScanInKernel: file %I64x,%I64x is CLEAN!!\n",
307  StreamContext->FileId.FileId64.UpperZeroes,
308  StreamContext->FileId.FileId64.Value) );
309 
310  SET_FILE_NOT_INFECTED_EX( IsInTxWriter, StreamContext );
311 
312  } else if (scanResult == AvScanResultInfected) {
313 
314  AV_DBG_PRINT( AVDBG_TRACE_DEBUG,
315  ("[AV] AvScanInKernel: file %I64x,%I64x is INFECTED!!\n",
316  StreamContext->FileId.FileId64.UpperZeroes,
317  StreamContext->FileId.FileId64.Value) );
318 
319  SET_FILE_INFECTED_EX( IsInTxWriter, StreamContext );
320 
321  } else {
322 
323  AV_DBG_PRINT( AVDBG_TRACE_ROUTINES,
324  ("[AV] AvScanInKernel: file %I64x,%I64x is UNKNOWN!!\n",
325  StreamContext->FileId.FileId64.UpperZeroes,
326  StreamContext->FileId.FileId64.Value) );
327 
328  SET_FILE_UNKNOWN_EX( IsInTxWriter, StreamContext );
329  }
330 
331  status = AvFinalizeSectionContext(sectionContext);
332 
333  return status;
334 }
335 
336 NTSTATUS
338  _Inout_ PFLT_CALLBACK_DATA Data,
339  _In_ PCFLT_RELATED_OBJECTS FltObjects,
340  _In_ UCHAR IOMajorFunctionAtScan,
341  _In_ BOOLEAN IsInTxWriter,
342  _In_ DEVICE_TYPE DeviceType
343  )
344 /*++
345 
346 Routine Description
347 
348  This function is a high level function which
349  will do the user-mode data scan.
350 
351 Arguments
352 
353  Data - Pointer to the filter callbackData that is passed to us.
354 
355  FltObjects - related objects for the IO operation.
356 
357  IOMajorFunctionAtScan - The major function of the IRP that issues this scan.
358 
359  IsInTxWriter - If this file is enlisted in a transacted writer.
360 
361  StreamContext - The stream context of this data stream.
362 
363 Return Value
364 
365  Returns the status of this operation.
366 
367 --*/
368 {
369  NTSTATUS status = STATUS_SUCCESS;
370  ULONG scanThreadId;
371  ULONG replyLength = sizeof(ULONG);
372  PAV_SCAN_CONTEXT scanCtx = NULL;
373  AV_SCANNER_NOTIFICATION notification = {0};
374  LONGLONG _1ms = 10000;
375  LARGE_INTEGER timeout = {0};
376 
377  status = AvAllocateScanContext(FltObjects->Instance,
378  FltObjects->FileObject,
379  &scanCtx);
380  if (!NT_SUCCESS(status)) {
381 
382  return status;
383  }
384 
385  //
386  // Scan context is passed to the user service program.
387  // Initialize it here.
388  //
389 
390  KeInitializeEvent( &scanCtx->ScanCompleteNotification, NotificationEvent, FALSE );
391  scanCtx->IOMajorFunctionAtScan = IOMajorFunctionAtScan;
392  scanCtx->IsFileInTxWriter = IsInTxWriter;
393  scanCtx->SectionContext = NULL;
394 
395  AvAcquireResourceExclusive( &Globals.ScanCtxListLock );
396  if (Globals.Unloading) {
397  //
398  // If the filter is being unloaded, we failed the scan.
399  //
400  AvReleaseResource( &Globals.ScanCtxListLock );
401  AvReleaseScanContext( scanCtx );
402 
403  return STATUS_FLT_DELETING_OBJECT;
404  }
405  scanCtx->ScanId = (++Globals.ScanIdCounter);
406  InsertTailList (&Globals.ScanCtxListHead, &scanCtx->List);
407  AvReleaseResource( &Globals.ScanCtxListLock );
408 
409  //
410  // Tell the user-scanner to start to scan the file
411  //
412 
413  notification.Message = AvMsgStartScanning;
414  notification.ScanId = scanCtx->ScanId;
415  notification.Reason = AvScanOnOpen;
416 
417  if (IOMajorFunctionAtScan == IRP_MJ_CLEANUP) {
418  notification.Reason = AvScanOnCleanup;
419  }
420 
421  //
422  // Set the scan timeout for this file based on if it is a local or
423  // network file. These values can come from the registry.
424  //
425 
426  if (DeviceType == FILE_DEVICE_NETWORK) {
427  timeout.QuadPart = Globals.NetworkScanTimeout;
428  } else {
429  timeout.QuadPart = Globals.LocalScanTimeout;
430  }
431 
432  timeout.QuadPart = -(timeout.QuadPart * _1ms);
433 
434  status = FltSendMessage( Globals.Filter,
436  &notification,
437  sizeof(AV_SCANNER_NOTIFICATION),
438  &scanThreadId,
439  &replyLength,
440  &timeout );
441  //
442  // If the message is not delievered or time-out, we can make sure that
443  // the scanner thread did not acknowledged this scan task, and thus
444  // we can safely remove it from the list.
445  //
446  if (!NT_SUCCESS( status ) || status == STATUS_TIMEOUT) {
447 
448  if ((status != STATUS_PORT_DISCONNECTED) &&
449  (status != STATUS_TIMEOUT)) {
450 
451  AV_DBG_PRINT( AVDBG_TRACE_ERROR,
452  ("[Av]: AvScanInUser: Failed to FltSendMessage.\n, 0x%08x\n",
453  status) );
454  }
455  goto Cleanup;
456  }
457 
458  scanCtx->ScanThreadId = scanThreadId;
459 
460  //
461  // Wait for an event that the scanner completes or aborts.
462  //
463 
464  status = FltCancellableWaitForSingleObject( &scanCtx->ScanCompleteNotification,
465  &timeout,
466  Data );
467 
468  if (!NT_SUCCESS(status) ||
469  (status == STATUS_TIMEOUT)) {
470 
471  //
472  // At this point we came out of the wait with an error. We are in one of the following conditions:
473  //
474  // 1. This thread is being terminated
475  // 2. The IO operation represented by Data was cancelled
476  // 3. If we are in user-mode scan mode, the communication to the user mode component timed out
477  // 4. If we are in user-mode scan mode, the user-mode component died and the wait timed out.
478  //
479 
480  NTSTATUS statusAbort = STATUS_SUCCESS;
481  //
482  // Notify the user scan thread to abort the scan.
483  //
484  statusAbort = AvSendAbortToUser(scanCtx->ScanThreadId,
485  scanCtx->ScanId);
486  if (NT_SUCCESS(statusAbort) &&
487  (statusAbort != STATUS_TIMEOUT)) {
488 
489  LARGE_INTEGER timeoutForAbortComplete = {0};
490  timeoutForAbortComplete.QuadPart = - 1000 * (LONGLONG)_1ms; // 1s
491  //
492  // Wait again on completion notification.
493  // The scan thread should close the section very soon because we have already notified
494  // the scan thread to abort the task.
495  //
496  statusAbort = FltCancellableWaitForSingleObject(
497  &scanCtx->ScanCompleteNotification,
498  &timeoutForAbortComplete,
499  NULL );
500  }
501  //
502  // If send abortion failed or wait failed, which general means the service is dead,
503  // we have to close section context/handle here by ourself.
504  //
505  if (!NT_SUCCESS(statusAbort) ||
506  (statusAbort == STATUS_TIMEOUT)) {
507 
509  //
510  // If this thread who the race, it will close the section.
511  //
512  AvFinalizeScanAndSection(scanCtx);
513  }
514  }
515 
516  //
517  // If the wait for scan to complete is cancelled (e.g. by CancelSynchronousIo )
518  //
519  if (!NT_SUCCESS(status) &&
520  (IOMajorFunctionAtScan == IRP_MJ_CREATE)) {
521 
522  AvCancelFileOpen(Data, FltObjects, status);
523  }
524 
525 Cleanup:
526 
527  //
528  // Here scanCtx must be non-NULL because we checked it in the beginning.
529  //
530 
531  AvAcquireResourceExclusive( &Globals.ScanCtxListLock );
532  RemoveEntryList (&scanCtx->List);
533  AvReleaseResource( &Globals.ScanCtxListLock );
534 
535  AvReleaseScanContext( scanCtx );
536 
537  return status;
538 }
539 
540 
541 NTSTATUS
543  _Inout_ PAV_SECTION_CONTEXT SectionContext
544  )
545 /*++
546 
547 Routine Description
548 
549  A wrapper function that wraps FltCloseSectionForDataScan and performs appropriate cleanup.
550 
551 Arguments
552 
553  SectionContext - The seciton handle and object will be cleaned up in sectino context.
554 
555 Return Value
556 
557  Returns the status of this operation.
558 
559 --*/
560 {
561  //
562  // Synchronized with AvScanAbortCallbackAsync(...)
563  //
564  InterlockedExchangePointer( &SectionContext->ScanContext, NULL );
565  ObDereferenceObject( SectionContext->SectionObject );
566 
567  SectionContext->SectionHandle = NULL;
568  SectionContext->SectionObject = NULL;
569  return FltCloseSectionForDataScan( (PFLT_CONTEXT)SectionContext );
570 }
571 
UCHAR IOMajorFunctionAtScan
Definition: avscan.h:63
LONGLONG NetworkScanTimeout
Definition: avscan.h:133
#define IRP_MJ_CLEANUP
Definition: mspyLog.h:302
LONGLONG ScanId
Definition: avscan.h:60
RtlCopyMemory(OutputStringBuffer, TempMappingBuffer->Data, OutputString->MaximumLength)
NTSTATUS AvCreateSectionContext(_In_ PFLT_INSTANCE Instance, _In_ PFILE_OBJECT FileObject, _Outptr_ PAV_SECTION_CONTEXT *SectionContext)
PFLT_PORT ScanClientPort
Definition: avscan.h:105
LONGLONG LocalScanTimeout
Definition: avscan.h:127
LIST_ENTRY ScanCtxListHead
Definition: avscan.h:115
NTSTATUS AvFinalizeScanAndSection(_Inout_ PAV_SCAN_CONTEXT ScanContext)
return TRUE
AV_SCANNER_GLOBAL_DATA Globals
Definition: avscan.h:152
NTSTATUS AvAllocateScanContext(_In_ PFLT_INSTANCE Instance, _In_ PFILE_OBJECT FileObject, _Outptr_ PAV_SCAN_CONTEXT *ScanContext)
NTSTATUS AvFinalizeSectionContext(_Inout_ PAV_SECTION_CONTEXT SectionContext)
PFLT_FILTER Filter
Definition: avscan.h:86
#define AV_DEFAULT_PATTERN_XOR_KEY
Definition: avlib.h:192
NTSTATUS AvScanInKernel(_In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ UCHAR IOMajorFunctionAtScan, _In_ BOOLEAN IsInTxWriter, _In_ PAV_STREAM_CONTEXT StreamContext)
Definition: scan.c:220
NTSTATUS AvSendAbortToUser(_In_ ULONG ScanThreadId, _In_ LONGLONG ScanId)
_In_ PLARGE_INTEGER _In_ ULONG _In_ ULONG _In_reads_bytes_(Length)
AVSCAN_REASON Reason
Definition: avlib.h:146
#define AV_DEFAULT_SEARCH_PATTERN_SIZE
Definition: avlib.h:191
BOOLEAN IoWaitOnScanCompleteNotificationAborted
Definition: avscan.h:65
NcLoadRegistryStringRetry NULL
Definition: ncinit.c:53
LONGLONG ScanIdCounter
Definition: avscan.h:79
PAV_SECTION_CONTEXT SectionContext
Definition: avscan.h:59
BOOLEAN IsFileInTxWriter
Definition: avscan.h:64
#define AV_DEFAULT_SEARCH_PATTERN
Definition: avlib.h:190
NTSTATUS AvCloseSectionForDataScan(_Inout_ PAV_SECTION_CONTEXT SectionContext)
Definition: scan.c:542
#define SET_FILE_INFECTED_EX(_flag, _sCtx)
ULONG ScanThreadId
Definition: avscan.h:61
ERESOURCE ScanCtxListLock
Definition: avscan.h:121
AVSCAN_MESSAGE Message
Definition: avlib.h:140
#define SET_FILE_NOT_INFECTED_EX(_flag, _sCtx)
LIST_ENTRY List
Definition: avscan.h:58
enum _AVSCAN_RESULT AVSCAN_RESULT
NTSTATUS AvReleaseScanContext(_In_ PAV_SCAN_CONTEXT ScanContext)
AVSCAN_RESULT AvScanMemoryStream(_In_reads_bytes_(Size) PVOID StartingAddress, _In_ SIZE_T Size, _In_ PBOOLEAN OperationCanceled)
Definition: scan.c:43
KEVENT ScanCompleteNotification
Definition: avscan.h:57
FORCEINLINE VOID AvCancelFileOpen(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ NTSTATUS Status)
Definition: avscan.h:178
NTSTATUS AvScanInUser(_Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_ UCHAR IOMajorFunctionAtScan, _In_ BOOLEAN IsInTxWriter, _In_ DEVICE_TYPE DeviceType)
Definition: scan.c:337
NTSTATUS AvMapSectionAndScan(_Inout_ PAV_SECTION_CONTEXT SectionContext, _Out_ AVSCAN_RESULT *ScanResult)
Definition: scan.c:124
#define AV_DBG_PRINT(_dbgLevel, _string)
Definition: avscan.h:172
#define SET_FILE_UNKNOWN_EX(_flag, _sCtx)
#define IRP_MJ_CREATE
Definition: mspyLog.h:284
LONGLONG ScanId
Definition: avlib.h:153

Social Network


Services Overview

Architect, implement and test file system filter drivers for a wide range of functionality. We can offer several levels of assistance to meet your specific.

Contact Us

You are welcome to contact us for salse or partnership.

Sales: sales@easefilter.com
Support: support@easefilter.com
Info: info@easefilter.com