Windows 驱动:向 DbgPrintf 一样将调试信息输出到文件

时间:2022-11-27 07:49:23

运用的技术跟应用层大体一致,倒是互斥的问题干扰我很久。已开始使用的是 FastMutex,但是它会提升 IRQL 到 APC_LEVEL,显然写文件的服务函数都只能跑在 PASSIVE_LEVEL 下,最后只好使用了 Event 。

示例代码说明:

GetCurrentTimeString() 详见前文:Windows 驱动中获取系统当前时间,生成格式字符串

GetCurrentProcessName() 详见前文:Windows 驱动:获取当前进程名

示例代码:

#include <stdarg.h>

//
// Enable log event: for synchronization
//
static KEVENT   gs_eventEnableKeLog;

//----------------------------------------------------------------------
//
// initialization interface
//
//----------------------------------------------------------------------
//
// initialize the global data structures, when the driver is loading.
// (Call in DriverEntry())
//
NTSTATUS
Dbg_LoadInit()
{
 // Initialize the event
 KeInitializeEvent(&gs_eventEnableKeLog, SynchronizationEvent, TRUE);
 return STATUS_SUCCESS;
}

static void WaitForWriteMutex()
{
 // Wait for enable log event
 KeWaitForSingleObject(&gs_eventEnableKeLog, Executive, KernelMode, TRUE, 0);
 KeClearEvent(&gs_eventEnableKeLog);
}
static void ReleaseWriteMutex()
{
 // Set enable log event
 KeSetEvent(&gs_eventEnableKeLog, 0, FALSE);
}
//----------------------------------------------------------------------
//
// DbgKeLog
//
// Trace to file.
//
//----------------------------------------------------------------------
BOOLEAN
DbgKeLog(LPCSTR lpszLog, ...)
{
 if (KeGetCurrentIrql() > PASSIVE_LEVEL)
 {
  TOKdPrint(("TKeHook: KeLog: IRQL too hight.../n"));
  return FALSE;
 }
 WaitForWriteMutex();

 __try
 {
  IO_STATUS_BLOCK  IoStatus;
  OBJECT_ATTRIBUTES objectAttributes;
  NTSTATUS status;
  HANDLE FileHandle;
  UNICODE_STRING fileName;
  static WCHAR s_szLogFile[] = L"
//??//C://KeLog.log";
  LPCWSTR lpszLogFile = s_szLogFile;

  PAGED_CODE();
  if (lpszLogFile == NULL)
   lpszLogFile = s_szLogFile;

  //get a handle to the log file object
  fileName.Buffer = NULL;
  fileName.Length = 0;
  fileName.MaximumLength = (wcslen(lpszLogFile) + 1) * sizeof(WCHAR);
  fileName.Buffer = ExAllocatePool(PagedPool, fileName.MaximumLength);
  if (!fileName.Buffer)
  {
   ReleaseWriteMutex();
   TOKdPrint(("TKeHook: KeLog: ExAllocatePool Failed.../n"));
   return FALSE;
  }
  RtlZeroMemory(fileName.Buffer, fileName.MaximumLength);
  status = RtlAppendUnicodeToString(&fileName, (PWSTR)lpszLogFile);

  InitializeObjectAttributes (&objectAttributes,
         (PUNICODE_STRING)&fileName,
         OBJ_CASE_INSENSITIVE,
         NULL,
         NULL );

  status = ZwCreateFile(&FileHandle,
        FILE_APPEND_DATA,
        &objectAttributes,
        &IoStatus,
        0,
        FILE_ATTRIBUTE_NORMAL,
        FILE_SHARE_WRITE,
        FILE_OPEN_IF,
        FILE_SYNCHRONOUS_IO_NONALERT,
        NULL,    
        0
        );

  if(NT_SUCCESS(status))
  {
   static CHAR szBuffer[1024];
   PCHAR  pszBuffer = szBuffer;
   ULONG  ulBufSize;
   int   nSize;
   va_list  pArglist;

   // add process name and time string
   sprintf(szBuffer, "[%s][%16s:%d] "
    , GetCurrentTimeString()
    , GetCurrentProcessName()
    , (ULONG)PsGetCurrentProcessId()
    );
   pszBuffer = szBuffer + strlen(szBuffer);
   
   va_start(pArglist, lpszLog);  
   // The last argument to wvsprintf points to the arguments  
   nSize = _vsnprintf( pszBuffer, 1024 - 32, lpszLog, pArglist);  
   // The va_end macro just zeroes out pArgList for no good reason  
   va_end(pArglist);
   if (nSize > 0)
   {
    //
    pszBuffer[nSize] = 0;
   }
   else
   {
    pszBuffer[0] = 0;
   }

   ulBufSize = strlen(szBuffer);
   ZwWriteFile(FileHandle,
       NULL,
       NULL,
       NULL,
       &IoStatus,
       szBuffer,
       ulBufSize,
       NULL,
       NULL
       );
   ZwClose(FileHandle);
  }
  if (fileName.Buffer)
   ExFreePool (fileName.Buffer);

  ReleaseWriteMutex();
  return TRUE;
 }
 __except(EXCEPTION_EXECUTE_HANDLER)
 {
  ReleaseWriteMutex();
  TOKdPrint(("TKeHook: DbgKeLog() except: %0xd !!/n", GetExceptionCode()));
  return FALSE;
 }
}