Пользователь
0,0
рейтинг
29 июня 2012 в 13:48

Разработка → Драйвер — это просто из песочницы

Многие считают что самому создать драйвер для Windows это что-то на грани фантастики. Но на самом деле это не так. Конечно, разработка драйвера для какого-то навороченного девайса бывает не простой задачей. Но ведь тоже самое можно сказать про создание сложных программ или игр. В разработке простого драйвера нет ничего сложного и я попытаюсь на примерах это показать.

Сперва нам нужно определится в чем мы же будем создавать наш первый драйвер. Поскольку материал ориентирован на новичков, то язык программирования был выбран один из простых, и это не Си или ассемблер, а бейсик. Будем использовать один из диалектов бейсика — PureBasic. Из коробки он не обучен создавать драйверы, но у него удачный набор файлов, используемых для компиляции и небольшое шаманство позволяет добавить эту возможность. Процесс компиляции состоит из нескольких этапов. Если кратко, то он происходит следующим образом: Сначала транслятор «перегоняет» basic-код в ассемблер, который отдается FASM'у (компилятор ассемблера), который создает объектный файл. Далее в дело вступает линкер polink, создающий исполняемый файл. Как компилятор ассемблера, так и линкер могут создавать драйверы и если немного изменить опции компиляции, то получим не исполняемый файл, типа EXE или DLL, а драйвер режима ядра (SYS).

Скачать немного модифицированную бесплатную демо версию PureBasic 4.61 x86 можно на файлопомойке, зеркало.
Если нужно создать драйвер для x64 системы, качайте эту версию, зеркало.

Дистрибутивы имеют небольшие размеры, около 3 МБ каждый. С помощью этой версии можно создавать только драйвера.
Скачиваем, распаковываем и запускаем, кликнув по файлу «PureBasic Portable». При этом запустится IDE и вылезет окошко с сообщением что это демо-версия и списком ограничений. Из него наиболее существенным является ограничение числа строк кода, равное 800, а для создания простых драйверов этого может хватить. Остальные ограничения в нашем случае, не существенны.

Окно IDE с загруженным кодом драйвера показано на скрине.

image

Компиляция драйвера выполняется через меню «Компилятор» (это если кто не понял).
image

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

Код драйвера:

Declare DriverEntry(*DriverObject, *RegistryPath)

!public PureBasicStart
!section '.code' code readable executable align 8
!PureBasicStart:
*A=@DriverEntry()
!jmp [p_A] ; Переход в процедуру DriverEntry().

#IOCTL_MyPlus = $200

!extrn PB_PokeL
    
CompilerSelect #PB_Compiler_Processor
  CompilerCase #PB_Processor_x86
    !extrn _IoCompleteRequest@8 ; Объявление импортируемых функций ядра.
    !extrn _RtlInitUnicodeString@8
    !extrn _IoCreateDevice@28
    !extrn _IoDeleteDevice@4
    !extrn _IoCreateSymbolicLink@8
    !extrn _IoDeleteSymbolicLink@4

    !extrn _PB_PeekI@4
    
    Import "ntoskrnl.lib" 
  CompilerCase #PB_Processor_x64
    
    !extrn IoCompleteRequest; Объявление импортируемых функций ядра.
    !extrn RtlInitUnicodeString
    !extrn IoCreateDevice
    !extrn IoDeleteDevice
    !extrn IoCreateSymbolicLink
    !extrn IoDeleteSymbolicLink
    !extrn PB_PeekI
    
    ImportC "ntoskrnl.lib"
  CompilerEndSelect
  
    
; Импорт функций ядра системы.
  IoCompleteRequest(*IRP, PriorityBoost)
  RtlInitUnicodeString(*UString, *String)
  IoCreateDevice(*DriverObject, DeviceExtensionSize, *UDeviceName, DeviceType, DeviceCharacteristics, Exclusive, *DeviceObject)
  IoDeleteDevice(*DeviceObject)
  IoCreateSymbolicLink(*SymbolicLinkName, *DeviceName)
  IoDeleteSymbolicLink(*SymbolicLinkName)
EndImport

Structure MyData ; Данные, передаваемые в драйвер.
  Plus_1.l
  Plus_2.l
EndStructure


; Прцедура обмена данными с программой.
Procedure DeviceIoControl(*DeviceObject.DEVICE_OBJECT, *pIrp.IRP)
  Protected *Stack.IO_STACK_LOCATION
  Protected *InpBuff, *OutBuff
  Protected InBuffSize, OutBuffSize
  Protected ntStatus, *MyData.MyData
  
  ntStatus = #STATUS_SUCCESS ; Все ОК.
  
  *Stack = *pIrp\Tail\Overlay\CurrentStackLocation
  
  ; Размеры буферов (см. WinAPI функцию DeviceIoControl())
  InBuffSize  = *Stack\Parameters\DeviceIoControl\InputBufferLength
  OutBuffSize  = *Stack\Parameters\DeviceIoControl\OutputBufferLength
  
  If InBuffSize >= SizeOf(Integer) And OutBuffSize >= 4
    
    Select *Stack\Parameters\DeviceIoControl\IoControlCode
      Case #IOCTL_MyPlus
        
        *Point = *pIrp\SystemBuffer
        If *Point
          *MyData = PeekI(*Point)
          
          If *MyData
            Result.l = *MyData\Plus_1 + *MyData\Plus_2
            PokeL(*pIrp\SystemBuffer, Result)
            *pIrp\IoStatus\Information = 4
          Else
            ntStatus = #STATUS_BUFFER_TOO_SMALL
            *pIrp\IoStatus\Information = 0
          EndIf
          
        EndIf
                
      Default
        ntStatus = #STATUS_UNSUCCESSFUL
        *pIrp\IoStatus\Information = 0
    EndSelect
  
  Else
    ntStatus = #STATUS_BUFFER_TOO_SMALL ; Размер буфера слишком мал.
    *pIrp\IoStatus\Information = 0
  EndIf
  
  *pIrp\IoStatus\Status = ntStatus
  IoCompleteRequest(*pIrp, #IO_NO_INCREMENT)
  
  ProcedureReturn ntStatus
EndProcedure


; Выгрузка драйвера. Вызывается при завершении работы драйвера.
Procedure UnloadDriver(*DriverObject.DRIVER_OBJECT)
  Protected uniDOSString.UNICODE_STRING
  
  ; Инициализация объектов-строк.
  RtlInitUnicodeString(@uniDOSString, ?DosDevices)
  ; Удаление символьной связи.
  IoDeleteSymbolicLink (@uniDOSString)
  
  ; Удаление устройства.
  IoDeleteDevice(*DriverObject\DeviceObject)
EndProcedure


; Вызывается при доступе к драйверу с помощью функци CreateFile().
Procedure CreateDispatch(*DeviceObject.DEVICE_OBJECT, *pIrp.IRP)
  *pIrp\IoStatus\Information = 0
  *pIrp\IoStatus\Status = #STATUS_SUCCESS
  IoCompleteRequest(*pIrp, #IO_NO_INCREMENT)
  ProcedureReturn #STATUS_SUCCESS
EndProcedure


; Вызывается при осовбождении драйвера функцией CloseHandle().
Procedure CloseDispatch(*DeviceObject.DEVICE_OBJECT, *pIrp.IRP)
  *pIrp\IoStatus\Information = 0
  *pIrp\IoStatus\Status = #STATUS_SUCCESS
  IoCompleteRequest(*pIrp, #IO_NO_INCREMENT)
  ProcedureReturn #STATUS_SUCCESS
EndProcedure


; Процедура загрузки драйвера. Вызывается однократно при его запуске.
Procedure DriverEntry(*DriverObject.DRIVER_OBJECT, *RegistryPath.UNICODE_STRING)
  Protected deviceObject.DEVICE_OBJECT
  Protected uniNameString.UNICODE_STRING
  Protected uniDOSString.UNICODE_STRING
  
  
  ; Инициализация объектов-строк.
  RtlInitUnicodeString(@uniNameString, ?Device)
  RtlInitUnicodeString(@uniDOSString, ?DosDevices)
  
  ; Создание устройства.
  status = IoCreateDevice(*DriverObject, 0, @uniNameString, #FILE_DEVICE_UNKNOWN, 0, #False, @deviceObject)
  If status <> #STATUS_SUCCESS
    ProcedureReturn status
  EndIf
    
  ; Создане символьной связи между именем этого устройства и именем,
  ; находящимся в видимой области для user-mode, для того, чтобы
  ; приложение могло получить доступ к этому устройству.
  status = IoCreateSymbolicLink(@uniDOSString, @uniNameString)
  If status <> #STATUS_SUCCESS
    IoDeleteDevice(@deviceObject)
    ProcedureReturn status
  EndIf
  
  ; Указатель на функцию выгрузки драйвера.
  *DriverObject\DriverUnload = @UnloadDriver()
  
  *DriverObject\MajorFunction[#IRP_MJ_CREATE] = @CreateDispatch()
  *DriverObject\MajorFunction[#IRP_MJ_CLOSE]  = @CloseDispatch()
  
  ; Указываем какая функция будет обрабатывать запросы WinAPI DeviceIoControl().
  *DriverObject\MajorFunction[#IRP_MJ_DEVICE_CONTROL] = @DeviceIoControl()
	
	ProcedureReturn #STATUS_SUCCESS
EndProcedure



; Имя драйвра (юникод).
DataSection
  Device:
  !du '\Device\pbDrPlus', 0, 0
  
  DosDevices:
  !du '\DosDevices\pbDrPlus', 0, 0
EndDataSection


Может показаться что это куча бессмысленного кода, но это не так.

У каждого драйвера должна быть точка входа, обычно у нее имя DriverEntry() и выполнена она в виде процедуры или функции. Как видите, в этом драйвере есть такая процедура. Если посмотрите на начало кода, то в первых строках увидите как ей передается управление. В этой процедуре происходит инициализация драйвера. Там же назначается процедура завершения работы драйвера, которая в нашем случае имеет имя UnloadDriver(). Процедуры CreateDispatch() и CloseDispatch() назначаются обработчиками соединения и отсоединения проги из юзермода.
Процедура DeviceIoControl() будет обрабатывать запросы WinAPI функции DeviceIoControl(), являющейся в данном драйвере связью с юзермодом. В конце кода расположена так называемая ДатаСекция (DataSection), в которой находятся имена драйвера, сохраненные в формате юникода (для этого использована одна из фишек ассемблера FASM).

Теперь рассмотрим как драйвер будет взаимодействовать с внешним миром. Это происходит в процедуре DeviceIoControl(). В ней отслеживается одно сообщение, а именно — #IOCTL_MyPlus, которое отправляет юзермодная прога, когда ей нужно сложить два числа в режиме ядра (круто звучит, правда?). Когда такое сообщение получено, то считываем из системного буфера, адрес указателя на структуру со слагаемыми, производим сложение и результат помещаем в системный буфер. Собственно это основная задача нашего первого драйвера.

Видите сколько понадобилось кода для выполнения простейшей математической операции — сложения двух чисел?

А теперь рассмотрим программу, работающую с этим драйвером. Она написана на том же PureBasic.


#DriverName = "pbDrPlus"
#IOCTL_MyPlus = $200

XIncludeFile "..\DrUserModeFramework.pbi"

Structure MyData ; Данные, передаваемые в драйвер.
  Plus_1.l
  Plus_2.l
EndStructure

; Абсолютный путь к файлу-драйверу.
DrFile.s = GetPathPart(ProgramFilename())+#DriverName+".sys"

; Загружает драйвер и если успешно, то порлучаем его хэндл.
hDrv=OpenDriver(DrFile, #DriverName, #DriverName, #DriverName)

If hDrv=0
  ; Деинсталляция драйвера из системы.
  Driver_UnInstall(#DriverName)
  MessageRequester("", "Ошибка загрузки драйвера")
  End
EndIf

; Обмен данными с драйвером.
Procedure.q Plus(hDrv, x1, x2)
  Protected MyData.MyData, Result, *Point
  
  MyData\Plus_1=x1
  MyData\Plus_2=x2
  *Point = @MyData
  DeviceIoControl_(hDrv, #IOCTL_MyPlus, @*Point, SizeOf(MyData), @Result, 4, @BytesReturned, 0)
  
  ProcedureReturn Result
EndProcedure


OpenWindow(1,300,300,140,90,"Title",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
StringGadget(1,10,10,50,20,"")
StringGadget(2,10,40,50,20,"")
TextGadget(3,70,30,70,20,"")
Repeat
  ev=WaitWindowEvent()
  If ev=#PB_Event_Gadget
    op1=Val(GetGadgetText(1))
    op2=Val(GetGadgetText(2))
    Result = Plus(hDrv, op1, op2)
    SetGadgetText(3,Str(Result))
  EndIf
Until ev=#PB_Event_CloseWindow


; Если драйвер загружен, то закрываем связь с ним.
If hDrv
  CloseHandle_(hDrv)
  hDrv=0
EndIf

; Деинсталляция драйвера из системы.
Driver_UnInstall(#DriverName)


При старте программы вызывается функция OpenDriver(), которая загружает драйвер. Для упрощения, имя драйвера, имя службы и описание службы заданы одинаковыми — «pbDrPlus». Если загрузка неудачная, то выводится соответствующее сообщение и программа завершает свою работу.

Процедура Plus() осуществляет связь с драйвером. Ей передаются хэндл, доступа к драйверу и слагаемые числа, которые помещаются в структуру и указатель на указатель которой, передается драйверу. Результат сложения чисел будет в переменной «Result».

Далее следует код простейшего GUI калькулятора, скопированного из википедии.

Когда закроют окно, то перед завершением работы программы, закрывается связь с драйвером и производится его деинсталляция из системы.

Результат сложения чисел 8 и 2 на скриншоте.

image

Исходные коды драйвера и программы, можно найти в папке «Examples», PureBasic на файлопомойке, ссылку на который давал в начале статьи. Там так же найдете примеры драйвера прямого доступа к порам компа и пример работы с памятью ядра.

PS.
Помните, работа в ядре чревата мелкими неожиданностями аля, BSOD (синий экран смерти), поэтому экспериментируйте осторожно и обязательно всё сохраняйте перед запуском драйвера.

За возможную потерю данных, я ответственности не несу!
@hachik
карма
11,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (60)

  • 0
    И что потом делать с этим драйвером на BASIC'е? Все-равно если понадобится потом написать настоящий драйвер для устройства, то лучше выбирать Си (ИМХО).
    • 0
      А для user mode драйвера с++.
    • +7
      Странный вопрос. Что делают с драйверами?
      Какая разница на чем написан драйвер? Ведь для системы это не имеет значения.
      • 0
        Это имеет значение для людей, которые будут развивать или сопровождать код.
      • 0
        Ну это как минимум выглядит несерьезно. И где вы потом найдете программиста на BASIC'е, который будет разбираться в системном программировании? :-)
  • +3
    Ну зачем использовать Basic?! Я не против языка, но C проще и понятней, тем более в случае системного программирования. А некоторые директивы вообще вводят меня в шок :)

    И откуда вы решили — что сейчас начинающие пишут на Basic?
    • +1
      Я не заставляю использовать бейсик или др. язык. Выбирать вам.
      Не все, но некоторые начинают с бейсика. Он ИМХО намного проще чем Си, как для понимания так и для разработки.
      • –2
        Проблема в том, что у BASIC'а я не вижу никакого достойного продолжения. Ненавистный мне Pascal и то позволяет программистам в дальнейшем рисовать окошечки и делать еще кучу всякой фигни в Delphi.
        • +3
          Разве вы не смотрели код?
          Разве это не создание окна OpenWindow()?
          Поэтому вы очень сильно заблуждаетесь насчет возможностей современных диалектов бейсика. Можно не только создавать окошки, но и разрабатывать кроссплатформенные приложения, компилируемые под Windws, Linux, MacOS X, AmigaOS и т. д.
          • 0
            Хорошо, а что насчет моего другого аргумента — где взять программистов?

            Вот я, допустим, не скрою, знал BASIC. И не знал тогда еще ничего ни о системеном программировании, ни об ООП, ни вообще об устройстве больших и серьезных программ. Сейчас я могу и драйвер на Си написать (под Linux, правда) и ООП хоть на том же Си не проблема (ага, без плюсов :-). Но без Google'а я не напишу даже HelloWorld'а на BASIC'е.

            И так со многими людьми, кто хоть когда-то знал BASIC.
            • +2
              Разве я писал об создании драйверов на профессиональном уровне и призывал всех с Сей и асма переходить на бейсик?

              Я извиняюсь, вы на каком диалекте бейсика когда-то кодили?
              Судя по всему, это QBasic или сродни ему. PureBasic намного продвинутее его. Релиз данной версии был буквально месяц назад.
              И на PureBasic есть относительно серьезные программы, к примеру, торрент клиент — pbTorrent.
              • 0
                QBasic, DarkBASIC, VisualBasic
      • +2
        Этот материал в первую очередь предназначен для обучения. Нужно ведь с чего-то начинать и при этом по возможности все должно быть не очень сложно. Помните как вы пошли в первый класс в школе? Что вы там учили? Высшую математику или таблицу умножения? Так же и здесь.
        • 0
          Если человек решил написать драйвер, то ему пара взрослеть и завязывать с BASIC'ом. ИМХО, конечно.

          Аналогично со школой — если ребенок уже учится в старших классах и изучает математику на более высоком уровне, чем в первом, то абсурдно считать на цветных палочках.
          • +2
            Я поддержу автора статьи. Нет ничего плохого в том, что человек разузнал и попробовал какой-то инструмент. Вдвойне хорошо, что он поделился своим опытом. Теперь и я знаю, что есть некая «хрень», которая позволяет писать драйверы на бейсике. Ну мало ли что, вдруг пригодится? И пусть автор никогда не будет использовать BASIC в рабочих системах (а я надеюсь что это так), опыт всё равно полезен.
            • 0
              Я не отрицаю, что автор молодец в этом плане. Я ему и за топик, и в карму плюсик поставил. Я лишь пытаюсь предостеречь остальных от этого пагубного дела (писать драйвер на BASIC'е).
        • 0
          Так есть понятные примеры в DDK.
      • 0
        Мне кажется, что С знают больше людей, чем Basic, и в этом проблема (с точки зрения «статья для обучения)». Я вот, например, начинал с Pascal, а с Basic ничего общего не имел, и таких как я может быть много. Грустно, что эта статья обходит меня стороной.
        • 0
          Извините, я там со скобками-кавычками напортачил.
  • +20
    Нет ничего проще, чем написать драйвер — поэтому усложним задачу и напишем его на диалекте бейсика!
    • +8
      Что на вас всех бейсик действует как красная тряпка на быка?
      Я же привел пример дрова на Brainfuck'е. Вот это реально было бы усложнение задачи.
      • 0
        Why so serious? Вы молодец, что отстаиваете свою позицию.
      • 0
        Драйвера на C проще, т.к. есть готовые декларации функций, поставляемые с WDK.
        На другом языке программирования Вам пришлось писать декларации импортируемых функций вручную, и вручную же гарантировать их корректность.
        Кстати, стоит упомянуть еще о статическом анализаторе PREFast, который заточен под C.
  • +5
    Дривер на Васике :) Мсье знает толк в извращениях
    • +3
      Хотя… Беру свою насмешку обратно. Прочитал по про ru.wikipedia.org/wiki/PureBasic и подумал, что использовать Васик не так уж и странно в данном случае — не надо ставить многотонные компиляторы и среды разработки. Рабочая среда легко развертывается и не менее легко сносится с компьютера. Для написания примера на тему «да, я смог сделать драйвер» — самое то.
    • 0
      Ага, лучше писать на ассемблере, да?
      И если нужно будет перенести его с 32 на 64 бита, ох уж и попотеете при этом! Вот это точно извращение ИМХО!
      А выложенный мной пример драйвера, компилируется как под x86, так и под x64 без модификации кода.
      • +1
        Вот для этих целей умные люди и придумали Си. И он далеко не только под x86 и x64 компилируется :-)
  • +4
    Пятница! Драйвер на диалекте basic! Вполне коллерируется! 5 баллов!
  • +2
    Ага, а теперь мы попробуем написать хоть немного функционально нагруженный драйвер и с учетом того, что нам необходимо будет узнать что такое UM-KM transition, IRQL, memory model, I/O model, всякие IDT, GDT, LDT, TSS, как раз и выходит «что-то на грани фантастики». Особенно весело это будет смотреться на бейсике :)
  • +7
    o_O

    OOOH MY FUCKING EYES

    Зы. Развелось вас: ithappens.ru/story/3099, результат как правило — ekimoff.ru/281/. Довить тапком!
    Ззы. wasm.ru/publist.php?list=21 — вот нормальные туториалы, кому нужно.
    • 0
      К сожалению, статьи по ссылке устарели. Начиная с Vista лучше использовать новый Kernel Mode Driver Framework и, для некоторых видов драйверов, User Mode Driver Framework.
  • 0
    Что-то бейсик всех пугает=) Я знаю одну очень крупную систему в Швеции, которая пишется на VB.Net, причем на Vb.Net пишется не только клиент, но и сервер. Вот так исторически сложилось и НИКАКИХ проблем нет, все работает.
    По сути современный Васик от МС может не меньше C#.
    • 0
      Замечательно. Только драйвера ОС немного отличаются от «крупных систем на VB.NET» тем, что они обычно пишутся на С c вставками на ASM. Написать драйвер на диалекте бейсика не проблема, но это всё равно что есть суп шумовкой. Приноровиться можно, но смысл?
      • НЛО прилетело и опубликовало эту надпись здесь
        • +1
          В процессе компиляции задействован FASM, поэтому допустимы не только асм. вставки, но и директивы и макросы FASM'а.
          Например, в начале кода драйвера есть строка для FASM'а.
          !section '.code' code readable executable align 8
          Думаю что означает и так понятно.
  • +4
    Зачем убивать себе мозг бейсиком если на С драйвер будет не намного сложнее? У меня есть небольшая статейка о драйверах, которую я написал на 3м курсе, если кому интересно почитать могу оформить и выложить.
    • +3
      Оформляйте и выкладывайте. Уверен, это будет интересно не только мне
    • 0
      Трюк в том, что реальный драйвер, который что-то делает, допустим вводит или выводит какие-то данные с устройства — на Си будет проще. Почему? Потому что там внутре у функций ядра все данные представлены в виде структур Си с указателями, адресной арифметикой и прочими прелестями. К ним можно сделать обертку на Бейсике, Паскале, да хоть JavaScript-e, но это всё равно будет оберткой над чужеродными данными.
      • +1
        Странная логика, ведь после компиляции уже неважно на чем написано.
        И для системы все рано, бейсик это или Си.
        • 0
          После компиляции — да.
          Проблема в коде, который ДО компиляции.
          Если, условно, в Бейсике нет понятия «указатель» и «адресная арифметика», а они нужны для работы драйвера, то программисту всё равно придется разобраться с этой адресной арифметикой, а потом пользоваться ей через какие-то кривые функции-обертки, предоставленные библиотеками языка.
          • +1
            Как нет указателей?
            Найдите в процедуре DeviceIoControl() драйвера строку *Stack = *pIrp\Tail\Overlay\CurrentStackLocation а чуть выше строка Protected *Stack.IO_STACK_LOCATION
            Если не поняли, то это доступ к структуре IO_STACK_LOCATION по указателю, хранимому в поле *pIrp\Tail\Overlay\CurrentStackLocation

            И с чего вы решили что нет адресной арифметики?
          • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    Что-то я не вижу у вас стандартных танцев с бубном вокруг сертификатов, самоподписей, тест мода и прочих чудес. Вы на 64битах на чем запускали?
    • +1
      Переводил ОС в тестовый режим и запускал.
      Подпись драйвера выходит за рамки этой статьи.
  • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      И сейчас с этим все отлично: WDK
  • 0
    Хорошо, может кто-то напишет про что-то подобное для Линукса и на С? :)
  • 0
    Драйвер для Windows, написанный на BASIC… Вам определённо стоит заняться написанием ОС на Ruby или распределённой базы данных на Brainfuck.
  • 0
    Хоть раньше и много писал на VB, но данный диалект вводит меня в ступор.
    • +1
      Все просто.
      Если разобраться то ИМХО даже проще и логичнее чем в VB. Работа с памятью и указателями более развита и дает больше свободы действий. Вообще, область решаемых задач шире чем у VB.
      Но синтаксис отличается от того, что в VB.
  • +2
    Кода много, описания почти никакого. Новички не поймут, опытные офигеют от ЯП. Смысл не понятен…
  • 0
    Эх… 10 лет назад мы писали курсач «wmd драйвер для перехвата сетевого трафика на wasm». Сколько же было бессонных ночей, сколько нулевых колец, сколько синих экранов, сколько перезагрузок (про виртуальные машины мы тогда и не мечтали). Отладка, естественно, на той же машине, где и разрабатывали. Скучаю по тем дням)
  • +2
    Хм… Такое ощущение, что самплы из ddk глянуть нельзя, на васме нет тутов four-f'а, который проводит их на основе тех же самплов… Очередная копипаста материала, которым и так заполнена сеть. лол, товарищи.
    • 0
      Эту статью я сам писал, так что не гоните про копипасту.
      • 0
        Мессадж не получен. Я имел ввиду, что материал по содержанию отнюдь не свеж. И я не понимаю, какой смысл писать то, что есть в том же ddk на другом языке и выкладывать на хабре.
        Может вы гордитесь тем, что написали… даже не велосипед, а спицу от колеса велосипеда на «не си». Я не понимаю, что этот материал делает на хабре.
  • +1
    > Драйвер — это просто
    Особенно это видно по кривым драйверам для принтером и МФУ HP и других производителей.
    • 0
      Я вообще не понимаю зачем делать драйвер для принтера/сканера в виде драйвера, а не user-mode приложения, особенно если этот принтер/сканер сетевой?

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