Alter.Org.UA  
 << Back Home EN en   Donate Donate www/www1/www2

Building NT kernel mode drivers in MS Visual C 6.0

Ну вот я и сподвигся на это. Ниже приведена инструкция по созданию полноценного проекта для kernel драйвера в MS Visual Studio 6.0

Содержание

Настройка переменных окружения

Настраиваем переменные окружения (рекомендую системные, а не пользовательские) BASEDIRNT4, BASEDIR2K, BASEDIRXP примерно следующим образом

BASEDIRNT4 = C:\Develop\DDKNT4
BASEDIR2K  = C:\Develop\DDK2000
BASEDIRXP  = C:\Develop\DDKXP

А также переменную BASEDIR, содержащую путь к наиболее любимому DDK (у меня это NT4, т.к. люблю писать хорошо совместимые драйвера). Например так:

BASEDIR = %BASEDIRNT4%

Создание проекта

  • File -> New... -> Projects
  • Выбираем Win32 Dynamic-link Library
  • Вводим путь и имя проекта (все как обычно)
  • OK -> An empty DLL project -> Finish -> OK

Настройка проекта

  • Project -> Settings
  • Выбираем в "Settings for" (слева вверху) вариант "All Configurations"
  • ... -> C/C++
    • Выбираем в "Category" вариант "General"
      • Выбираем в "Debug info" вариант "Program Database" в конфигурации "Win32 Debug".
    • Выбираем в "Category" вариант "Code Generation"
      • Выбираем в "Calling convention" вариант "__stdcall"
      • Выбираем в "Struct member alignment" вариант "8 Bytes *"
    • Выбираем в "Category" вариант "Preprocessor"
      • Вводим пути к INCLUDE каталогам от DDK в поле "Additional include directories":
        $(BASEDIRNT4)\inc,$(BASEDIR2K)\src\filesys\inc
        Note 1: разделитель здесь - запятая. Кавычки вокруг путей не нужны.
        Note 2: Если вы пользуетесь .MAK файлами, задавайте имена переменных BASEDIRxxx с учетом регистра. Т.е. в точности так, как они названы в диалоге создания/редактирования переменных окружения.
      • Вводим следующие предопределенные константы в поле "Preprocessor definitions" (thanks to Emusic from http://www.rsdn.ru). Это обеспечит правильную компиляцию всех .H из DDK:
        WIN32, _WINDOWS, i386=1, _X86_=1, STD_CALL, CONDITION_HANDLING=1,
        NT_INST=0, _NT1X_=100, WINNT=1,
        _WIN32_WINNT=0x0400 /* minimum required OS version */
        WIN32_LEAN_AND_MEAN=1, DEVL=1, FPO=1
        
        Для конфигурации "Win32 Debug" следует еще добавить следующие константы:
        DBG, DEBUG, _DEBUG
        
        Note 1: разделитель здесь - запятая. Кавычки не нужны.
        Note 2: Если вы пользуетесь precompiled headers, можно эти определения занести в .H, используемый для построения .PCH или в общем заголовочном файле. Пример для проекта, использующего *.cpp находится в каталоге pch_cpp, а *.c - в каталоге pch_c в driver_template_v7.rar/tgz (9.4 Kb/10.1 Kb)).
    • В "Project Options" находим ключ "/GZ" и удаляем его в конфигурации "Win32 Debug". Это во многих случаях спасет от головной боли формата "Debug работает, а Release глючит". Глючить если и будет, то одинаково ( неинициализированные переменные, блоки памяти, переполнения и т.п.). Кроме того, этот неполезный ключик говорит компилятору, что нужно встраивать код проверки целостности стека, выливающийся в unresolved external _chkesp во время линковки.
  • ... -> Link
    • Выбираем в "Category" вариант "General"
      • Устанавливаем имя .SYS файла (например "driver_template.sys") в поле "Output file name" (для каждой конфигурации отдельно).
      • Убираем "Link incrementally").
    • Выбираем в "Category" вариант "Input"
      • Устанавливаем "Ignore all default libraries"
      • Заменяем список стандартных библиотек импорта на DDK'шные в "Object/library modules". Например:
        $(BASEDIR)\Lib\i386\Checked\ntoskrnl.lib
        $(BASEDIR2k)\libchk\i386\ntoskrnl.lib
        $(BASEDIR)\Lib\i386\Checked\int64.lib
        $(BASEDIR)\Lib\i386\Checked\Hal.lib
        Note 1: разделитель здесь - пробел. Кавычки вокруг путей не нужны.
        Note 2: Если вы пользуетесь .MAK файлами, задавайте имена переменных BASEDIRxxx с учетом регистра. Т.е. в точности так, как они названы в диалоге создания/редактирования переменных окружения.
        Note 3: библиотека
        $(BASEDIR2k)\libchk\i386\ntoskrnl.lib
        включена вместе с
        $(BASEDIR)\Lib\i386\Checked\ntoskrnl.lib
        (и именно после нее) для того, чтобы импорты в первую очередь брались из NT4 версии, но в то же время были доступны импорты из более свежих ServicePack'ов той же NT4.
        Note 4: раньше я рекомендовал еще $(BASEDIR)\Lib\i386\Checked\Ntdll.lib. Беру свои слова обратно. Если вам действительно нужны экспорты из ntdll.dll, kernel-mode GetProcAddress() вам в руки. Во-первых, ваш драйвер может запросто не смочь загрузиться (что такое unresolved external объяснять ?). А во-вторых в ядре положено использовать ZwXxxx(), а не NtXxx(), и в новых версиях Винды это проверяется все жестче и жестче.
    • Выбираем в "Category" вариант "Output"
      • Устанавливаем значение "DriverEntry" в поле "Entry point symbol".
    • Выбираем в "Category" вариант "Debug"
      • Снимаем галку "Separate types". При этом информация о используемых типах (особенно актуально для структур) попадет в общий .PDB файл вместе с остальной отладочной информацией. В дальнейшем эта информация сможет быть использована отладчиками (SoftIce, WinDbg). На уровне параметров командной строки это эквивалентно замене /pdbtype:sept на /pdbtype:con.
      • Для старых версий SoftIce установить тип .PDB файла в "COFF". (В моих шаблонных проектах используется "MS").
    • В "Project Options" (для каждой конфигурации отдельно) находим ключ "/subsystem:xxxxx" и заменяем на "/subsystem:native" (или добавляем, если такого нет) или даже "/subsystem:native,4.00".
    • В "Project Options" (для каждой конфигурации отдельно) добавляем ключ "/driver".
  • OK
  • File -> Save Workspace
  • Если вы любите собирать проекты из командной строки или из скрипта с помощью nmake, экспортируйте еще и .MAK + .DEP файлы:
    • Project -> Export Makefile
    • Устанавливаем "Write dependencies when writing makefile"
    • Устанавливаем check-box напротив имени .MAK файла.
    • OK
    • Еще при желании можно создать в том же каталоге файл с гордым именем Makefile со следующим содержимым:
      !INCLUDE my_driver_project.mak
      
      Тогда nmake'у не придется указывать имя .MAK файла.
  • А теперь имеет смысл этот пустой проект куда-нибудь скопировать и использовать в качестве заготовки :) Например вот такой: driver_template_v7.rar/tgz (9.4 Kb/10.1 Kb)
  • PS. начиная с 6й версии в архиве в подкаталоге pch_cpp помимо проекта для VS6 есть еще и проект для VS8. driver_template_v7.rar/tgz (9.4 Kb/10.1 Kb)

Добавление файлов

  • Просто добавляем файлы в проект :)
  • Если проект большой и есть .LIB или .DLL, собирающиеся из других .DSP, эти файлы тоже стоит добавить в проект. Тогда VC6 сможет понять, что к примеру при изменении .LIB стоит пересобрать и зависимый от них модуль.
  • Если пользуетесь .PCH'ами, не забудьте во все *.c и *.cpp включить строчку
    #include "stdafx.h"
    
    вместо
    #include <ntddk.h>
    .....
    

2005.02.17

thanks to Emusic from http://www.rsdn.ru for additional #define's

2005.03.25

thanks to Axxie for bugfixes

2005.03.31

См. также:

<< Back Автор: Alter (Александр А. Телятников) Сервер: Apache+PHP под FBSD © 2002-2017