Windows driver log messages

Writing to the System Event Log

Errors are specified by their NTSTATUS value. The system predefines particular NTSTATUS values that can be used by drivers, and driver writers can define additional errors. Note that only certain NTSTATUS values can be used when logging errors.

Each NTSTATUS value that can be used when logging errors has an associated error message. For example, the parallel port driver uses the NTSTATUS value PAR_INTERRUPT_CONFLICT to represent hardware interrupt conflicts, with message text «Interrupt conflict detected for %1».

The Event Viewer displays the message text in the Description text box on the log entry’s property sheet. If the message text string contains «%1», the Event Viewer replaces it with the name of the device that logged the entry. The message text can contain additional parameters of the form «%2», «%3», and so on. When the driver logs the error, it can provide string values for those parameters. These string values are known as insertion strings. The Event Viewer will automatically insert them in place of the percent values.

The driver can also include binary data in the log entry, known as dump data. The Event Viewer displays the dump data in the Data text box of the log entry’s property sheet.

You can bring up the property sheet for a log entry by double-clicking the entry in the Event Viewer. The following screen shot shows a sample log entry property sheet.

Drivers use the IoAllocateErrorLogEntry routine to allocate an error log entry. Log entries consist of a variable-length IO_ERROR_LOG_PACKET header, followed by insertion strings.

The following diagram shows the layout of an error log entry in memory.

The ErrorCode member of IO_ERROR_LOG_PACKET specifies the NTSTATUS value of the error. The DumpData member specifies any dump data for the log entry. DumpData is a variable-sized array, whose size is specified by the DumpDataSize member. Drivers specify the beginning of the first insertion string with the StringOffset member, and the number of strings in the NumberOfStrings member. Each insertion string itself is a null-terminated Unicode string.

Once the driver fills out the allocated error log entry, it writes the entry to the error log by using IoWriteErrorLogEntry. IoWriteErrorLogEntry automatically frees the memory allocated for the log entry. Drivers can use IoFreeErrorLogEntry to free any unused log entries.

Predefined error codes (of the form IO_ERR_XXX) are defined in the ntiologc.h header file that is included with the Windows Driver Kit (WDK). The error message associated with each error code can be found in the comments for ntiologc.h, next to the error code’s declaration. To use a predefined error code, the driver must register the system file, iologmsg.dll, as the source of the associated error messages. For further information, see Registering as a Source of Error Messages.

Drivers can also define their own custom error types, and associated error messages. For further information, see Defining Custom Error Types.

Code Integrity Event Log Messages

The following are warning events that are logged to the Code Integrity operational log:

Code Integrity is unable to verify the image integrity of the file because file hash could not be found on the system.

Code Integrity detected an unsigned driver.

This event is related to Software Quality Monitoring (SQM).

The following are informational events that are logged to the Code Integrity verbose log:

Code Integrity found a set of per-page image hashes for the file in a catalog .

Code Integrity found a set of per-page image hashes for the file in the image embedded certificate.

Code Integrity found a file hash for the file in a catalog .

Code Integrity found a file hash for the file in the image embedded certificate.

Code Integrity determined an unsigned kernel module is loaded into the system. Check with the publisher to see whether a signed version of the kernel module is available.

Code Integrity is unable to verify the image integrity of the file because the set of per-page image hashes could not be found on the system.

Code Integrity is unable to verify the image integrity of the file because the set of per-page image hashes could not be found on the system. The image is allowed to load because kernel mode debugger is attached.

Code Integrity is unable to verify the image integrity of the file because a file hash could not be found on the system. The image is allowed to load because kernel mode debugger is attached.

Code Integrity was unable to load the catalog.

Code Integrity successfully loaded the catalog.

Читайте также:  Jbl flip 4 драйвера для windows

Creating a Driver Verification Log

Certain programs of theВ Windows Hardware Certification Program require a Driver Verification Log (DVL) for all driver submissions. The DVL contains a summary of the results from the Code Analysis (CA), Static Driver Verifier (SDV), and CodeQL log files. The DVL does not contain any source information. You must run the Code Analysis tool and Static Driver Verifier prior to creating a DVL for your driver.

To create a driver verification log

  1. Before running the Code Analysis tools, be sure that you can build and link your driver using the latest Windows Driver Kit (WDK).
  2. For the Driver Solution, make sure that you have selected a Release configuration as the Solution Configuration and x64 as the Solution Platform.
  3. Run Static Driver Verifier. For information about creating the log file, see Creating a log file for Static Driver Verifier and Using Static Driver Verifier to find defects in drivers.
  4. Run the Code Analysis tool for drivers. Address and fix any defects that are found. See Creating a log file for the code analysis tool and How to run Code Analysis for Drivers. For more information about code analysis, see Analyzing C/C++ Code Quality by Using Code Analysis.
  5. Run CodeQL. Address and fix defects that are found. Certification will fail if defects that are deemed «Must-Fix» are not corrected. For more information about CodeQL and the Static Tools Logo Test, see CodeQL and the Static Tools Logo Test.
  6. Create the Driver Verification Log. From the Driver menu, select Create Driver Verification Log. .
  7. Verify that the Code Analysis Log, Static Driver Verifier Log, and CodeQL Log files are detected. Select Create.

The driver verification log has the file name extension .DVL.XML. The log is created in the project folder, for example, \myDriverProject\myDriverName.DVL.XML.

Note SDV performs a clean rebuild of the driver, which removes the Code Analysis log. As such, please be sure to run SDV before running CA.

NoteВ В When you are ready to test your driver using the Windows Hardware Lab Kit, you need to copy the driver verification log to the %systemdrive%\DVL directory on the test computer. Be sure to delete the contents of the directory on the test computer before you copy the new driver verification log.

Remarks

For the most up-to-date information about the Code Analysis tool, Static Driver Verifier, and the Driver Verification Log, refer to the WDK Release Notes. The Release Notes are available on the Windows Driver Kit (WDK) download page.

ImportantВ В Timeouts, spaceouts, and other non-successful results in the DVL file are acceptable for certification submission. This will not cause the Static Tools test in HLK to fail.

You can also create the driver verification log from a Visual Studio Command Prompt window, either by the Visual Studio Native Tools Command Prompt installed with Visual Studio or via the Enterprise Windows Driver Kit (EWDK):

Creating a Driver Verification Log Outside of msbuild or Visual Studio

Microsoft ships as part of the Windows Driver Kit (WDK) and Enterprise WDK (eWDK) a component called dvl.exe which can be used to generate Driver Verification Logs (DVLs) via command-line. Starting in WDK/eWDK preview versions 21342 and above, it is possible to generate a DVL from the command line outside of the context of msbuild or Visual Studio. Follow the steps below to create the DVL via command-line:

  1. Place the results that need to be consumed to create the DVL in a single directory. Typically for drivers intended to be certified for Windows Client, this is the CodeQL SARIF file. For Windows Server certification, this may also include the Code Analysis and Static Driver Verifier (SDV) results files. Check the WHCP requirements documents for specific details on which tools are required to be run for device driver certification.
  2. CodeQL SARIF files and Code Analysis XML files should be placed in the top level of the directory. The SDV DVL.xml file should be placed in a “sdv” subfolder.
  3. From the command line, navigate to the top-level directory which contains the CodeQL SARIF file.
  4. Locate dvl.exe from the WDK or a mounted eWDK.
  5. Call dvl.exe by passing the /manualCreate flag, a driver name, and a desired architecture. For example:

One of the following strings should be used for your driverArchitecture string:

Do not include «.sys» as part of your driverName string

  1. Inspect the generated DVL to ensure that it was generated correctly

This usage is primarily intended for generating DVLs with CodeQL results, but can also be used for SDV and CA results.

Reading and Filtering Debugging Messages

The DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, and KdPrintEx routines send a message to the kernel debugger under conditions that you specify. This procedure enables you to filter out low-priority messages.

In Microsoft Windows Server 2003 and earlier versions of Windows, the DbgPrint and KdPrint routines send messages to the kernel debugger unconditionally. In Windows Vista and later versions of Windows, these routines send messages conditionally, like DbgPrintEx and KdPrintEx. Whichever version of Windows you are using, you should use DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, and KdPrintEx, because these routines enable you to control the conditions under which the message is sent.

Читайте также:  Фокусировка внимания windows 10 как отключить уведомления

To filter debugging messages

For each message that you want to send to the debugger, use DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, or KdPrintEx in your driver’s code. Pass the appropriate component name to the ComponentId parameter, and pass a value to the Level parameter that reflects the severity or nature of this message. The message itself is passed to the Format and arguments parameters by using the same syntax as printf.

Set the value of the appropriate component filter mask. Each component has a different mask. The mask value indicates which of that component’s messages are displayed. You can set the component filter mask in the registry by using a registry editor or in memory by using a kernel debugger.

Attach a kernel debugger to the computer. Every time that your driver passes a message to DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, or KdPrintEx, the values that are passed to ComponentId and Level are compared with the value of the corresponding component filter mask. If these values satisfy certain criteria, the message are sent to the kernel debugger and displayed. Otherwise, no message is sent.

All references on this page to DbgPrintEx apply equally to KdPrintEx, vDbgPrintEx, and vDbgPrintExWithPrefix.

Identifying the Component Name

Each component has a separate filter mask. This allows the debugger to configure the filter for each component separately.

Each component is referred to in different ways, depending on the context. In the ComponentId parameter of DbgPrintEx, the component name is prefixed with «DPFLTR_» and suffixed with «_ID». In the registry, the component filter mask has the same name as the component itself. In the debugger, the component filter mask is prefixed with «Kd_» and suffixed with «_Mask».

There is a complete list of all component names (in DPFLTR_XXXX_ID format) in the Microsoft Windows Driver Kit (WDK) header dpfilter.h. Most of these component names are reserved for Windows and for drivers written by Microsoft.

There are six component names reserved for independent hardware vendors. To avoid mixing your driver’s output with the output of Windows components, you should use one of the following component names:

Component name Driver type
IHVVIDEO Video driver
IHVAUDIO Audio driver
IHVNETWORK Network driver
IHVSTREAMING Kernel streaming driver
IHVBUS Bus driver
IHVDRIVER Any other type of driver

For example, if you are writing a video driver, you would use DPFLTR_IHVVIDEO_ID as the ComponentId parameter of DbgPrintEx, use the value name IHVVIDEO in the registry, and refer to Kd_IHVVIDEO_Mask in the debugger.

All messages sent by DbgPrint and KdPrint are associated with the DEFAULT component.

Choosing the Correct Level

The Level parameter of the DbgPrintEx routine is of type DWORD. It is used to determine the importance bit field. The connection between the Level parameter and this bit field depends on the size of Level:

If Level is equal to a number between 0 and 31, inclusive, it is interpreted as a bit shift. The importance bit field is set to the value 1 —>

Вертим логи как хотим ― анализ журналов в системах Windows

Пора поговорить про удобную работу с логами, тем более что в Windows есть масса неочевидных инструментов для этого. Например, Log Parser, который порой просто незаменим.

В статье не будет про серьезные вещи вроде Splunk и ELK (Elasticsearch + Logstash + Kibana). Сфокусируемся на простом и бесплатном.

Журналы и командная строка

До появления PowerShell можно было использовать такие утилиты cmd как find и findstr. Они вполне подходят для простой автоматизации. Например, когда мне понадобилось отлавливать ошибки в обмене 1С 7.7 я использовал в скриптах обмена простую команду:

Она позволяла получить в файле fail.txt все ошибки обмена. Но если было нужно что-то большее, вроде получения информации о предшествующей ошибке, то приходилось создавать монструозные скрипты с циклами for или использовать сторонние утилиты. По счастью, с появлением PowerShell эти проблемы ушли в прошлое.

Основным инструментом для работы с текстовыми журналами является командлет Get-Content, предназначенный для отображения содержимого текстового файла. Например, для вывода журнала сервиса WSUS в консоль можно использовать команду:

Для вывода последних строк журнала существует параметр Tail, который в паре с параметром Wait позволит смотреть за журналом в режиме онлайн. Посмотрим, как идет обновление системы командой:


Смотрим за ходом обновления Windows.

Если же нам нужно отловить в журналах определенные события, то поможет командлет Select-String, который позволяет отобразить только строки, подходящие под маску поиска. Посмотрим на последние блокировки Windows Firewall:


Смотрим, кто пытается пролезть на наш дедик.

При необходимости посмотреть в журнале строки перед и после нужной, можно использовать параметр Context. Например, для вывода трех строк после и трех строк перед ошибкой можно использовать команду:

Оба полезных командлета можно объединить. Например, для вывода строк с 45 по 75 из netlogon.log поможет команда:

Журналы системы ведутся в формате .evtx, и для работы с ними существуют отдельные командлеты. Для работы с классическими журналами («Приложение», «Система», и т.д.) используется Get-Eventlog. Этот командлет удобен, но не позволяет работать с остальными журналами приложений и служб. Для работы с любыми журналами, включая классические, существует более универсальный вариант ― Get-WinEvent. Остановимся на нем подробнее.

Для получения списка доступных системных журналов можно выполнить следующую команду:


Вывод доступных журналов и информации о них.

Для просмотра какого-то конкретного журнала нужно лишь добавить его имя. Для примера получим последние 20 записей из журнала System командой:


Последние записи в журнале System.

Для получения определенных событий удобнее всего использовать хэш-таблицы. Подробнее о работе с хэш-таблицами в PowerShell можно прочитать в материале Technet about_Hash_Tables.

Для примера получим все события из журнала System с кодом события 1 и 6013.

В случае если надо получить события определенного типа ― предупреждения или ошибки, ― нужно использовать фильтр по важности (Level). Возможны следующие значения:

  • 0 ― всегда записывать;
  • 1 ― критический;
  • 2 ― ошибка;
  • 3 ― предупреждение;
  • 4 ― информация;
  • 5 ― подробный (Verbose).

Собрать хэш-таблицу с несколькими значениями важности одной командой так просто не получится. Если мы хотим получить ошибки и предупреждения из системного журнала, можно воспользоваться дополнительной фильтрацией при помощи Where-Object:


Ошибки и предупреждения журнала System.

Аналогичным образом можно собирать таблицу, фильтруя непосредственно по тексту события и по времени.

Подробнее почитать про работу обоих командлетов для работы с системными журналами можно в документации PowerShell:

PowerShell ― механизм удобный и гибкий, но требует знания синтаксиса и для сложных условий и обработки большого количества файлов потребует написания полноценных скриптов. Но есть вариант обойтись всего-лишь SQL-запросами при помощи замечательного Log Parser.

Работаем с журналами посредством запросов SQL

Утилита Log Parser появилась на свет в начале «нулевых» и с тех пор успела обзавестись официальной графической оболочкой. Тем не менее актуальности своей она не потеряла и до сих пор остается для меня одним из самых любимых инструментов для анализа логов. Загрузить утилиту можно в Центре Загрузок Microsoft, графический интерфейс к ней ― в галерее Technet. О графическом интерфейсе чуть позже, начнем с самой утилиты.

О возможностях Log Parser уже рассказывалось в материале «LogParser — привычный взгляд на непривычные вещи», поэтому я начну с конкретных примеров.

Для начала разберемся с текстовыми файлами ― например, получим список подключений по RDP, заблокированных нашим фаерволом. Для получения такой информации вполне подойдет следующий SQL-запрос:

Посмотрим на результат:


Смотрим журнал Windows Firewall.

Разумеется, с полученной таблицей можно делать все что угодно ― сортировать, группировать. Насколько хватит фантазии и знания SQL.

Log Parser также прекрасно работает с множеством других источников. Например, посмотрим откуда пользователи подключались к нашему серверу по RDP.

Работать будем с журналом TerminalServices-LocalSessionManager\Operational.

Не со всеми журналами Log Parser работает просто так ― к некоторым он не может получить доступ. В нашем случае просто скопируем журнал из %SystemRoot%\System32\Winevt\Logs\Microsoft-Windows-TerminalServices-LocalSessionManager%4Operational.evtx в %temp%\test.evtx.

Данные будем получать таким запросом:


Смотрим, кто и когда подключался к нашему серверу терминалов.

Особенно удобно использовать Log Parser для работы с большим количеством файлов журналов ― например, в IIS или Exchange. Благодаря возможностям SQL можно получать самую разную аналитическую информацию, вплоть до статистики версий IOS и Android, которые подключаются к вашему серверу.

В качестве примера посмотрим статистику количества писем по дням таким запросом:

Если в системе установлены Office Web Components, загрузить которые можно в Центре загрузки Microsoft, то на выходе можно получить красивую диаграмму.


Выполняем запрос и открываем получившуюся картинку…


Любуемся результатом.

Следует отметить, что после установки Log Parser в системе регистрируется COM-компонент MSUtil.LogQuery. Он позволяет делать запросы к движку утилиты не только через вызов LogParser.exe, но и при помощи любого другого привычного языка. В качестве примера приведу простой скрипт PowerShell, который выведет 20 наиболее объемных файлов на диске С.

Ознакомиться с документацией о работе компонента можно в материале Log Parser COM API Overview на портале SystemManager.ru.

Благодаря этой возможности для облегчения работы существует несколько утилит, представляющих из себя графическую оболочку для Log Parser. Платные рассматривать не буду, а вот бесплатную Log Parser Studio покажу.


Интерфейс Log Parser Studio.

Основной особенностью здесь является библиотека, которая позволяет держать все запросы в одном месте, без россыпи по папкам. Также сходу представлено множество готовых примеров, которые помогут разобраться с запросами.

Вторая особенность ― возможность экспорта запроса в скрипт PowerShell.

В качестве примера посмотрим, как будет работать выборка ящиков, отправляющих больше всего писем:


Выборка наиболее активных ящиков.

При этом можно выбрать куда больше типов журналов. Например, в «чистом» Log Parser существуют ограничения по типам входных данных, и отдельного типа для Exchange нет ― нужно самостоятельно вводить описания полей и пропуск заголовков. В Log Parser Studio нужные форматы уже готовы к использованию.

Помимо Log Parser, с логами можно работать и при помощи возможностей MS Excel, которые упоминались в материале «Excel вместо PowerShell». Но максимального удобства можно достичь, подготавливая первичный материал при помощи Log Parser с последующей обработкой его через Power Query в Excel.

Приходилось ли вам использовать какие-либо инструменты для перелопачивания логов? Поделитесь в комментариях.

Оцените статью