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

本文介绍如何在Windows驱动中实现类似于DbgPrintf的功能,将调试信息输出到文件。由于驱动服务函数运行在PASSIVE_LEVEL,不能使用提升IRQL的FastMutex,最终采用Event来解决互斥问题。示例代码中包含了获取系统当前时间和当前进程名的函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

运用的技术跟应用层大体一致,倒是互斥的问题干扰我很久。已开始使用的是 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;
 }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值