WDK Mini Filter Example
mspyLib.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) 1989-2002 Microsoft Corporation
4 
5 Module Name:
6 
7  mspyLib.c
8 
9 Abstract:
10  This contains library support routines for MiniSpy
11 
12 Environment:
13 
14  Kernel mode
15 
16 --*/
17 
18 #include <initguid.h>
19 #include <stdio.h>
20 
21 #include "mspyKern.h"
22 
23 //
24 // Can't pull in wsk.h until after MINISPY_VISTA is defined
25 //
26 
27 #if MINISPY_VISTA
28 #include <ntifs.h>
29 #include <wsk.h>
30 #endif
31 
32 //---------------------------------------------------------------------------
33 // Assign text sections for each routine.
34 //---------------------------------------------------------------------------
35 
36 #ifdef ALLOC_PRAGMA
37  #pragma alloc_text(INIT, SpyReadDriverParameters)
38 #if MINISPY_VISTA
39  #pragma alloc_text(PAGE, SpyBuildEcpDataString)
40  #pragma alloc_text(PAGE, SpyParseEcps)
41 #endif
42 #endif
43 
45  _In_ ULONG TxNotification
46  )
47 /*++
48 
49 Routine Description:
50 
51  This routine has been written to convert a transaction notification code
52  to an Irp minor code. This function is needed because RECORD_DATA has a
53  UCHAR field for the Irp minor code whereas TxNotification is ULONG. As
54  of now all this function does is compute log_base_2(TxNotification) + 1.
55  That fits our need for now but might have to be evolved later. This
56  function is intricately tied with the enumeration TRANSACTION_NOTIFICATION_CODES
57  in mspyLog.h and the case statements related to transactions in the function
58  PrintIrpCode (Minispy\User\mspyLog.c).
59 
60 Arguments:
61 
62  TxNotification - The transaction notification received.
63 
64 Return Value:
65 
66  0 if TxNotification is 0;
67  log_base_2(TxNotification) + 1 otherwise.
68 
69 --*/
70 {
71  UCHAR count = 0;
72 
73  if (TxNotification == 0)
74  return 0;
75 
76  //
77  // This assert verifies if no more than one flag is set
78  // in the TxNotification variable. TxNotification flags are
79  // supposed to be mutually exclusive. The assert below verifies
80  // if the value of TxNotification is a power of 2. If it is not
81  // then we will break.
82  //
83 
84  FLT_ASSERT( !(( TxNotification ) & ( TxNotification - 1 )) );
85 
86  while (TxNotification) {
87 
88  count++;
89 
90  TxNotification >>= 1;
91 
92  //
93  // If we hit this assert then we have more notification codes than
94  // can fit in a UCHAR. We need to revaluate our approach for
95  // storing minor codes now.
96  //
97 
98  FLT_ASSERT( count != 0 );
99  }
100 
101  return ( count );
102 }
103 
104 
105 //---------------------------------------------------------------------------
106 // Log Record allocation routines
107 //---------------------------------------------------------------------------
108 
111  _Out_ PULONG RecordType
112  )
113 /*++
114 
115 Routine Description:
116 
117  Allocates a new buffer from the MiniSpyData.FreeBufferList if there is
118  enough memory to do so and we have not exceed our maximum buffer
119  count.
120 
121  NOTE: Because there is no interlock between testing if we have exceeded
122  the record allocation limit and actually increment the in use
123  count it is possible to temporarily allocate one or two buffers
124  more then the limit. Because this is such a rare situation there
125  is not point to handling this.
126 
127  NOTE: This code must be NON-PAGED because it can be called on the
128  paging path or at DPC level.
129 
130 Arguments:
131 
132  RecordType - Receives information on what type of record was allocated.
133 
134 Return Value:
135 
136  Pointer to the allocated buffer, or NULL if the allocation failed.
137 
138 --*/
139 {
140  PVOID newBuffer;
141  ULONG newRecordType = RECORD_TYPE_NORMAL;
142 
143  //
144  // See if we have room to allocate more buffers
145  //
146 
148 
149  InterlockedIncrement( &MiniSpyData.RecordsAllocated );
150 
151  newBuffer = ExAllocateFromNPagedLookasideList( &MiniSpyData.FreeBufferList );
152 
153  if (newBuffer == NULL) {
154 
155  //
156  // We failed to allocate the memory. Decrement our global count
157  // and return what type of memory we have.
158  //
159 
160  InterlockedDecrement( &MiniSpyData.RecordsAllocated );
161 
162  newRecordType = RECORD_TYPE_FLAG_OUT_OF_MEMORY;
163  }
164 
165  } else {
166 
167  //
168  // No more room to allocate memory, return we didn't get a buffer
169  // and why.
170  //
171 
173  newBuffer = NULL;
174  }
175 
176  *RecordType = newRecordType;
177  return newBuffer;
178 }
179 
180 
181 VOID
183  _In_ PVOID Buffer
184  )
185 /*++
186 
187 Routine Description:
188 
189  Free an allocate buffer.
190 
191  NOTE: This code must be NON-PAGED because it can be called on the
192  paging path or at DPC level.
193 
194 Arguments:
195 
196  Buffer - The buffer to free.
197 
198 Return Value:
199 
200  None.
201 
202 --*/
203 {
204  //
205  // Free the memory, update the counter
206  //
207 
208  InterlockedDecrement( &MiniSpyData.RecordsAllocated );
209  ExFreeToNPagedLookasideList( &MiniSpyData.FreeBufferList, Buffer );
210 }
211 
212 
213 //---------------------------------------------------------------------------
214 // Logging routines
215 //---------------------------------------------------------------------------
216 
219  VOID
220  )
221 /*++
222 
223 Routine Description:
224 
225  Allocates a new RECORD_LIST structure if there is enough memory to do so. A
226  sequence number is updated for each request for a new record.
227 
228  NOTE: This code must be NON-PAGED because it can be called on the
229  paging path or at DPC level.
230 
231 Arguments:
232 
233  None
234 
235 Return Value:
236 
237  Pointer to the RECORD_LIST allocated, or NULL if no memory is available.
238 
239 --*/
240 {
241  PRECORD_LIST newRecord;
242  ULONG initialRecordType;
243 
244  //
245  // Allocate the buffer
246  //
247 
248  newRecord = SpyAllocateBuffer( &initialRecordType );
249 
250  if (newRecord == NULL) {
251 
252  //
253  // We could not allocate a record, see if the static buffer is
254  // in use. If not, we will use it
255  //
256 
257  if (!InterlockedExchange( &MiniSpyData.StaticBufferInUse, TRUE )) {
258 
260  initialRecordType |= RECORD_TYPE_FLAG_STATIC;
261  }
262  }
263 
264  //
265  // If we got a record (doesn't matter if it is static or not), init it
266  //
267 
268  if (newRecord != NULL) {
269 
270  //
271  // Init the new record
272  //
273 
274  newRecord->LogRecord.RecordType = initialRecordType;
275  newRecord->LogRecord.Length = sizeof(LOG_RECORD);
276  newRecord->LogRecord.SequenceNumber = InterlockedIncrement( &MiniSpyData.LogSequenceNumber );
277  RtlZeroMemory( &newRecord->LogRecord.Data, sizeof( RECORD_DATA ) );
278  }
279 
280  return( newRecord );
281 }
282 
283 
284 VOID
286  _In_ PRECORD_LIST Record
287  )
288 /*++
289 
290 Routine Description:
291 
292  Free the given buffer
293 
294  NOTE: This code must be NON-PAGED because it can be called on the
295  paging path or at DPC level.
296 
297 Arguments:
298 
299  Record - the buffer to free
300 
301 Return Value:
302 
303  None.
304 
305 --*/
306 {
307  if (FlagOn(Record->LogRecord.RecordType,RECORD_TYPE_FLAG_STATIC)) {
308 
309  //
310  // This was our static buffer, mark it available.
311  //
312 
315 
316  } else {
317 
318  SpyFreeBuffer( Record );
319  }
320 }
321 
322 #if MINISPY_VISTA
323 
324 VOID
326  _In_ PRECORD_LIST RecordList,
327  _Inout_ PUNICODE_STRING EcpData,
328  _In_reads_(NumKnownEcps) PVOID * ContextPointers
329  )
330 /*++
331 
332 Routine Description:
333 
334  Given the ECP presence data and context pointers located in SpyParseEcps,
335  uses _snwprintf to write a human-readable log output to a string provided.
336 
337 Arguments:
338 
339  RecordList - Pointer to the record, so we can see ECP count and masking
340 
341  EcpData - Pointer to string to receive formatted ECP log
342 
343  ContextPointers - Pointer to array of pointers, each of which is either NULL
344  or a context structure specific to a given type of ECP
345 
346 Return Value:
347 
348  None.
349 
350 --*/
351 {
352  ULONG knownCount = 0;
353  SHORT wcharsCopied = 0;
354  PRECORD_DATA recordData = &RecordList->LogRecord.Data;
355  PWCHAR printPointer = EcpData->Buffer;
356 
357 #if MINISPY_WIN7
358  TCHAR addressBuffer[ADDRESS_STRING_BUFFER_SIZE];
359  ULONG addressBufferLen;
360  LONG addressConvStatus;
361 #endif
362 
363  PAGED_CODE();
364 
365  FLT_ASSERT(NULL != ContextPointers);
366 
367  //
368  // Print initial ECP text
369  //
370  // NOTE: We don't check the return value of _snwprintf until the very end
371  // of this function. Because of this, if we run out of buffer space before we
372  // have printed all our information, we keep calling _snwprintf, although it
373  // does nothing. This is deliberate in the interest of keeping the code
374  // somewhat clean.
375  //
376 
377  #pragma prefast(push)
378  #pragma prefast(disable: __WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY __WARNING_BANNED_API_USAGE, "reviewed and safe usage")
379  // Prefast complains here because _snwprintf has some oddities.
380  // We've code reviewed to ensure safe usage.
381 
382  wcharsCopied = (SHORT) _snwprintf( printPointer,
384  L"[%d ECPs:",
385  recordData->EcpCount );
386 
387  //
388  // Next, check all the known ECPs against the mask that was set in SpyParseEcps.
389  // If we recognize any of the ECPs, add their data to the log string.
390  //
391 
392 #if MINISPY_WIN7
393 
394  //
395  // Oplock key ECP
396  //
397 
398  if (FlagOn( recordData->KnownEcpMask, ECP_TYPE_FLAG_OPLOCK_KEY )) {
399 
400  POPLOCK_KEY_ECP_CONTEXT oplockEcpContext = NULL;
401  LPGUID oplockKeyGuid;
402  UNICODE_STRING oplockKeyGuidString;
403 
404  knownCount++;
405 
406  //
407  // We now know this context pointer points to a
408  // OPLOCK_KEY_ECP_CONTEXT structure
409  //
410 
411  oplockEcpContext = (POPLOCK_KEY_ECP_CONTEXT) ContextPointers[EcpOplockKey];
412 
413  FLT_ASSERT(NULL != oplockEcpContext);
414 
415  oplockKeyGuid = &oplockEcpContext->OplockKey;
416 
417  if (NT_SUCCESS(RtlStringFromGUID( oplockKeyGuid,
418  &oplockKeyGuidString ))) {
419 
420  //
421  // Format an output string to display the key in GUID form
422  //
423 
424  wcharsCopied = (SHORT) _snwprintf( printPointer,
426  L"%s OPLOCK KEY: %wZ;",
427  printPointer,
428  &oplockKeyGuidString );
429 
430  RtlFreeUnicodeString( &oplockKeyGuidString );
431 
432  } else {
433 
434  //
435  // Error processing the GUID
436  //
437 
438  wcharsCopied = (SHORT) _snwprintf( printPointer,
440  L"%s INVALID OPLOCK KEY;",
441  printPointer );
442  }
443  }
444 
445  //
446  // NFS ECP
447  //
448 
449  if (FlagOn( recordData->KnownEcpMask, ECP_TYPE_FLAG_NFS )) {
450 
451  PNFS_OPEN_ECP_CONTEXT nfsEcpContext = NULL;
452  PUNICODE_STRING nfsShareNameString;
453  PSOCKADDR_STORAGE_NFS nfsClientSocketAddr;
454 
455  knownCount++;
456 
457  //
458  // We now know this context pointer points to a
459  // NFS_OPEN_ECP_CONTEXT structure
460  //
461 
462  nfsEcpContext= (PNFS_OPEN_ECP_CONTEXT) ContextPointers[EcpNfsOpen];
463 
464  FLT_ASSERT(NULL != nfsEcpContext);
465 
466  nfsShareNameString = nfsEcpContext->ExportAlias;
467  nfsClientSocketAddr = nfsEcpContext->ClientSocketAddress;
468 
469  //
470  // Print the share name, if the string (optional) is present
471  //
472 
473  if (nfsShareNameString) {
474 
475  wcharsCopied = (SHORT) _snwprintf( printPointer,
477  L"%s NFS SHARE NAME: %wZ,",
478  printPointer,
479  nfsShareNameString );
480  }
481 
482  FLT_ASSERT(nfsClientSocketAddr != NULL);
483 
484  addressConvStatus = STATUS_INVALID_PARAMETER;
485  addressBufferLen = ADDRESS_STRING_BUFFER_SIZE;
486 
487  if (nfsClientSocketAddr->ss_family == AF_INET) {
488 
489  PSOCKADDR_IN ipv4SocketAddr = (PSOCKADDR_IN) nfsClientSocketAddr;
490 
491  //
492  // Format IPv4 address and port
493  //
494 
495  addressConvStatus = RtlIpv4AddressToStringEx(
496  &ipv4SocketAddr->sin_addr,
497  ipv4SocketAddr->sin_port,
498  addressBuffer,
499  &addressBufferLen );
500 
501  } else if (nfsClientSocketAddr->ss_family == AF_INET6) {
502 
503  PSOCKADDR_IN6 ipv6SocketAddr = (PSOCKADDR_IN6) nfsClientSocketAddr;
504 
505  //
506  // Format IPv6 address and port
507  //
508 
509  addressConvStatus = RtlIpv6AddressToStringEx(
510  &ipv6SocketAddr->sin6_addr,
511  0,
512  ipv6SocketAddr->sin6_port,
513  addressBuffer,
514  &addressBufferLen );
515  }
516 
517  //
518  // Print the address (and port)
519  //
520 
521  if ((STATUS_INVALID_PARAMETER != addressConvStatus) &&
522  (0 < addressBufferLen)) {
523 
524  wcharsCopied = (SHORT) _snwprintf( printPointer,
526  L"%s NFS SOCKET ADDR: %S;",
527  printPointer,
528  addressBuffer );
529 
530  } else {
531 
532  wcharsCopied = (SHORT) _snwprintf( printPointer,
534  L"%s NFS INVALID SOCKET ADDR;",
535  printPointer );
536  }
537  }
538 
539  //
540  // SRV ECP
541  //
542 
543  if (FlagOn( recordData->KnownEcpMask, ECP_TYPE_FLAG_SRV )) {
544 
545  PSRV_OPEN_ECP_CONTEXT srvEcpContext = NULL;
546  PUNICODE_STRING srvShareNameString;
547  PSOCKADDR_STORAGE_NFS srvClientSocketAddr;
548 
549  knownCount++;
550 
551  //
552  // We now know this context pointer points to a
553  // SRV_OPEN_ECP_CONTEXT structure
554  //
555 
556  srvEcpContext= (PSRV_OPEN_ECP_CONTEXT) ContextPointers[EcpSrvOpen];
557 
558  FLT_ASSERT(NULL != srvEcpContext);
559 
560  srvShareNameString = srvEcpContext->ShareName;
561  srvClientSocketAddr = srvEcpContext->SocketAddress;
562 
563  //
564  // Print the share name, if the string is present
565  //
566 
567  if (srvShareNameString) {
568 
569  wcharsCopied = (SHORT) _snwprintf( printPointer,
571  L"%s SRV SHARE NAME: %wZ,",
572  printPointer,
573  srvShareNameString );
574  }
575 
576  FLT_ASSERT(srvClientSocketAddr != NULL);
577 
578  addressConvStatus = STATUS_INVALID_PARAMETER;
579  addressBufferLen = ADDRESS_STRING_BUFFER_SIZE;
580 
581  //
582  // Print the address, whether it's IPv4 or IPv6
583  //
584 
585  if (srvClientSocketAddr->ss_family == AF_INET) {
586 
587  PSOCKADDR_IN ipv4SocketAddr = (PSOCKADDR_IN) srvClientSocketAddr;
588 
589  //
590  // Format IPv4 address and port
591  //
592 
593  addressConvStatus = RtlIpv4AddressToStringEx(
594  &ipv4SocketAddr->sin_addr,
595  ipv4SocketAddr->sin_port,
596  addressBuffer,
597  &addressBufferLen );
598 
599  } else if (srvClientSocketAddr->ss_family == AF_INET6) {
600 
601  PSOCKADDR_IN6 ipv6SocketAddr = (PSOCKADDR_IN6) srvClientSocketAddr;
602 
603  //
604  // Format IPv6 address and port
605  //
606 
607  addressConvStatus = RtlIpv6AddressToStringEx(
608  &ipv6SocketAddr->sin6_addr,
609  0,
610  ipv6SocketAddr->sin6_port,
611  addressBuffer,
612  &addressBufferLen );
613  }
614 
615  if ((STATUS_INVALID_PARAMETER != addressConvStatus) &&
616  (0 < addressBufferLen)) {
617 
618  wcharsCopied = (SHORT) _snwprintf( printPointer,
620  L"%s SRV SOCKET ADDR: %S;",
621  printPointer,
622  addressBuffer );
623 
624  } else {
625 
626  wcharsCopied = (SHORT) _snwprintf( printPointer,
628  L"%s SRV INVALID SOCKET ADDR;",
629  printPointer );
630  }
631 
632  //
633  // Print SRV flags
634  //
635 
636  wcharsCopied = (SHORT) _snwprintf( printPointer,
638  L"%s SRV FLAGS: %s%s%s;",
639  printPointer,
640  (srvEcpContext->OplockBlockState) ? L"B" : L"-",
641  (srvEcpContext->OplockAppState) ? L"A" : L"-",
642  (srvEcpContext->OplockFinalState) ? L"F" : L"-" );
643  }
644 
645 #else
646  UNREFERENCED_PARAMETER( ContextPointers );
647 #endif
648 
649  //
650  // Prefetch ECP
651  //
652 
653  if (FlagOn( recordData->KnownEcpMask, ECP_TYPE_FLAG_PREFETCH )) {
654 
655  knownCount++;
656 
657  wcharsCopied = (SHORT) _snwprintf( printPointer,
659  L"%s PREFETCH;",
660  printPointer );
661  }
662 
663  //
664  // Print closing ECP text
665  //
666 
667  if (knownCount < recordData->EcpCount) {
668 
669  wcharsCopied = (SHORT) _snwprintf( printPointer,
671  L"%s %d unknown ECPs]",
672  printPointer,
673  recordData->EcpCount - knownCount );
674 
675  } else {
676 
677  wcharsCopied = (SHORT) _snwprintf( printPointer,
679  L"%s]",
680  printPointer );
681  }
682 
683  //
684  // If wcharsCopied is negative, it means we maxed out our buffer
685  // and exited early. Otherwise, the length is the maximum space
686  // minus the leftover buffer space
687  //
688 
689  if (wcharsCopied >= 0) {
690 
691  EcpData->Length = wcharsCopied * sizeof(WCHAR);
692 
693  } else {
694 
695  //
696  // There wasn't enough buffer space, so manually truncate in a NULL
697  //
698 
699  EcpData->Length = MAX_NAME_SPACE_LESS_NULL;
700  EcpData->Buffer[MAX_NAME_WCHARS_LESS_NULL] = UNICODE_NULL;
701  }
702 
703  #pragma prefast(pop)
704 }
705 
706 VOID
708  _In_ PFLT_CALLBACK_DATA Data,
709  _Inout_ PRECORD_LIST RecordList,
710  _Inout_ PUNICODE_STRING EcpData
711  )
712  /*++
713 
714 Routine Description:
715 
716  Extracts ECPs from the given callback data and logs them,
717  then calls SpyBuildEcpDataString to write a MiniSpy-specific
718  ECP log string.
719 
720 Arguments:
721 
722  Data - The Data structure that contains the information we want to record.
723 
724  RecordList - Pointer to the record, so we can set ECP count and masking
725 
726  EcpData - Pointer to string to receive formatted ECP log
727 
728 Return Value:
729 
730  None.
731 
732 --*/
733 {
734  NTSTATUS status;
735  PECP_LIST ecpList;
736  PRECORD_DATA recordData = &RecordList->LogRecord.Data;
737  PVOID ecpContext = NULL;
738  GUID ecpGuid = {0};
739  ULONG ecpContextSize = 0;
740  ULONG ecpFlag;
741  PVOID contextPointers[NumKnownEcps];
742  UCHAR offset = 0;
743 
744  PAGED_CODE();
745 
746  RtlZeroMemory( contextPointers, sizeof(PVOID) * NumKnownEcps );
747 
748  //
749  // Try to get an ECP list pointer from filter manager
750  //
751 
752  status = FltGetEcpListFromCallbackData( MiniSpyData.Filter,
753  Data,
754  &ecpList );
755 
756  //
757  // Even if the operation was successful, ecpList may be NULL
758  // if there are no ECPs attached to this operation, so we must
759  // make both checks
760  //
761 
762  if (NT_SUCCESS(status) && (NULL != ecpList)) {
763 
764  //
765  // Now ask filter manager for each ECP
766  //
767 
768  while (NT_SUCCESS(
769  FltGetNextExtraCreateParameter( MiniSpyData.Filter,
770  ecpList,
771  ecpContext,
772  (LPGUID) &ecpGuid,
773  &ecpContext,
774  &ecpContextSize ))) {
775 
776  //
777  // At this point, we have all the information we should need for a given
778  // ECP, but processing of ECPs is contingent on knowledge of their
779  // specific context structure. From here, ECP processing is driver-specific.
780  //
781 
782  //
783  // MiniSpy supports several system-defined ECPs. What follows is
784  // MiniSpy-specific code to log any known ECPs and produce some
785  // meaningful output for the user
786  //
787 
788  ecpFlag = 0;
789 
790  if (IsEqualGUID( &GUID_ECP_PREFETCH_OPEN, &ecpGuid )) {
791 
792  //
793  // Prefetch ECP
794  //
795 
796  ecpFlag = ECP_TYPE_FLAG_PREFETCH;
797  offset = EcpPrefetchOpen;
798  }
799 
800 #if MINISPY_WIN7
801 
802  //
803  // There are three system-defined ECPs that are only available
804  // as of Windows 7
805  //
806  else if (IsEqualGUID( &GUID_ECP_OPLOCK_KEY, &ecpGuid )) {
807 
808  //
809  // Oplock key ECP
810  //
811 
812  ecpFlag = ECP_TYPE_FLAG_OPLOCK_KEY;
813  offset = EcpOplockKey;
814 
815  } else if (IsEqualGUID( &GUID_ECP_NFS_OPEN, &ecpGuid )) {
816 
817  //
818  // NFS open ECP
819  //
820 
821  ecpFlag = ECP_TYPE_FLAG_NFS;
822  offset = EcpNfsOpen;
823 
824  } else if (IsEqualGUID( &GUID_ECP_SRV_OPEN, &ecpGuid )) {
825 
826  //
827  // SRV ECP
828  //
829 
830  ecpFlag = ECP_TYPE_FLAG_SRV;
831  offset = EcpSrvOpen;
832  }
833 
834 #endif
835 
836  //
837  // We don't accept user mode ECPs because of the potential
838  // for bad buffers
839  //
840 
841  if ((0 != ecpFlag) &&
842  !FltIsEcpFromUserMode( MiniSpyData.Filter, ecpContext )) {
843 
844  //
845  // If ecpFlag was set, we found a MiniSpy-supported ECP.
846  // Make sure we have not already found an ECP of this type
847  // for this particular operation
848  //
849 
850  FLT_ASSERT(!FlagOn( recordData->KnownEcpMask, ecpFlag ));
851 
852  //
853  // Set the flag to indicate a given type of ECP was found
854  //
855 
856  recordData->KnownEcpMask |= ecpFlag;
857 
858  //
859  // Save the context pointer so we can get detailed data later
860  //
861 
862  contextPointers[offset] = ecpContext;
863  }
864 
865  //
866  // Increment the number of total ECPs (counting both known and unknown)
867  //
868 
869  recordData->EcpCount++;
870  }
871 
872  //
873  // Call the Minispy-specific function to format the ECP data string for
874  // output
875  //
876 
877  if (0 < recordData->EcpCount) {
878 
879  SpyBuildEcpDataString( RecordList, EcpData, contextPointers );
880  }
881  }
882 }
883 
884 VOID
886  _Inout_ PLOG_RECORD LogRecord,
887  _In_ PUNICODE_STRING Name,
888  _In_opt_ PUNICODE_STRING EcpData
889  )
890 /*++
891 
892 Routine Description:
893 
894  Sets the given file name in the LogRecord.
895 
896  NOTE: This code must be NON-PAGED because it can be called on the
897  paging path.
898 
899 Arguments:
900 
901  LogRecord - The record in which to set the name.
902 
903  Name - The name to insert
904 
905  EcpData - A string of variable-length ECP data to insert
906 
907 Return Value:
908 
909  None.
910 
911 --*/
912 {
913 
914  PWCHAR printPointer = (PWCHAR)LogRecord->Name;
915  SHORT wcharsCopied;
916  USHORT stringLength;
917 
918  FLT_ASSERT(NULL != Name);
919 
920  //
921  // Put as much of the two strings as possible into the final buffer,
922  // name first, followed by ECP information (if any)
923  //
924 
925  if (NULL != EcpData) {
926 
927  #pragma prefast(suppress:__WARNING_BANNED_API_USAGE, "reviewed and safe usage")
928  wcharsCopied = (SHORT) _snwprintf( printPointer,
930  L"%wZ %wZ",
931  Name,
932  EcpData );
933 
934  } else {
935 
936  #pragma prefast(suppress:__WARNING_BANNED_API_USAGE, "reviewed and safe usage")
937  wcharsCopied = (SHORT) _snwprintf( printPointer,
939  L"%wZ",
940  Name );
941  }
942 
943  if (wcharsCopied >= 0) {
944 
945  stringLength = wcharsCopied * sizeof(WCHAR);
946 
947  } else {
948 
949  //
950  // There wasn't enough buffer space, so manually truncate in a NULL
951  // because we can't trust _snwprintf to do so in that case.
952  //
953 
954  stringLength = MAX_NAME_SPACE_LESS_NULL;
955  printPointer[MAX_NAME_WCHARS_LESS_NULL] = UNICODE_NULL;
956  }
957 
958  //
959  // We will always round up log-record length to sizeof(PVOID) so that
960  // the next log record starts on the right PVOID boundary to prevent
961  // IA64 alignment faults. The length of the record of course
962  // includes the additional NULL at the end.
963  //
964 
965  LogRecord->Length = ROUND_TO_SIZE( (LogRecord->Length +
966  stringLength +
967  sizeof( UNICODE_NULL )),
968  sizeof( PVOID ) );
969 
970  FLT_ASSERT(LogRecord->Length <= MAX_LOG_RECORD_LENGTH);
971 }
972 
973 #else
974 
975 VOID
976 SpySetRecordName(
977  _Inout_ PLOG_RECORD LogRecord,
978  _In_ PUNICODE_STRING Name
979  )
980 /*++
981 
982 Routine Description:
983 
984  Sets the given file name in the LogRecord.
985 
986  NOTE: This code must be NON-PAGED because it can be called on the
987  paging path.
988 
989 Arguments:
990 
991  LogRecord - The record in which to set the name.
992 
993  Name - The name to insert
994 
995 Return Value:
996 
997  None.
998 
999 --*/
1000 {
1001 
1002  PWCHAR printPointer = (PWCHAR)LogRecord->Name;
1003  SHORT wcharsCopied;
1004  USHORT stringLength;
1005 
1006  FLT_ASSERT(NULL != Name);
1007 
1008  #pragma prefast(suppress:__WARNING_BANNED_API_USAGE, "reviewed and safe usage")
1009  wcharsCopied = (SHORT) _snwprintf( printPointer,
1011  L"%wZ",
1012  Name );
1013 
1014  if (wcharsCopied >= 0) {
1015 
1016  stringLength = wcharsCopied * sizeof(WCHAR);
1017 
1018  } else {
1019 
1020  //
1021  // There wasn't enough buffer space, so manually truncate in a NULL
1022  // because we can't trust _snwprintf to do so in that case.
1023  //
1024 
1025  stringLength = MAX_NAME_SPACE_LESS_NULL;
1026  printPointer[MAX_NAME_WCHARS_LESS_NULL] = UNICODE_NULL;
1027  }
1028 
1029  //
1030  // We will always round up log-record length to sizeof(PVOID) so that
1031  // the next log record starts on the right PVOID boundary to prevent
1032  // IA64 alignment faults. The length of the record of course
1033  // includes the additional NULL at the end.
1034  //
1035 
1036  LogRecord->Length = ROUND_TO_SIZE( (LogRecord->Length +
1037  stringLength +
1038  sizeof( UNICODE_NULL )),
1039  sizeof( PVOID ) );
1040 
1041  FLT_ASSERT(LogRecord->Length <= MAX_LOG_RECORD_LENGTH);
1042 }
1043 
1044 #endif
1045 
1046 VOID
1048  _In_ PFLT_CALLBACK_DATA Data,
1049  _In_ PCFLT_RELATED_OBJECTS FltObjects,
1050  _Inout_ PRECORD_LIST RecordList
1051  )
1052 /*++
1053 
1054 Routine Description:
1055 
1056  This is called from the pre-operation callback routine to copy the
1057  necessary information into the log record.
1058 
1059  NOTE: This code must be NON-PAGED because it can be called on the
1060  paging path.
1061 
1062 Arguments:
1063 
1064  Data - The Data structure that contains the information we want to record.
1065 
1066  FltObjects - Pointer to the io objects involved in this operation.
1067 
1068  RecordList - Where we want to save the data
1069 
1070 Return Value:
1071 
1072  None.
1073 
1074 --*/
1075 {
1076  PRECORD_DATA recordData = &RecordList->LogRecord.Data;
1077  PDEVICE_OBJECT devObj;
1078  NTSTATUS status;
1079 
1080  status = FltGetDeviceObject(FltObjects->Volume,&devObj);
1081  if (NT_SUCCESS(status)) {
1082 
1083  ObDereferenceObject(devObj);
1084 
1085  } else {
1086 
1087  devObj = NULL;
1088  }
1089 
1090  //
1091  // Save the information we want
1092  //
1093 
1094  recordData->CallbackMajorId = Data->Iopb->MajorFunction;
1095  recordData->CallbackMinorId = Data->Iopb->MinorFunction;
1096  recordData->IrpFlags = Data->Iopb->IrpFlags;
1097  recordData->Flags = Data->Flags;
1098 
1099  recordData->DeviceObject = (FILE_ID)devObj;
1100  recordData->FileObject = (FILE_ID)FltObjects->FileObject;
1101  recordData->Transaction = (FILE_ID)FltObjects->Transaction;
1102  recordData->ProcessId = (FILE_ID)PsGetCurrentProcessId();
1103  recordData->ThreadId = (FILE_ID)PsGetCurrentThreadId();
1104 
1105  recordData->Arg1 = Data->Iopb->Parameters.Others.Argument1;
1106  recordData->Arg2 = Data->Iopb->Parameters.Others.Argument2;
1107  recordData->Arg3 = Data->Iopb->Parameters.Others.Argument3;
1108  recordData->Arg4 = Data->Iopb->Parameters.Others.Argument4;
1109  recordData->Arg5 = Data->Iopb->Parameters.Others.Argument5;
1110  recordData->Arg6.QuadPart = Data->Iopb->Parameters.Others.Argument6.QuadPart;
1111 
1112  KeQuerySystemTime( &recordData->OriginatingTime );
1113 }
1114 
1115 
1116 VOID
1118  _In_ PFLT_CALLBACK_DATA Data,
1119  _Inout_ PRECORD_LIST RecordList
1120  )
1121 /*++
1122 
1123 Routine Description:
1124 
1125  This is called from the post-operation callback routine to copy the
1126  necessary information into the log record.
1127 
1128  NOTE: This code must be NON-PAGED because it can be called on the
1129  paging path or at DPC level.
1130 
1131 Arguments:
1132 
1133  Data - The Data structure that contains the information we want to record.
1134 
1135  RecordList - Where we want to save the data
1136 
1137 Return Value:
1138 
1139  None.
1140 
1141 --*/
1142 {
1143  PRECORD_DATA recordData = &RecordList->LogRecord.Data;
1144 
1145  recordData->Status = Data->IoStatus.Status;
1146  recordData->Information = Data->IoStatus.Information;
1147  KeQuerySystemTime( &recordData->CompletionTime );
1148 }
1149 
1150 
1151 VOID
1153  _In_ PCFLT_RELATED_OBJECTS FltObjects,
1154  _Inout_ PRECORD_LIST RecordList,
1155  _In_ ULONG TransactionNotification
1156  )
1157 /*++
1158 
1159 Routine Description:
1160 
1161  This routine logs the transaction notification.
1162 
1163 Arguments:
1164 
1165  FltObjects - Pointer to the io objects involved in this operation.
1166 
1167  RecordList - Where we want to save the data
1168 
1169  TransactionNotification - Notification for this transaction.
1170 
1171 Return Value:
1172 
1173  None.
1174 
1175 --*/
1176 {
1177  PRECORD_DATA recordData = &RecordList->LogRecord.Data;
1178  PDEVICE_OBJECT devObj;
1179  NTSTATUS status;
1180 
1181  status = FltGetDeviceObject(FltObjects->Volume,&devObj);
1182  if (NT_SUCCESS(status)) {
1183 
1184  ObDereferenceObject(devObj);
1185 
1186  } else {
1187 
1188  devObj = NULL;
1189  }
1190 
1191 
1193  recordData->CallbackMinorId = TxNotificationToMinorCode(TransactionNotification);
1194 
1195  recordData->DeviceObject = (FILE_ID)devObj;
1196  recordData->FileObject = (FILE_ID)FltObjects->FileObject;
1197  recordData->Transaction = (FILE_ID)FltObjects->Transaction;
1198  recordData->ProcessId = (FILE_ID)PsGetCurrentProcessId();
1199  recordData->ThreadId = (FILE_ID)PsGetCurrentThreadId();
1200 
1201  KeQuerySystemTime( &recordData->OriginatingTime );
1202 }
1203 
1204 
1205 VOID
1207  _In_ PRECORD_LIST RecordList
1208  )
1209 /*++
1210 
1211 Routine Description:
1212 
1213  This routine inserts the given log record into the list to be sent
1214  to the user mode application.
1215 
1216  NOTE: This code must be NON-PAGED because it can be called on the
1217  paging path or at DPC level and uses a spin-lock
1218 
1219 Arguments:
1220 
1221  RecordList - The record to append to the MiniSpyData.OutputBufferList
1222 
1223 Return Value:
1224 
1225  The function returns STATUS_SUCCESS.
1226 
1227 
1228 
1229 --*/
1230 {
1231  KIRQL oldIrql;
1232 
1233  KeAcquireSpinLock(&MiniSpyData.OutputBufferLock, &oldIrql);
1234  InsertTailList(&MiniSpyData.OutputBufferList, &RecordList->List);
1235  KeReleaseSpinLock(&MiniSpyData.OutputBufferLock, oldIrql);
1236 }
1237 
1238 
1239 NTSTATUS
1241  _Out_writes_bytes_to_(OutputBufferLength,*ReturnOutputBufferLength) PUCHAR OutputBuffer,
1242  _In_ ULONG OutputBufferLength,
1243  _Out_ PULONG ReturnOutputBufferLength
1244  )
1245 /*++
1246 
1247 Routine Description:
1248  This function fills OutputBuffer with as many LOG_RECORDs as possible.
1249  The LOG_RECORDs are variable sizes and are tightly packed in the
1250  OutputBuffer.
1251 
1252  NOTE: This code must be NON-PAGED because it uses a spin-lock.
1253 
1254 Arguments:
1255  OutputBuffer - The user's buffer to fill with the log data we have
1256  collected
1257 
1258  OutputBufferLength - The size in bytes of OutputBuffer
1259 
1260  ReturnOutputBufferLength - The amount of data actually written into the
1261  OutputBuffer.
1262 
1263 Return Value:
1264  STATUS_SUCCESS if some records were able to be written to the OutputBuffer.
1265 
1266  STATUS_NO_MORE_ENTRIES if we have no data to return.
1267 
1268  STATUS_BUFFER_TOO_SMALL if the OutputBuffer is too small to
1269  hold even one record and we have data to return.
1270 
1271 --*/
1272 {
1273  PLIST_ENTRY pList;
1274  ULONG bytesWritten = 0;
1275  PLOG_RECORD pLogRecord;
1276  NTSTATUS status = STATUS_NO_MORE_ENTRIES;
1277  PRECORD_LIST pRecordList;
1278  KIRQL oldIrql;
1279  BOOLEAN recordsAvailable = FALSE;
1280 
1281  KeAcquireSpinLock( &MiniSpyData.OutputBufferLock, &oldIrql );
1282 
1283  while (!IsListEmpty( &MiniSpyData.OutputBufferList ) && (OutputBufferLength > 0)) {
1284 
1285  //
1286  // Mark we have records
1287  //
1288 
1289  recordsAvailable = TRUE;
1290 
1291  //
1292  // Get the next available record
1293  //
1294 
1295  pList = RemoveHeadList( &MiniSpyData.OutputBufferList );
1296 
1297  pRecordList = CONTAINING_RECORD( pList, RECORD_LIST, List );
1298 
1299  pLogRecord = &pRecordList->LogRecord;
1300 
1301  //
1302  // If no filename was set then make it into a NULL file name.
1303  //
1304 
1305  if (REMAINING_NAME_SPACE( pLogRecord ) == MAX_NAME_SPACE) {
1306 
1307  //
1308  // We don't have a name, so return an empty string.
1309  // We have to always start a new log record on a PVOID aligned boundary.
1310  //
1311 
1312  pLogRecord->Length += ROUND_TO_SIZE( sizeof( UNICODE_NULL ), sizeof( PVOID ) );
1313  pLogRecord->Name[0] = UNICODE_NULL;
1314  }
1315 
1316  //
1317  // Put it back if we've run out of room.
1318  //
1319 
1320  if (OutputBufferLength < pLogRecord->Length) {
1321 
1322  InsertHeadList( &MiniSpyData.OutputBufferList, pList );
1323  break;
1324  }
1325 
1326  KeReleaseSpinLock( &MiniSpyData.OutputBufferLock, oldIrql );
1327 
1328  //
1329  // The lock is released, return the data, adjust pointers.
1330  // Protect access to raw user-mode OutputBuffer with an exception handler
1331  //
1332 
1333  try {
1334  RtlCopyMemory( OutputBuffer, pLogRecord, pLogRecord->Length );
1335  } except (SpyExceptionFilter( GetExceptionInformation(), TRUE )) {
1336 
1337  //
1338  // Put the record back in
1339  //
1340 
1341  KeAcquireSpinLock( &MiniSpyData.OutputBufferLock, &oldIrql );
1342  InsertHeadList( &MiniSpyData.OutputBufferList, pList );
1343  KeReleaseSpinLock( &MiniSpyData.OutputBufferLock, oldIrql );
1344 
1345  return GetExceptionCode();
1346 
1347  }
1348 
1349  bytesWritten += pLogRecord->Length;
1350 
1351  OutputBufferLength -= pLogRecord->Length;
1352 
1353  OutputBuffer += pLogRecord->Length;
1354 
1355  SpyFreeRecord( pRecordList );
1356 
1357  //
1358  // Relock the list
1359  //
1360 
1361  KeAcquireSpinLock( &MiniSpyData.OutputBufferLock, &oldIrql );
1362  }
1363 
1364  KeReleaseSpinLock( &MiniSpyData.OutputBufferLock, oldIrql );
1365 
1366  //
1367  // Set proper status
1368  //
1369 
1370  if ((bytesWritten == 0) && recordsAvailable) {
1371 
1372  //
1373  // There were records to be sent up but
1374  // there was not enough room in the buffer.
1375  //
1376 
1377  status = STATUS_BUFFER_TOO_SMALL;
1378 
1379  } else if (bytesWritten > 0) {
1380 
1381  //
1382  // We were able to write some data to the output buffer,
1383  // so this was a success.
1384  //
1385 
1386  status = STATUS_SUCCESS;
1387  }
1388 
1389  *ReturnOutputBufferLength = bytesWritten;
1390 
1391  return status;
1392 }
1393 
1394 
1395 VOID
1397  VOID
1398  )
1399 /*++
1400 
1401 Routine Description:
1402 
1403  This routine frees all the remaining log records in the OutputBufferList
1404  that are not going to get sent up to the user mode application since
1405  MiniSpy is shutting down.
1406 
1407  NOTE: This code must be NON-PAGED because it uses a spin-lock
1408 
1409 Arguments:
1410 
1411  None.
1412 
1413 Return Value:
1414 
1415  None.
1416 
1417 --*/
1418 {
1419  PLIST_ENTRY pList;
1420  PRECORD_LIST pRecordList;
1421  KIRQL oldIrql;
1422 
1423  KeAcquireSpinLock( &MiniSpyData.OutputBufferLock, &oldIrql );
1424 
1425  while (!IsListEmpty( &MiniSpyData.OutputBufferList )) {
1426 
1427  pList = RemoveHeadList( &MiniSpyData.OutputBufferList );
1428  KeReleaseSpinLock( &MiniSpyData.OutputBufferLock, oldIrql );
1429 
1430  pRecordList = CONTAINING_RECORD( pList, RECORD_LIST, List );
1431 
1432  SpyFreeRecord( pRecordList );
1433 
1434  KeAcquireSpinLock( &MiniSpyData.OutputBufferLock, &oldIrql );
1435  }
1436 
1437  KeReleaseSpinLock( &MiniSpyData.OutputBufferLock, oldIrql );
1438 }
1439 
1440 //---------------------------------------------------------------------------
1441 // Logging routines
1442 //---------------------------------------------------------------------------
1443 
1444 VOID
1446  _In_ PUNICODE_STRING RegistryPath
1447  )
1448 /*++
1449 
1450 Routine Description:
1451 
1452  This routine tries to read the MiniSpy-specific parameters from
1453  the registry. These values will be found in the registry location
1454  indicated by the RegistryPath passed in.
1455 
1456  This processes the following registry keys:
1457  hklm\system\CurrentControlSet\Services\Minispy\MaxRecords
1458  hklm\system\CurrentControlSet\Services\Minispy\NameQueryMethod
1459 
1460 
1461 Arguments:
1462 
1463  RegistryPath - the path key which contains the values that are
1464  the MiniSpy parameters
1465 
1466 Return Value:
1467 
1468  None.
1469 
1470 --*/
1471 {
1472  OBJECT_ATTRIBUTES attributes;
1473  HANDLE driverRegKey;
1474  NTSTATUS status;
1475  ULONG resultLength;
1476  UNICODE_STRING valueName;
1477  PKEY_VALUE_PARTIAL_INFORMATION pValuePartialInfo;
1478  UCHAR buffer[sizeof( KEY_VALUE_PARTIAL_INFORMATION ) + sizeof( LONG )];
1479 
1480  //
1481  // Open the registry
1482  //
1483 
1484  InitializeObjectAttributes( &attributes,
1485  RegistryPath,
1486  OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1487  NULL,
1488  NULL );
1489 
1490  status = ZwOpenKey( &driverRegKey,
1491  KEY_READ,
1492  &attributes );
1493 
1494  if (!NT_SUCCESS( status )) {
1495 
1496  return;
1497  }
1498 
1499  //
1500  // Read the MaxRecordsToAllocate entry from the registry
1501  //
1502 
1503  RtlInitUnicodeString( &valueName, MAX_RECORDS_TO_ALLOCATE );
1504 
1505  status = ZwQueryValueKey( driverRegKey,
1506  &valueName,
1508  buffer,
1509  sizeof(buffer),
1510  &resultLength );
1511 
1512  if (NT_SUCCESS( status )) {
1513 
1514  pValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
1515  FLT_ASSERT( pValuePartialInfo->Type == REG_DWORD );
1516  MiniSpyData.MaxRecordsToAllocate = *((PLONG)&(pValuePartialInfo->Data));
1517  }
1518 
1519  //
1520  // Read the NameQueryMethod entry from the registry
1521  //
1522 
1523  RtlInitUnicodeString( &valueName, NAME_QUERY_METHOD );
1524 
1525  status = ZwQueryValueKey( driverRegKey,
1526  &valueName,
1528  buffer,
1529  sizeof(buffer),
1530  &resultLength );
1531 
1532  if (NT_SUCCESS( status )) {
1533 
1534  pValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
1535  FLT_ASSERT( pValuePartialInfo->Type == REG_DWORD );
1536  MiniSpyData.NameQueryMethod = *((PLONG)&(pValuePartialInfo->Data));
1537  }
1538 
1539  ZwClose(driverRegKey);
1540 }
1541 
FILE_ID ThreadId
Definition: minispy.h:111
ULONG Length
Definition: minispy.h:146
LOG_RECORD LogRecord
Definition: minispy.h:175
LIST_ENTRY OutputBufferList
Definition: mspyKern.h:150
_In_ PLARGE_INTEGER _In_ ULONG Length
#define ECP_TYPE_FLAG_SRV
Definition: mspyKern.h:91
#define RECORD_TYPE_NORMAL
Definition: minispy.h:89
ULONG Flags
Definition: minispy.h:118
_In_ PCWSTR valueName
Definition: ncinit.c:8
#define ECP_TYPE_FLAG_OPLOCK_KEY
Definition: mspyKern.h:89
__volatile LONG StaticBufferInUse
Definition: mspyKern.h:170
WCHAR Name[]
Definition: minispy.h:153
#define MAX_NAME_SPACE_LESS_NULL
Definition: minispy.h:217
PVOID Arg4
Definition: minispy.h:127
LARGE_INTEGER Arg6
Definition: minispy.h:129
ULONG NameQueryMethod
Definition: mspyKern.h:193
__volatile LONG LogSequenceNumber
Definition: mspyKern.h:185
RtlCopyMemory(OutputStringBuffer, TempMappingBuffer->Data, OutputString->MaximumLength)
#define RECORD_TYPE_FLAG_STATIC
Definition: minispy.h:92
struct _RECORD_LIST * PRECORD_LIST
FILE_ID FileObject
Definition: minispy.h:107
PVOID OutOfMemoryBuffer[RECORD_SIZE/sizeof(PVOID)]
Definition: mspyKern.h:179
ULONG_PTR FILE_ID
Definition: minispy.h:76
PRECORD_LIST SpyNewRecord(VOID)
Definition: mspyLib.c:218
#define ADDRESS_STRING_BUFFER_SIZE
Definition: mspyKern.h:95
LONG SpyExceptionFilter(_In_ PEXCEPTION_POINTERS ExceptionPointer, _In_ BOOLEAN AccessingUserBuffer)
Definition: minispy.c:1336
VOID SpyParseEcps(_In_ PFLT_CALLBACK_DATA Data, _Inout_ PRECORD_LIST RecordList, _Inout_ PUNICODE_STRING EcpData)
Definition: mspyLib.c:707
UCHAR CallbackMajorId
Definition: minispy.h:120
FLT_ASSERT(IS_MY_CONTROL_DEVICE_OBJECT(DeviceObject))
return TRUE
struct _LOG_RECORD LOG_RECORD
PVOID Arg1
Definition: minispy.h:124
#define ECP_TYPE_FLAG_NFS
Definition: mspyKern.h:90
#define ECP_TYPE_FLAG_PREFETCH
Definition: mspyKern.h:85
NcLoadRegistryStringRetry KeyValuePartialInformation
Definition: ncinit.c:53
PFLT_FILTER Filter
Definition: mspyKern.h:131
ULONG SequenceNumber
Definition: minispy.h:147
#define RECORD_TYPE_FLAG_EXCEED_MEMORY_ALLOWANCE
Definition: minispy.h:93
PVOID Arg3
Definition: minispy.h:126
VOID SpyLogPreOperationData(_In_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Inout_ PRECORD_LIST RecordList)
Definition: mspyLib.c:1047
VOID SpyLogPostOperationData(_In_ PFLT_CALLBACK_DATA Data, _Inout_ PRECORD_LIST RecordList)
Definition: mspyLib.c:1117
FILE_ID DeviceObject
Definition: minispy.h:106
NTSTATUS Status
Definition: minispy.h:115
_In_ BOOLEAN _Out_ PFILE_BASIC_INFORMATION Buffer
#define FlagOn(_F, _SF)
Definition: minispy.h:247
#define ROUND_TO_SIZE(_length, _alignment)
Definition: minispy.h:242
#define REMAINING_NAME_SPACE(LogRecord)
Definition: minispy.h:226
#define MAX_NAME_SPACE
Definition: minispy.h:210
VOID SpyLogTransactionNotify(_In_ PCFLT_RELATED_OBJECTS FltObjects, _Inout_ PRECORD_LIST RecordList, _In_ ULONG TransactionNotification)
Definition: mspyLib.c:1152
ULONG KnownEcpMask
Definition: minispy.h:132
NTSTATUS SpyGetLog(_Out_writes_bytes_to_(OutputBufferLength, *ReturnOutputBufferLength) PUCHAR OutputBuffer, _In_ ULONG OutputBufferLength, _Out_ PULONG ReturnOutputBufferLength)
Definition: mspyLib.c:1240
UNREFERENCED_PARAMETER(FileObject)
ULONG IrpFlags
Definition: minispy.h:117
VOID SpyFreeRecord(_In_ PRECORD_LIST Record)
Definition: mspyLib.c:285
NcLoadRegistryStringRetry NULL
Definition: ncinit.c:53
NPAGED_LOOKASIDE_LIST FreeBufferList
Definition: mspyKern.h:156
PRECORD_LIST SpyAllocateBuffer(_Out_ PULONG RecordType)
Definition: mspyLib.c:110
FILE_ID Transaction
Definition: minispy.h:108
KSPIN_LOCK OutputBufferLock
Definition: mspyKern.h:149
__volatile LONG RecordsAllocated
Definition: mspyKern.h:163
RECORD_DATA Data
Definition: minispy.h:152
FILE_ID ProcessId
Definition: minispy.h:110
PAGED_CODE()
VOID SpyReadDriverParameters(_In_ PUNICODE_STRING RegistryPath)
Definition: mspyLib.c:1445
#define MAX_NAME_WCHARS_LESS_NULL
Definition: minispy.h:218
ULONG_PTR Information
Definition: minispy.h:113
LARGE_INTEGER CompletionTime
Definition: minispy.h:104
#define MAX_RECORDS_TO_ALLOCATE
Definition: mspyKern.h:243
#define IRP_MJ_TRANSACTION_NOTIFY
Definition: minispy.h:49
VOID SpyEmptyOutputBufferList(VOID)
Definition: mspyLib.c:1396
VOID SpyBuildEcpDataString(_In_ PRECORD_LIST RecordList, _Inout_ PUNICODE_STRING EcpData, _In_reads_(NumKnownEcps) PVOID *ContextPointers)
Definition: mspyLib.c:325
ULONG EcpCount
Definition: minispy.h:131
UCHAR TxNotificationToMinorCode(_In_ ULONG TxNotification)
Definition: mspyLib.c:44
PVOID Arg5
Definition: minispy.h:128
VOID SpyLog(_In_ PRECORD_LIST RecordList)
Definition: mspyLib.c:1206
LONG MaxRecordsToAllocate
Definition: mspyKern.h:162
#define NAME_QUERY_METHOD
Definition: mspyKern.h:246
PVOID Arg2
Definition: minispy.h:125
LARGE_INTEGER OriginatingTime
Definition: minispy.h:103
ULONG RecordType
Definition: minispy.h:149
UCHAR CallbackMinorId
Definition: minispy.h:121
#define MAX_LOG_RECORD_LENGTH
Definition: minispy.h:230
#define RECORD_TYPE_FLAG_OUT_OF_MEMORY
Definition: minispy.h:94
VOID SpySetRecordNameAndEcpData(_Inout_ PLOG_RECORD LogRecord, _In_ PUNICODE_STRING Name, _In_opt_ PUNICODE_STRING EcpData)
Definition: mspyLib.c:885
VOID SpyFreeBuffer(_In_ PVOID Buffer)
Definition: mspyLib.c:182
MINISPY_DATA MiniSpyData
Definition: minispy.c:26

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