Форум программистов, компьютерный форум, киберфорум
Наши страницы

Программирование драйверов

Войти
Регистрация
Восстановить пароль
 
 
ASDFD12
57 / 57 / 13
Регистрация: 15.09.2012
Сообщений: 542
#1

Зачем нужен драйвер и как написать простейший драйвер - Программирование драйверов

23.09.2012, 14:50. Просмотров 47410. Ответов 38
Метки нет (Все метки)

Хотя в интернете и есть на русском языке некоторые обяснения что такое драйвер для его програмирования считаю это довольно узко. Рускоязычные книги тоже не совсем понятно написаны. Вобщем мои рассуждения ( правильны ли они). Расссматриваю написания драйверов под виндовс. Для стабильности ОС програмисты разделиль функционирование ОС на две части - пользовательский режим и режим ядра, так как в пользовательском режиме возможности малы, то и испортить систему меньше шансов разным софтом. Драйвера работают в режиме ядра. Соответственно есть уже готовые функции API которые реализуют низкоуровневые операции и с помощью которых в основном и пишутся драйвера. Думаю что почти любой драйвер можна написать на основании этих функций + некоторые созданные собственно + асемблерные вставки. Соответственно драйвер считаю - это добавка до кода ОС, которая обясняяет как ей общаться с ОС. А как это делается ? Предполагаю что драйвер указывает какие низкоуровневые функции мы можем применить по отношению до даного устройства, указать какой приоритет у даного устройства. Неукладывается в голове что конкретно он делает. Вот подключаем мы какое-то неизвестное устройство до ПК. Оно подает какие то сигналы, и должно обрабатывать входящие. Для того чтобы просто работать с устройством ( ближе до человеческого языка) думаю что драйвер - это "образ" устройства в програмной форме - что то наподобе применения обектов в пользовательских приложениях (ООП). Тоесть мы создаем клас даного устройства, который описывает функции которые имеет даный обект и его свойства - не знаю какие. Кто как понимает - что делает драйвер. С чего начинается создание драйвера. Если допустим управлять внешним контроллером как выключателем. Почему написания драйверов кардинально отличается от написания пользовательського кода. Эсть ли какая то аналогичность. Очень хотелось бы чтобы человек который уже писал драйвера и четко все себе уяснил постарался по простому тезисно обяснить суть, самые важные аспекты по написанию драйверов.
2
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
23.09.2012, 14:50
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Зачем нужен драйвер и как написать простейший драйвер (Программирование драйверов):

Как написать драйвер для COM-порта - Программирование драйверов
Люди, помогите написать драйвер для COM порта ... устройство: нажали на датчик и данные пошли в прогу, где в график преобразуются... ...

Как написать драйвер для флешки, шифрующий данные - Программирование драйверов
Как написать драйвер для флешки, шифрующий данные на ней)

Помогите написать драйвер клавиатуры! - Программирование драйверов
1)Издающий писк только при вводе цифр на дополнительной клавиатуре 2)Издающий писк, если слово оканчивается буквой "в" 3)Издающий...

Написать драйвер для мышки - Программирование
помогите написать драйвер мыши!!

Можно ли написать свой драйвер для мышки? - Программирование драйверов
Я хочу написать свой драйвер каторый будет сам наводить прицел на врага (шутер). можно ли так сделать и на каком языке лучше? И еще...

Как установить свой драйвер? - Программирование драйверов
Где можно прочитать про создание inf файла? что ещё необходимо? скомпелировал WINDDK, получил sys-файл Написал inf файл, но выдаёт...

38
Mikl___
Автор FAQ
11029 / 5803 / 513
Регистрация: 11.11.2010
Сообщений: 10,814
26.09.2012, 06:12 #2
ASDFD12,
хороший цикл статей «Драйверы режима ядра», написанный Four-F, почитай его. Написание драйвера ничем кардинально не отличается от написания пользовательского кода, просто требует дополнительных усилий по отладке и наличие отладчиков для программ режима ядра и прежде чем "тезисно объяснять суть, самые важные аспекты по написанию драйверов" хотелось бы узнать какие книги прочел ТС, чтобы опереться на что-то, а не объяснять ВСЁ подряд...
1
ASDFD12
57 / 57 / 13
Регистрация: 15.09.2012
Сообщений: 542
26.09.2012, 19:08  [ТС] #3
Спасибо за ответ, почитаю. Нащет книг - С++, C# (в основном по консольным приложениям). Изучал электронику (цыфровую как раз неизучал). Прочел азы асемблера (половину книги). Захотелось создавать устройства на МК, и как их связать с ПК. Прочел пару статей в интернете, пробежался 70% книги Комисарова (по драйверам) - изучить по такой книге нереально, пример драйвера дается сразу с потолка - вот так нада и все. Искал разную литературу и понял что ее почти нет на русском языке. Все на английском, а я его знаю плохо, чтобы читать книги. Книг по DDK тоже нет. Сейчас начал читать книгу по разработке операционной системы. Таких книг немного есть на русском и вижу, что они могут дать неплохую базу. Что скажете?
0
Mikl___
Автор FAQ
11029 / 5803 / 513
Регистрация: 11.11.2010
Сообщений: 10,814
10.10.2012, 10:25 #4
Доступ к командам In/Out через драйвер режима ядра

Вообще то, здесь должна была быть статья с рабочим названием «Доступ к портам ввода/вывода под Windows XP». «Иллюстрациями» к статье должны были kernel-mode драйвера, но так как статья до сих пор не готова, а драйвера уже есть, начну с них. Все драйвера, которые будут приводится в этом топике, будут открывать порты 42h, 43h, 61h, чтобы сыграть системным динамиком «Марш клоунов» Нино Ротта.

Переделаем драйвер beeper из KmdTutor by Four-F.
Драйвер собирается при помощи следующих строк в bat-файле

Код
cls
set filename=%1
if exist %filename%.sys del if exist %filename%.sys
set masm_path=\masm32
%masm_path%\bin\ml /c /Cp /Gz /I%masm_path%\include /nologo /c /coff %filename%.asm  || exit
%masm_path%\bin\link /LIBPATH:%masm_path%\lib\ /nologo /driver /base:0x10000 ^
/align:32 /out:%filename%.sys /subsystem:native %filename%.obj  || exit
if exist %filename%.obj del %filename%.obj
Теория

На материнской плате находится перепрограммируемый интервальный таймер ― система, состоящая из трех каналов, каждый из которых можно запрограммировать для работы в одном из шести режимов. На многих современных материнских платах расположено два таких таймера, следовательно, число каналов равно шести.
таймерпортназначение портаназначение канала
первый таймер40hканал #0отвечает за ход системных часов. Сигнал с этого канала вызывает прерывание времени. 18,2 раз в секунду выполняется процедура, на которую направлен вектор прерывания #8. Эта процедура производит изменения в области памяти, где хранится текущее время. В специальном регистре задвижки хранится число синхроимпульсов, по прошествии которых сигнал таймера должен вызвать прерывание времени. Уменьшая это число (через порт каналов), можно заставить идти системные часы быстрее. Канал #0 используется также для синхронизации некоторых дисковых операций, поэтому при при изменеии числа синхроимпульсов необходимо восстановить первоначальное значение перед использованием обращений к дискам.
 41hканал #1отвечает за регенерацию памяти. Можно уменьшить число циклов регенерации памяти в секунду, однако это можно делать лишь в небольших пределах, так как при увеличении промежутка регенерации возрастает вероятность сбоя памяти
 42hканал #2обычно задействуют для работы с динамиком, хотя можно использовать и для других целей, например для синхронизации какого-либо внешнего устройства.
 43hуправляющий регистр 
второй таймер для компьютера с шиной Microchannel44hканал #0 
 45hканал #1
 46hканал #2 
 47hуправляющий регистр 
второй таймер для компьютера с шиной EISA48hканал #0 
 49hканал #1 
 4Ahканал #2 
 4Bhуправляющий регистр 
Таблица #1:Пространство портов ввода/вывода для таймера
Второй канал таймера управляет системным динамиком компьютера, генерируя прямоугольные импульсы с частотой 1193180/начальное значение счетчика герц. Начальное значение счетчика является 16-битным, и устанавливается через порт 42h. 1193180 Гц ― частота тактового генератора таймера. Динамик включается и выключается при выводе специального значения в порт управления динамиком с номером 61h, связанный с микросхемой программируемого контроллера периферийного интерфейса Intel 8255. Для включения динамика нужно прочитать байт из порта 61h, установить в единицу его два младших бита (0-ой бит разрешает работу канала таймера, а 1-ый бит включает динамик), а затем записать полученное значение в тот же порт. Чтобы отключить динамик, нужно сбросить значение двух младших битов порта 61h. Все управление таймером осуществляется путем вывода байта в порт 43h. Назначение битов порта 43h приведены в таблице #2.
Номер бита назначение
 Если 7-6 биты не равны 11b, значит байт, посылаемый в порт 43h ― это команда программирования канала[/B]
7-6Номер канала:
  00b ― 0-ой канал
 01b ― 1-ый канал
 10b ― 2-ой канал
5-4Индикатор считывания/записи
  00b ― зафиксировать текущее значение счетчика для чтения (в этом случае биты 3-0 не используются)
 01b ― чтение/запись только младшего байта
 10b ― чтение/запись только старшего байта
 11b ― чтение/запись сначала младшего, а потом старшего байта
3-1Режим работы канала:
000b ― Прерывание IRQ0 при достижении нуля (концу счета). Сигнал GATE=1 разрешает счет, а GATE=0 запрещает счет, причем GATE не влияет на выход OUT. Содержимое CR передается в CE по первому импульсу CLK после того, как процессор осуществил запись в CR, независимо от сигнала на входе GATE. Импульс, который загружает CE, не учитывается при счете. На выходе OUT формируется низкий уровень при записи в регистр управления, который сохраняется до достижения счетчиком 0. Режим 0 предназначен в основном для счета событий.
 001b ― Аппаратно-перезапускаемый одновибратор (ждущий мультивибратор). После загрузки значения N в CR переход 0->1 на входе GATE вызывает загрузку CE, переход 1->0 на выходе OUT и запускает счет. Когда счетчик достигнет 0, на выходе OUT формируется высокий уровень; таким образом, результатом является отрицательный импульс на выходе OUT с продолжительностью N периодов синхронизации.
 010b ― Переодический интервальный таймер (генератор импульсов). После загрузки значения N в CR следующий импульс синхронизации осуществляет передачу из CR в CE. На выходе OUT возникает переход 1->0, когда счетчик достигает 0; низкий уровень сохраняется в течение одного импульса CLK. Затем на выходе OUT появляется высокий уровень, производится повторная загрузка CE из CR; в результате на выходе OUT появляется отрицательный импульс через N тактов синхронизации. Сигнал GATE=1 разрешает счет, а GATE=0 запрещает. Переход 0->1 на выходе GATE вызывает ренинициализацию счета следующим импульсом синхронизации. Данный режим применяется для реализации переодического интервального таймера.
 011b ― Генератор прямоугольного сигнала. Аналогичен режиму 2, но на входе OUT формируется низкий уровень при достижении половины начального счета; этот уровень сохраняется до достижения счетчиком 0. Как и прежде, сигнал GATE разрешает и запрещает счет, а его переход 0->1 реинициализирует счет. Этот режим применяется в генераторах, определяющих скорость передачи в бодах.
 100b ― Программно-запускаемый строб. Аналогичен режиму 0, но на выходе OUT в процессе счета действует высокий уровень, а при достижении счетчиком 0 появится отрицательный импульс с продолжительностью в один такт синхронизации.
 101b ― Аппаратно-запускаемый строб с перезапуском. После загрузки CR переход 0->1 на входе GATE вызывает передачу из CR в CE следующим импульсом CLK. В процессе счета на выходе OUT действует высокий уровень, а при достижении счетчиком 0 формируется отрицательный импульс с продолжительностью в один период CLK. Сигнал GATE может в любой момент времени реинициализировать счет.
0Формат счетчика:
0 ― двоичное 16-разрядное число с диапазоном от 0 до 0FFFFh. Максимальное значение счетчика = 216- 1
 1 ― двоично-десятичное число с диапазоном от 0000 до 9999. Максимальное значение счетчика = 104- 1
 Если 7-6 биты равны 11b, значит байт посылаемый в порт 43h ― это команда чтения счетчиков
7-6 11b ― команда чтения счетчиков
5-4 00b ― сначала состояние канала, потом значение счетчиков
 01b ― значение счетчиков
 10b ― состояние канала
3-1 Команда относится к каналам 0-2
Таблица #2: Назначение битов порта 43h
Частота генерируемого звука задается с помощью микросхемы программируемого интервального таймера Intel 8253. Этот контроллер в числе прочего определяет, сколько импульсов в секунду следует послать на системный динамик. Таймер вырабатывает базовую частоту 1,193180 МГц. Первоначальное значение делителя частоты установлено в (1)0000h, что эквивалентно 65536. Для этого числа частота прерываний таймера равна 1193180/65536=18,20648193359375 Гц, что ниже граничной частоты восприятия звука человеком. Мы можем посылать Intel 8253 другое число для деления базовой частоты 1,19 МГц. Для установки таймера в правильный рабочий режим посылаем число 0B6h в порт 43h. После этого можно использовать порт 42h для передачи делителя. Если отправить в порт 42h число 5000, то получим частоту следования импульсов 1193180/5000=238,636 Гц, чуть ниже ноты си третьей октавы (для третьей октавы значение частоты из таблицы #3 делят на 2, а для пятой октавы ― умножают на 2). Так как делитель является 16-разрядным числом, поэтому передаем его двумя частями. Сначала отправляем младший байт, а затем старший байт.
нотачастота (Гц)делитель =1193180/частота
до диез 277,23 10CFh
ре 293,66 0FDFh
ре диез 311,13 0EFAh
ми 329,63 0E23h
фа 349,23 0D58h
фа диез 370 0C98h
соль 392 0BE3h
соль диез 415,3 0B39h
ля 440 0A97h
ля диез 466,16 9FFh
си 493,88 96Fh
до 523,25 8E8h
Таблица #3: Ноты четвертой октавы

Практика

Выводим в порт 43h число 0B6h=10.11.011.0b, мы помещаем в управляющий регистр таймера значение, определяющее:
  • номер канала, которым мы будем управлять (10b=2-ой канал)
  • тип операции (11b = чтение/запись сначала младшего, а потом старшего байта)
  • режим работы канала (011b = генератор прямоугольных импульсов (основной режим))
  • формат счетчика (0 = 16-разрядное число от 0 до 0FFFFh)
Assembler
1
2
    mov al,0B6h
    out 43h,al
Затем, в порт 42h выводим 16-битное начальное значение счетчика. Сначала младший байт, затем старший.
Assembler
1
2
3
4
5
6
        mov esi,offset melody; данные
    mov ecx,size_melody  ; счетчик
    mov dx,42h      ;используем порт 42h для передачи делителя
a0: . . . ; создаем задержку между импульсами в 40 мкСек
    outsb
    loop a0
Команда OUTSB выводит данные в порт ввода- вывода, номер которого загружен в регистр DX, из ячейки памяти по адресу DS:ESI (массив melody), после выполнения команды OUTSB содержимое регистра ESI увеличивается на единицу, это будет происходить до тех пор, пока содержимое регистра ECX не станет равным нулю. Для получения задержки, чтобы не зависеть от быстродействия конкретного CPU, используем функцию KeStallExecutionProcessor. После проигрыша мелодии выключаем динамик, сбрасывая два младших бита. На время работы с регистрами таймера, запрещаем аппаратные прерывания (команда CLI). На этом работу нашего драйвера можно считать законченной. Драйвер возвращает системе STATUS_DEVICE_CONFIGURATION_ERROR ― код фиктивной ошибки и благополучно удаляется системой из памяти. Код ошибки возвращен только для того, чтобы система сама удалила драйвер и он понапрасну не «болтался» в памяти. Когда мы доберемся до полнофункциональных драйверов, то, естественно, будем возвращать STATUS_SUCCESS.
Assembler
1
2
    mov eax, STATUS_DEVICE_CONFIGURATION_ERROR;возвращаем код ошибки, для 
    ret     ;того, чтобы система удалила драйвер из памяти
Далее исходный текст драйвера scp00.sys
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
; masm windows native #
;написано на основе драйвера режима ядра beeper из «KmdTutor by Four-F»
.686P
.model flat
include ntstatus.inc
include ntddk.inc
includelib hal.lib
extern _imp__KeStallExecutionProcessor@4:dword
.code
DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING
    cli
    in al,61h   ;получаем текущий статус порта B
    or al,00000011b ;включаем системный динамик и таймер
    out 61h,al  ;заменяем байт
    mov al,0B6h     ;установка канала 2 микросхемы 8253 в правильный
    out 43h, al     ;рабочий режим для приема делителя
        mov esi,offset melody; данные
    mov ecx,size_melody  ; счетчик
    mov dx,42h      ;используем порт 42h для передачи делителя
a0: push ecx        ;запоминаем содержимое edx и ecx, так как функция
    push edx        ;KeStallExecutionProcessor их обязательно изменит
    mov ecx,800; 50 мкСек * 800 = 40 мСек
a1: push ecx
    push 50; максимальное количество мкСек для функции KeStallExecutionProcessor
    call _imp__KeStallExecutionProcessor@4
    pop ecx
    loop a1
    pop edx         ;восстанавливаем содержимое edx и ecx
    pop ecx         ;команда outs выводит данные в порт ввода/вывода
    outsb       ;номер, которого загружен в регистр DX, 
    loop a0     ;из ячейки памяти по адресу DS:ESI
    in al,61h   ;получаем текущий статус порта B
    and al,11111100b ;выключаем системный динамик и таймер
    out 61h,al      ;заменяем байт
    sti
    mov eax, STATUS_DEVICE_CONFIGURATION_ERROR;возвращаем код ошибки, для 
    ret     ;того, чтобы система удалила драйвер из памяти
melody  dw 2 dup(354h),2,2,2 dup(387h),2,2,2 dup(3BDh),2 dup(387h)
    dw 2 dup(3BDh),2 dup(3F5h),2 dup(432h),2,2,2 dup(472h),2,2
    dw 4 dup(4B5h),4 dup(472h),2 dup(3F5h),2,2,2 dup(432h),2,2
    dw 2 dup(472h),2 dup(432h),2 dup(472h),2 dup(4B5h),2 dup(4FDh) 
    dw 2,2,2 dup(549h),2,2,4 dup(599h),4 dup(549h),2 dup(472h)
    dw 2,2,5EEh,2,5EEh,2,4 dup(649h),4 dup(5EEh),2 dup(472h),2,2
    dw 5EEh,2,5EEh,2,4 dup(649h),4 dup(5EEh),2 dup(70Eh),2 dup(6A8h)
    dw 2 dup(649h),2 dup(5EEh),2 dup(599h),2 dup(549h),2 dup(4FDh)
    dw 2 dup(4B5h),2 dup(472h),2,2,2 dup(432h),2,2,2 dup(3F5h),2,2
    dw 2 dup(387h),2,2,8 dup(354h),2
size_melody = $ - melody
user-mode приложение может запустить драйвер следующими способами:
  1. использовать API-функции Service Control Manager'a;
  2. прописать драйвер в реестре «вручную» и загрузить его с помощью функции ZwLoadDriver. В реестре создается в минимум необходимых записей, после запуска драйвера его раздел удаляется из реестра;
  3. загрузить драйвер при помощи функции ZwSetSystemInformation;
  4. через динамический загрузчик Свена Шрайбера, прилагаемый к его книге «Недокументированные возможности Windows 2000» (сам загрузчик можно найти на WASM'е). (Ничего нового! Та же загрузка драйвера через API-функции Service Control Manager'a, единственный плюс ― ничего не нужно писать самому, всё, что от вас требуется ― это указать в коммандной строке динамическому загрузчику полный путь до вашего драйвера)

Первый вариант user-mode приложения, которое запускает драйвер scp00.sys

user-mode приложение, которое запускает scp00.sys драйвер, используя API-функции Service Control Manager'a: OpenSCManager, CreateService, StartService, CloseServiceHandle и DeleteService.
Этот способ очень прост и хорошо документирован, он подходит для постоянной установки драйверов.

Для запуска и управления драйвером необходимы следующие компоненты:
  • диспетчер управления службами (Service Control Menager ― SCM). Именно благодаря ему мы будем иметь возможность легко и просто загружать драйверы;
  • программа управления службами (Service Control Programm ― SCP). Это программа третьего кольца; она работает с диспетчером управления службами (вызывает функции, которые он предоставляет), чтобы установить, запустить драйвер и завершить его работу;
  • собственно сам драйвер;
  • для запуска драйвера его необходимо зарегистрировать. За этот процесс в системе отвечает функция CreateService. Также при работе с драйвером потребуются следующие функции: StartService, ControlService, DeleteService, CloseServiceHandle
Кроме того, для возможности работы с диспетчером управления службами необходимо получить к нему доступ при помощи функции OpenSCMenager. Функция CloseServiceHandle закрывает описатель, который возвращает функция OpenSCMenager. Все функции, которые предоставляет диспетчер управления службами, находятся в advapi32.dll.

На конечном этапе загрузки системы перед появлением диалога регистрации пользователя запускается SCM (\%SystemRoot%\System32\Services.exe), который, просматривая раздел реестра HKEY_LOCAL_MASHINE\SYSTEM\CurentControlSet\Service\, создает свою внутреннюю базу данных (ServiceActive database или SCM database). Далее SCM находит в созданной базе все драйвера устройств и службы, помеченные для автоматического запуска, и загружает их.

Рассмотрим процесс запуска и управления драйвером более подробно.

Помещаем драйвер в сервисную базу. База должна быть предварительно открыта функцией OpenSCManager:
C
1
2
3
4
5
SC_HANDLE OpenSCManager(
  LPCTSTR lpMachineName,
  LPCTSTR lpDatabaseName,
  DWORD dwDesiredAccess
);
Параметры:
lpMachineName
Указатель на строку (завершающуюся нулём), содержащую имя компьютера. Этот параметр мы сразу устанавливаем в NULL, так как будем открывать канал связи с SCM только на локальном компьютере.
lpDatabaseName
Указатель на строку (завершающуюся нулём), которая содержит имя открываемой базы данных менеджера управления сервисами. Этот параметр должен быть равен SERVICES_ACTIVE_DATABASE. Если этот параметр приравнять NULL, то по умолчанию будет открыта база SERVICES_ACTIVE_DATABASE. Так как мы не собираемся открывать никакую другую базу данных SCM, кроме активной в данный момент, просто, установим этот параметр в NULL.
dwDesiredAccess
Права доступа к менеджеру управления сервисами. Сообщает SCM, что мы собственно намереваемся делать с его базой данных. Нам могут быть полезны три значения:
Значение Предназначение
SC_MANAGER_CONNECT доступ на установку канала связи с SCM. По умолчанию (то есть если просто передать в этом параметре 0), устанавливается именно это значение. Хотя в документации ничего не говорится, что конкретно мы можем делать с этим уровнем доступа. А делать можно многое: запускать драйвер, останавливать, и даже удалять сведения о нем из базы данных SCM и из реестра.
SC_MANAGER_CREATE_SERVICE доступ на занесение в базу данных SCM нового драйвера. Так как мы собираемся занести туда своего представителя, то именно это значение и используем. Можно подумать, что никаких других прав, кроме регистрации нового драйвера, этот флаг не дает. Это не так. Так как флаг SC_MANAGER_CONNECT считается установленным по умолчанию, то и соответствующие права нам тоже предоставляются. Что тоже совсем не очевидно;
SC_MANAGER_ALL_ACCESS позволяет получить максимальный доступ
Если канал связи с SCM успешно установлен, функция OpenSCManager вернет описатель (handle), предоставляющий доступ к активной базе данных SCM, который мы сохраняем в переменной hSCManager для дальнейшего использования.
Получив доступ к базе SCM, мы регистрируем в ней свой драйвер, с помощью функции CreateService. Функция CreateService создает объект службы и добавляет его в указанную базу данных диспетчера управления службами.
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SC_HANDLE CreateService(
  SC_HANDLE hSCManager,
  LPCTSTR lpServiceName,
  LPCTSTR lpDisplayName,
  DWORD dwDesiredAccess,
  DWORD dwServiceType,
  DWORD dwStartType,
  DWORD dwErrorControl,
  LPCTSTR lpBinaryPathName,
  LPCTSTR lpLoadOrderGroup,
  LPDWORD lpdwTagId,
  LPCTSTR lpDependencies,
  LPCTSTR lpServiceStartName,
  LPCTSTR lpPassword
);
Параметры:
hSCManager
Дескриптор базы данных диспетчера управления службой. Этот дескриптор возвращается функцией OpenSCManager и должен иметь право доступа SC_MANAGER_CREATE_SERVICE. Определяет в какую именно базу мы добавляем сведения о новом драйвере.
lpServiceName
Указатель на строку с завершающим нулем, которая задает устанавливаемое имя службы. Максимальная длина строки ― 256 символов. База данных диспетчера управления службами сохраняет регистр символов, но при сравнении имени службы ― всегда без учета регистра. Прямой слэш (/) и обратный слэш (\) ― неприменяемые символы в имени службы.
lpDisplayName
Указатель на строку с завершающим нулем, которая имеет в своем составе отображаемое имя, которое используется пользовательскими программами интерфейса, чтобы идентифицировать службу. Эта строка имеет максимальную длину 256 символов. Имя сохраняется с учетом регистра в диспетчере управления службами. Сравнения отображаемого имени всегда не чувствительны к регистру.
dwDesiredAccess
Доступ к службе. Перед предоставлением требуемого доступа, система проверяет маркер доступа вызывающего процесса.
Тип Предназначение
SERVICE_ALL_ACCESS позволяет получить максимальный доступ
SERVICE_START доступ на запуск драйвера вызовом функции StartService
SERVICE_STOP доступ на останов драйвера вызовом функции ControlService с параметром SERVICE_CONTROL_STOP
DELETE доступ на удаление сведений о драйвере из базы данных SCM вызовом функции DeleteService
Нам потребуется выполнить всего два действия: запустить драйвер и удалить сведения о нем из базы данных SCM, а следовательно, и из реестра. Поэтому в этом параметре мы передаем комбинацию флагов SERVICE_START и DELETE. Останавливать запущенный драйвер нам не потребуется, так как его инициализация завершится ошибкой.
dwServiceType
Типы службы. Для драйвера может быть только SERVICE_KERNEL_DRIVER (Соответствует параметру Type в реестре)
dwStartType
Варианты запуска службы. Этот параметр может быть SERVICE_DEMAND_START Служба, запускается диспетчером управления службами, когда процесс вызывает функцию StartService. (Соответствует параметру Start в реестре)
dwErrorControl
Серьезность ошибки и предпринимаемое действие, если эта служба не в состоянии запуститься. Этот параметр может быть одним из следующих значений.
Значение Предназначение
SERVICE_ERROR_IGNORE Программа запуска регистрирует ошибку, но продолжает операцию запуска.
SERVICE_ERROR_NORMAL Программа запуска регистрирует ошибку и показывает всплывающее окно сообщения, но продолжает операцию запуска.
SERVICE_ERROR_SEVERE Программа запуска регистрирует ошибку. Если запускается последняя, заведомо без ошибок конфигурация, операция запуска продолжается. Иначе, система перезапускается с последней, заведомо без ошибок конфигурацией.
SERVICE_ERROR_CRITICAL Если возможно, программа запуска регистрирует ошибку . Если запускается последняя, заведомо без ошибок конфигурация, операция запуска завершается ошибкой. Иначе, система перезапускается с последней из известных конфигураций без ошибок.
lpBinaryPathName
Указатель на строку с завершающим нулем, которая имеет в своем составе полный путь доступа к двоичному файлу службы. Если путь имеет в своем составе пробел, он должен быть заключен в кавычки. Соответствует параметру ImagePath в реестре
lpLoadOrderGroup
Указатель на строку с завершающим нулем, именующую группу очередности загрузки, членом которой является эта служба. Задайте значение NULL или пустую строку, если служба не принадлежит группе. Программа запуска использует очередность загрузки групп, чтобы загрузить группы служб в указанном порядке по отношению к другим группам. Список очередности загрузки групп содержатся в следующем значении реестра:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\ServiceGroupOrder
lpdwTagId
Указатель на переменную, которая получает значение признака, являющееся уникальным в группе, заданной в параметре lpLoadOrderGroup. Задайте значение ПУСТО (NULL), если Вы не изменяете существующий признак. Вы можете использовать признак для того, чтобы упорядочить запуск службы в пределах очередности загрузки группы, определяя вектор очередности признака в следующем значении реестра:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\GroupOrderList
Признаки вычисляются только для служб драйвера, которые имеют типы пуска SERVICE_BOOT_START или SERVICE_SYSTEM_START.
lpDependencies
Указатель на массив имен служб, разделенных нулем, с двойным символом нуля в конце или очередности загрузки групп, которую система должна запустить перед этой службой. Задайте значение NULL или пустую строку, если служба не имеет никаких зависимостей. Зависимость от группы означает, что эта служба может запуститься тогда, если по крайней мере один член группы запущен после попытки запустить все члены группы. Вы должны ставить в начале имен группы SC_GROUP_IDENTIFIER так, чтобы они могли отличаться от имени службы, потому что службы и группы служб совместно используют то же самое пространство имен. Если драйвер не зависит от других драйверов, то в этом параметре можно указать NULL или указатель на пустую строку.
lpServiceStartName
Указатель на строку с завершающим нулем, которая задает имя учетной записи, с правами которой будет запущен драйвер. Если тип службы SERVICE_KERNEL_DRIVER, то этот параметр должен содержать имя объекта драйвера, которое используется системой для загрузки. Если используется имя объекта "драйвер" созданное подсистемой ввода-вывода, то этот параметр устанавливается равным NULL.
lpPassword
Указатель на строку с завершающим нулем, которая имеет в своем составе пароль к имени учетной записи, заданному параметром lpServiceStartName. Для служб драйвера пароли игнорируются, поэтому NULL
Вызовом функции GetFullPathName, мы формируем строку с полным путем к файлу драйвера, состоящую из текущего каталога и имени файла драйвера, и передаем ее функции CreateService. CreateService регистрирует в базе данных SCM новый драйвер, и заполняет соответствующий подраздел реестра.
Запуск драйвера осуществляется функцией StartService
C++
1
2
3
4
5
BOOL StartService(
  SC_HANDLE hService,
  DWORD dwNumServiceArgs,
  LPCTSTR* lpServiceArgVectors
);
Параметры:
hService
Дескриптор службы. Этот дескриптор возвращается функцией OpenService или CreateService, и он должен иметь право доступа SERVICE_START.
dwNumServiceArgs
Число строк в массиве lpServiceArgVectors. Если lpServiceArgVectors имеет значение NULL, этот параметр может быть нулем. Для драйверов это всегда так.
lpServiceArgVectors
Указатель на массив указателей на строки с завершающим нулем, который передается службе как параметры. Службы драйвера не получают эти параметры, поэтому мы устанавливаем этот параметр в NULL.
Функция StartService заставляет систему произвести действия, очень сильно напоминающие загрузку обыкновенной DLL. Образ файла драйвера проецируется на системное адресное пространство. При этом, возможности управлять адресом загрузки нет никакой. Да это и не нужно. Предопределенный адрес загрузки (preferred base address) у всех наших драйверов будет равен 10000h, что значительно ниже начала системного диапазона адресов. Пытаться установить его в какое-то другое значение не имеет смысла, так как система, все равно, будет загружать драйвер по случайному (для нас) адресу. Поскольку фактический адрес загрузки не совпадает с предопределенным, система производит настройку адресов пользуясь таблицей перемещений (relocation table), находящейся в секции .reloc файла драйвера. Затем производится связывание (fix-up) импорта. Кстати, импорт в файле драйвера раскинут в секции INIT и .idata. В .idata находится таблица адресов импорта (import address table, IAT). В ней содержатся адреса функций во внешних модулях. Она нужна драйверу постоянно. А в секции INIT содержится остальная часть импорта, необходимая только на этапе загрузки (имена внешних модулей и имена импортируемых функций), после которой, память занимаемая этой секцией освобождается. Когда образ драйвера подготовлен, управление передается на точку входа (entry point), которая находится в процедуре DriverEntry. Принципиальная разница, не считая уровня привилегий, в том, что код процедуры DriverEntry всегда выполняется одним из потоков процесса System, и, естественно, в адресном контексте этого процесса.
Вызов StartService синхронный. Это значит, что она не вернет управление до тех пор, пока не отработает процедура DriverEntry в драйвере. Если инициализация драйвера прошла успешно, DriverEntry должна вернуть STATUS_SUCCESS, а функция StartService вернет значение отличное от нуля. И мы вновь окажемся в контексте потока вызвавшего StartService, то есть в контексте нашей SCP.
Вызов StartService может завершиться неудачей, если база данных SCM заблокирована. Последующий вызов функции GetLastError вернет ERROR_SERVICE_DATABASE_LOCKED. Как написано в документации, в этом случае, следует подождать несколько секунд, и повторить попытку, но мы этого делать не будем, так как такая ситуация крайне маловероятна. И вообще, в данном случае, нас не интересует возвращаемое функцией StartService значение, так как драйвер уже проиграл свою мелодию и вернул код ошибки. То есть мы заранее знаем, что вызов StartService даст ошибку.

Осталось привести систему в исходное состояние. Вызовом функции DeleteService мы удаляем сведения о драйвере из базы данных SCM и из реестра. Странно, но передавать описатель самой базы данных SCM в функцию DeleteService не нужно.
Функция DeleteService отмечает указанную службу для удаления из базы данных диспетчера управления службами.
C++
1
2
3
BOOL DeleteService(
  SC_HANDLE hService
);
Параметр:
hService
Дескриптор службы. Этот дескриптор возвращается функцией OpenService или CreateService и он должен иметь право доступа DELETE.
На самом деле, функция DeleteService ничего ниоткуда не удаляет. Она только сообщает системе, что это можно сделать, когда наступит благоприятный момент. А он наступит тогда, когда все описатели службы будут закрыты. Так как мы все еще держим описатель hService открытым, то удаления не происходит. Если попытаться вызвать DeleteService повторно, то он завершится неудачей, а последующий вызов функции GetLastError вернет ERROR_SERVICE_MARKED_FOR_DELETE.

Вызовом функции CloseServiceHandle мы закрываем описатель диспетчера управления службами hService.
C++
1
2
3
BOOL CloseServiceHandle( 
  SC_HANDLE hSCObject 
);
Параметр:
hSCObject
Дескриптор объекта диспетчера управления службами или объекта службы, который закрывается. Дескрипторы объектов менеджера управления службами возвращаются функцией OpenSCManager, а дескрипторы объектов служб возвращаются или функцией OpenService или функцией CreateService.
Поскольку больше открытых описателей службы нет, то именно в этот момент система приводит базу данных SCM в исходное состояние. Второй вызов CloseServiceHandle закрывает описатель самого SCM.
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
; masm windows gui #
.686P
.model flat
include windows.inc
 
includelib kernel32.lib
includelib user32.lib
includelib advapi32.lib
 
extern _imp__ExitProcess@4:dword 
extern _imp__GetFullPathNameA@16:dword
extern _imp__MessageBoxA@16:dword
extern _imp__CloseServiceHandle@4:dword
extern _imp__DeleteService@4:dword
extern _imp__StartServiceA@12:dword
extern _imp__CreateServiceA@52:dword
extern _imp__OpenSCManagerA@12:dword
.code
 
start proc
 
local hSCManager:HANDLE
local acDriverPath[MAX_PATH]:CHAR
 
        xchg eax,ebx
    xor esi,esi;тип ошибки равен 0
    mov edi,offset scp00_sys_name
    ; Open a handle to the SC Manager database
    push SC_MANAGER_CREATE_SERVICE;определяем нужный тип доступа
    push ebx;адрес имени базы данных сервисов. Для открытия базы 
;по умолчанию равно NULL 
    push ebx;имя (адрес имени) рабочей станции в сети, на которой хотят 
;открыть базу. Для локального компьютера равна NULL 
    call _imp__OpenSCManagerA@12;открываем базу сервисов 
    xchg eax,ecx
    jecxz err;if eax != NULL выводим сообщение об ошибке (тип ошибки равен 0)
    inc esi;тип ошибки равен 1
    mov hSCManager,ecx;при успешном выполнении возвращает дескриптор базы данных
    push eax
    push esp
    lea eax,acDriverPath
    push eax
    push MAX_PATH
    push edi;offset scp1_sys_name
    call _imp__GetFullPathNameA@16
        pop eax
    mov [edi+5],ebx
    ; Register driver in SCM active database
    push ebx;пароль учетной записи. NULL нет пароля
    push ebx;имя учетной записи, с которой должна запускаться служба. 
;NULL предполагает, что служба запускается под именем LocalSystem
    push ebx;сервисы и группы сервисов от которых зависит наш сервис NULL 
    push ebx;NULL 
    push ebx;порядок загрузки групп служб. В данном случае порядок не важен (NULL) 
    lea ecx,acDriverPath 
    push ecx;строка содержащая имя и полный путь к программе-сервису
    push ebx;SERVICE_ERROR_IGNORE=0 уровень реакции на ошибку
    push SERVICE_DEMAND_START;тип старта службы (здесь "запуск по требовнию")
    push SERVICE_KERNEL_DRIVER;тип сервиса "драйвер режима ядра"
    push SERVICE_START + DELETE;возможный тип доступа к сервису
    push edi;"scp00" параметр определяет отображаемое имя.
    push edi;"scp00" адрес строки, содержащей имя одной из логических служб, 
;по которому в дальнейшем будет возможно обращение к этой службе.
    push hSCManager;дескриптор сервисной базы данных
    call _imp__CreateServiceA@52;помещаем сервис в сервисную базу
    test eax,eax;if eax == NULL выводим сообщение об ошибке=1
    jne short a1
err:    push MB_ICONSTOP        
    push ebx;NULL
    push handle[esi*4]
    push ebx;NULL
    call _imp__MessageBoxA@16;выводим тип ошибки
    jmp short a2;выходим из программы
a1: push eax;hService для CloseServiceHandle
    push eax;hService для DeleteService
    push ebx;параметры передаваемые в службу, обычно NULL
    push ebx;параметры передаваемые в службу, обычно 0 
    push eax;hService дескриптор возвращенный функцией CreateService
    call _imp__StartServiceA@12;программный запуск зарегистрированного сервиса
    ; Here driver scp00.sys plays melody
    ;and reports error to be removed from memory
    ;Remove driver from SCM database
    call _imp__DeleteService@4;удаляем сервис
    call _imp__CloseServiceHandle@4;закрываем базу сервисов
    push hSCManager
    call _imp__CloseServiceHandle@4;закрываем базу сервисов
a2: push ebx;0
    call _imp__ExitProcess@4
 
start endp
scp00_sys_name db "scp00.sys",0
handle dd can_t_connect,can_t_register
can_t_connect db "Can't connect to Service Control Manager.",0
can_t_register db "Can't register driver.",0
end start
Второй вариант user-mode приложения, которое запускает драйвер scp00.sys
Предварительно прописываем драйвер scp00.sys в реестре «вручную» (используем функции RegOpenKey, RegCreateKey, RegSetValue) и загружаем драйвер scp00.sys с помощью функции ZwLoadDriver. В реестре создается минимум необходимых записей, запускаем драйвер, выгружаем драйвер функцией ZwUnloadDriver и удаляем его раздел из реестра (используем функции RegCloseKey, SHDeleteKey).
Этот способ позволяет запускать драйвер быстро и незаметно и подходит для маленьких программ не требующих установки, но требующих запуска своего драйвера.
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
; masm windows gui #
.686P
.model flat
include windows.inc
 
includelib kernel32.lib
includelib advapi32.lib
includelib ntdll.lib
includelib shlwapi.lib
 
extern _imp__ExitProcess@4:dword 
extern _imp__GetFullPathNameA@16:dword
extern _imp__RegOpenKeyA@12:dword
extern _imp__RegCreateKeyA@12:dword
extern _imp__RegSetValueExA@24:dword
extern _imp__RegCloseKey@4:dword
extern _imp__SHDeleteKeyA@8:dword
extern _imp__ZwLoadDriver@4:dword
extern _imp__ZwUnloadDriver@4:dword
;--------macros-------------------
du  macro string
    irpc c,<string>
    if '&c'gt 127
    db ('&c'- 0B0h),4
    else
    dw '&c'
    endif
    endm
    dw 0
    endm
.const
align 4
us: du <\registry\machine\SYSTEM\CurrentControlSet\Services\scp00>
len_us = $-us
align 4
cusDevice dw (len_us - 2)
          dw (len_us)
      dd us
.code
 
start proc
local Key2:HKEY
local Key:HKEY
local acDriverPath[MAX_PATH]:CHAR
 
        xchg eax,ebx
    mov esi,offset scp00_sys_name
    lea edi,acDriverPath
    mov eax,'\??\'
    stosd;путь к драйверу должен начаться с '\??\'
    push eax;резервирую место в стеке
    push esp;указатель на пустое место в стеке
    push edi
    sub edi,4
    push MAX_PATH
    push esi;offset scp1_sys_name
    call _imp__GetFullPathNameA@16
;GetFullPathName(scp00_sys_name, MAX_PATH, PChar(dword(@Image) + 4), Pth);
    add eax,4
    push eax;длина полного пути для RegSetValueEx(Key2,"ImagePath",0,
;REG_SZ,&acDriverPath,lenth(acDriverPath))
    lea eax,Key
    push eax
    push offset aSystem
    push HKEY_LOCAL_MACHINE
    call _imp__RegOpenKeyA@12
    mov [esi+5],ebx; из "scp00.sys" делаем "scp00"
    lea eax,Key2
    push eax
    push esi
    push Key
    call _imp__RegCreateKeyA@12
    push edi;&acDriverPath
    push REG_SZ
    push ebx;0
    push offset aImagePath
    push Key2
    call _imp__RegSetValueExA@24;RegSetValueEx(Key2,"ImagePath",0,
;REG_SZ,&acDriverPath,lenth(acDriverPath))
    mov eax,esp;указатель на пустое место в стеке
        push sizeof(dword)
    mov dword ptr [eax],1;в пустое место в стеке поместим переменную dType=1
    push eax;&dType
    push REG_DWORD;тип переменной dType
    push ebx;0
    push offset aType;название переменной dType
    push Key2
    call _imp__RegSetValueExA@24
;RegSetValueEx(Key2,"Type",0,REG_DWORD,&dType)
    push Key2
    call _imp__RegCloseKey@4
    mov [esp],offset cusDevice
    call _imp__ZwLoadDriver@4; выравниваем стек после GetFullPathNameA
    push offset cusDevice
    call _imp__ZwUnloadDriver@4
    push esi 
    push Key
    call _imp__SHDeleteKeyA@8;удаляем непустую строку из реестра 
    push Key
    call _imp__RegCloseKey@4
    push ebx;0
    call _imp__ExitProcess@4
start endp
aSystem db 'SYSTEM\CurrentControlSet\Services',0
scp00_sys_name db "scp00.sys",0
aType   db "Type",0
aImagePath db "ImagePath",0
end start
Третий вариант user-mode приложения, которое запускает драйвер scp00.sys

Собственно это модифицированный второй вариант. Произошла замена функций из advapi32.dll и других динамических библиотек на Zw-функции из ntdll.dll, а далее замена Zw-функций на вызов 2Eh прерывания, поэтому за исключением функции RtlGetFullPathName_U наша программа не использует импорт
DLLисходная функцияфункция из ntdll.dllномер функции в SDT для Windows XPНазначение Zw-функций
kernel32 GetFullPathName RtlGetFullPathName_U 
advapi32RegOpenKey ZwOpenKey119открывает доступ к существующему подразделу реестра или создает новый. Возвращает дескриптор открытого объекта.
 RegCreateKeyZwCreateKey41открывает доступ к существующему подразделу реестра или создает новый. Возвращает дескриптор открытого объекта.
 RegSetValueExZwSetValueKey 247создает или изменяет значение параметра в открытом подразделе реестра. Для возможности применения этой функции, дескриптор подраздела при открытии должен быть получен с применением маски DesiredAccess, содержащей флаг KEY_SET_VALUE
 RegCloseKeyZwClose 25закрывает дескриптор открытого ранее подраздела реестра, фиксирует произведенные изменения на жестком диске
shlwapiSHDeleteKey ZwDeleteKey63удаляет открытый подраздел из реестра
ntdllZwLoadDriverZwLoadDriver97
 ZwUnloadDriver ZwUnloadDriver262
Таблица #7:
вызовом функции ZwOpenKey открываем существующий раздел, запрашивая необходимые в данный момент права доступа
вызовом функции ZwCreateKey, создаем новый подраздел «scp00» в ветке «HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services»

После успешного вызова ZwCreateKey по значению переменной dwDisposition можно определить, был ли создан новый подраздел (REG_CREATED_NEW_KEY) или такой подраздел уже существовал в реестре (REG_OPENED_EXISTING_KEY) и поэтому был открыт

При помощи ZwSetValueKey создадим в нашем подразделе:
  1. unicode-строковый параметр с именем «ImagePath». Строка содержит путь к исполняемому файлу драйвера или службы. В отличие от служб, для драйверов не обязательно указывать значение этого параметра, но тогда файл драйвера должен находиться в каталоге «\%SystemRoot%\System32\Drivers». Полный путь к нашему драйверу, начинающийся с символов «\??\» содержится в edi. Длину полного пути нам вернула функция RtlGetFullPathName_U.
  2. также создаем параметр с именем «Type», определяющим тип службы, типом параметра REG_DWORD и значением SERVICE_KERNEL_DRIVER (=1).
Тип параметра Описание
REG_NONE Нетипизированный параметр
REG_SZ Unicode-строка фиксированной длины с нулём в конце
REG_EXPAND_SZ Unicode-строка переменной длины с нулём в конце; может включать переменные окружения
REG_BINARY Двоичные данные произвольной длины
REG_DWORD 32-битное число
REG_DWORD_LITTLE_ENDIAN 32-битное число, в котором первым является младший байт, эквивалентно REG_DWORD
REG_DWORD_BIG_ENDIAN 32-битное число, в котором первым является старший байт
REG_LINK Символьная строка в формате Unicode
REG_MULTI_SZ Массив Unicode-строк с завершающим нулём
REG_RESOURCE_LIST Описание аппаратного ресурса
REG_FULL_RESOURCE_DESCRIPTOR Описание аппаратного ресурса
REG_RESOURCE_REQUIREMENTS_LIST Список требований к ресурсам
Таблица #8: Типы параметров реестра
После проигрыша мелодии удаляем подраздел реестра вызовом ZwDeleteKey

при использовании sysenter вместо Zw-функций размер файла 789 байт, при использовании call ds:[7FFE0300h] ― размер файла 762 байта, при использовании int 2Eh ― размер 699 байт
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
.686P
.model tiny
include windows.inc
;for WinXP - 699 bytes
exebase     equ 400000h
OBJ_CASE_INSENSITIVE    equ 40h
SERVICE_KERNEL_DRIVER   equ 01h
du  macro string
    irpc c,<string>
    if '&c'gt 127
    db ('&c'- 0B0h),4
    else
    dw '&c'
    endif
    endm
    dw 0
    endm
 
UNICODE_STRING STRUCT
    _Length     WORD    ?; len of string in bytes (not chars)
    MaximumLength   WORD    ?; len of Buffer in bytes (not chars)
    Buffer      PWSTR   ?; pointer to string
UNICODE_STRING ENDS
 
PUNICODE_STRING typedef PTR UNICODE_STRING
 
OBJECT_ATTRIBUTES STRUCT        ; sizeof = 18h
    _Length             DWORD       ? ; original name Length
    RootDirectory           HANDLE      ?
    ObjectName          PUNICODE_STRING ?
    Attributes          DWORD       ?
    SecurityDescriptor      PVOID       ? ; Points to type SECURITY_DESCRIPTOR
    SecurityQualityOfService    PVOID       ? ; Points to type SECURITY_QUALITY_OF_SERVICE
OBJECT_ATTRIBUTES ENDS
 
.code
 
main:
include capito.asm
align 4
us: du <\registry\machine\SYSTEM\CurrentControlSet\Services\scp00.sys>
len_us = $-us
align 4
cusDevice dw len_us - 10
          dw len_us - 8
      dd us+exebase
pusSystem dw len_us-58; du <\SYSTEM\CurrentControlSet\Services>
      dw len_us-56
      dd us+exebase+36
pusScp00  dw len_us-114; du <scp00>
      dw len_us-112
      dd us+exebase+104
align 4
aImagePath: du <ImagePath>
a2:
align 4
pusImagePath    dw a2-aImagePath-2
        dw a2-aImagePath
        dd aImagePath+exebase
align 4
aType:  du <Type>
a3:
align 4
pusType     dw a3-aType-2
        dw a3-aType
        dd aType+exebase 
start: 
Key2        equ dword ptr [ebp-4]
Key     equ dword ptr [ebp-8]
dwDisposition   equ dword ptr [ebp-12]
acDriverPath    equ dword ptr [ebp-MAX_PATH-12]
oa      equ dword ptr [ebp-MAX_PATH-12-sizeof(OBJECT_ATTRIBUTES)]
    enter MAX_PATH+12+sizeof(OBJECT_ATTRIBUTES),0
        xchg eax,ebx
    lea edi,acDriverPath
    mov eax,3F005Ch;unicode '\?'
    stosd
    ror eax,10h
        stosd
    invoke RtlGetFullPathName_U,offset us+exebase+104,MAX_PATH,edi,esp,eax
    sub edi,8;путь к драйверу должен начаться с '\??\'
    add eax,10
    push eax;длина полного пути для ZwSetValueKey
;Для последующего вызова функции ZwOpenKey нам потребуется указатель на 
;заполненную структуру OBJECT_ATTRIBUTES
        lea ecx,oa
    assume ecx: ptr OBJECT_ATTRIBUTES 
;InitializeObjectAttributes
        mov [ecx]._Length,sizeof(OBJECT_ATTRIBUTES)
    mov [ecx].RootDirectory,ebx
    mov [ecx].ObjectName,offset pusSystem+exebase
    mov [ecx].Attributes,OBJ_CASE_INSENSITIVE
    mov [ecx].SecurityDescriptor,ebx
    mov [ecx].SecurityQualityOfService,ebx
        assume ecx: nothing
        lea eax,Key  ; Адрес Key
    push ecx;POBJECT_ATTRIBUTES  ObjectAttributes
    push KEY_READ;ACCESS_MASK  DesiredAccess
    push eax;PHANDLE  KeyHandle
    mov eax,119
    mov edx,esp
    int 2Eh;ZwOpenKey(&Key,2000000h,&oa)
    lea ecx,oa;ObjectAttributes
    mov (OBJECT_ATTRIBUTES ptr [ecx]).ObjectName,offset pusScp00+exebase
    lea eax,dwDisposition
    push eax;PULONG  Disposition  OPTIONAL
    push ebx;ULONG  CreateOptions=REG_OPTION_NON_VOLATILE
    push ebx;PUNICODE_STRING  Class  OPTIONAL
    push ebx;ULONG  TitleIndex
    push ecx;POBJECT_ATTRIBUTES  ObjectAttributes
    push KEY_READ;ACCESS_MASK  DesiredAccess
    lea eax,Key2
    push eax;PHANDLE  KeyHandle
    mov eax,41
    mov edx,esp
    int 2Eh;ZwCreateKey
    add esp,28+12
    push edi;PVOID  Data
    push REG_SZ;ULONG  Type
    push ebx;ULONG  TitleIndex  OPTIONAL
    push offset pusImagePath+exebase;PUNICODE_STRING  ValueName
    push Key2;HANDLE  KeyHandle
    mov eax,247
    mov edx,esp 
    int 2Eh;ZwSetValueKey(Key2,&pusImagePath,0,REG_SZ,edi)
    add esp,24
    mov eax,esp;указатель на пустое место в стеке
    mov dword ptr [eax],SERVICE_KERNEL_DRIVER;в пустое место в стеке поместим переменную dType=1
    push sizeof(dword);ULONG  DataSize
    push eax;PVOID  Data
    push REG_DWORD;ULONG  Type
    push ebx;ULONG  TitleIndex  OPTIONAL
    push offset pusType+exebase;PUNICODE_STRING  ValueName
    push Key2;HANDLE  KeyHandle
    mov eax,247
    mov edx,esp 
    int 2Eh;ZwSetValueKey(Key2,&pusType,0,REG_DWORD,eax,sizeof(dword))
    push Key2;Handle
    mov eax,25
    mov edx,esp 
    int 2Eh;ZwClose(Key2)
    mov edi,offset cusDevice+exebase
    push edi
        mov eax,97
    mov edx,esp 
    int 2Eh;ZwLoadDriver(&cusDevice)
    push edi
        mov eax,262
    mov edx,esp 
    int 2Eh;ZwUnloadDriver(&cusDevice)
    push Key2;Handle
    mov eax,63
    mov edx,esp 
    int 2Eh;ZwDeleteKey(Key2)
    push Key;Handle
    mov eax,25
    mov edx,esp 
    int 2Eh;ZwClose(Key)
    leave
    retn;ExitProcess
import:
dd 0,0,0,ntdll_dll,ntdll_table
dd 0,0
ntdll_table:
RtlGetFullPathName_U    dd _RtlGetFullPathName_U
            dw 0
_RtlGetFullPathName_U   db 0,0,"RtlGetFullPathName_U",0
ntdll_dll       db "ntdll"
end_import:
end main
Четвертый вариант user-mode приложения, которое запускает драйвер scp00.sys

Используя функцию ZwSetSystemInformation с параметром SystemLoadAndCalllmage можно за одно действие загрузить и запустить драйвер в системе Windows NT. При этом не требуется никакой регистрации драйвера. Однако возникнет «побочный эффект» ― после такой загрузки драйвер невозможно выгрузить «Обычный» (написанный по всем правилам драйвер) будет находиться в памяти до следующей перезагрузки компьютера. Но наш-то драйвер после выполнения возвратит системе STATUS_DEVICE_CONFIGURATION_ERROR (код фиктивной ошибки) и благополучно будет «самовыпилен» (удален системой из памяти) .

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

8-байтовая локальная переменная GregsImage представляет из себя структуру UNICODE_STRING используемую для работы с UNICODE-строками в нулевом кольце

Код
UNICODE_STRING STRUCT
	_Length		WORD	?; len of string in bytes (not chars)
	MaximumLength	WORD	?; len of Buffer in bytes (not chars)
	Buffer		PWSTR	?; pointer to string
UNICODE_STRING ENDS
Поле _Length содержит текущую длину строки в байтах, не считая двух завершающих нулей. Поле MaximumLength содержит максимальный размер буфера в байтах, в котором эта строка присутствует (MaximumLength = _Length + 2). Поле Buffer содержит указатель на буфер, где находится UNICODE-строка.

Assembler
1
2
3
4
5
    call _imp__RtlGetFullPathName_U@16
    imul eax,10001h
    add eax,2
        mov edi,esp;edi=&GregsImage
    mov [edi],eax
Для вычисления длины строки используем функцию RtlGetFullPathName умножив возвращенное значение на 10001h и добавив 2 мы получили значения для GregsImage._Length и GregsImage.MaximumLength
Assembler
1
2
        lea edi,daPath
    mov GregsImage.Buffer,edi
Помещаем в поле GregsImage.Buffer указатель на UNICODE-строку.
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
; masm windows gui #
.686P
.model flat
include windows.inc
 
includelib kernel32.lib
includelib ntdll.lib
 
extern _imp__ExitProcess@4:dword 
extern _imp__RtlGetFullPathName_U@16:dword
extern _imp__ZwSetSystemInformation@12:dword
;----------const------------------
SystemLoadAndCallImage equ 26h
;--------macros-------------------
du  macro string
    irpc c,<string>
    if '&c'gt 127
    db ('&c'- 0B0h),4
    else
    dw '&c'
    endif
    endm
    dw 0
    endm
;--------struct-------------------
UNICODE_STRING STRUCT
    _Length     WORD    ?; len of string in bytes (not chars)
    MaximumLength   WORD    ?; len of Buffer in bytes (not chars)
    Buffer      PWSTR   ?; pointer to string
UNICODE_STRING ENDS
;---------------------------------
.code
start proc
local daPath[MAX_PATH]:CHAR
local GregsImage:UNICODE_STRING
 
        lea edi,daPath
    mov GregsImage.Buffer,edi
    mov eax,3F005Ch;eax='\',0,'?',0
    stosd;путь к драйверу должен начаться с '\??\'
    ror eax,16;eax='?',0,'\',0
    stosd
    push eax;резервирую место в стеке
    push esp;указатель на пустое место в стеке
    push edi
    push MAX_PATH
    push offset scp00_sys_name
    call _imp__RtlGetFullPathName_U@16
;GetFullPathName(scp00_sys_name, MAX_PATH, PChar(dword(@Image) + 4), Pth);
    pop ecx
    add eax,8;учтем, что путь стал длиннее на '\??\'
    imul eax,10001h
    add eax,2
    mov edi,esp;edi=&GregsImage
    mov [edi],eax
    push sizeof UNICODE_STRING;8
    push edi;&GregsImage
    push SystemLoadAndCallImage;=26h
    call _imp__ZwSetSystemInformation@12
    push 0
    call _imp__ExitProcess@4
start endp
scp00_sys_name: du <scp00.sys>
end start
_________________________________________________________________

Для написания данной главы использовались работы следующих авторов:

Программирование и устройство таймера:
  • Лю Ю-Чжен, Гибсон Г. Микропроцессоры семейства 8086/8088. Архитектура, программирование и проектирование микрокомпьютерных систем: Пер. с англ. ― М.: Радио и связь, 1987. ― 512 с.; ил.
    Глава 9. Интерфейсы ввода-вывода. Программируемый интервальный таймер.
  • Юров В.И. Assembler. Учебник для вузов 2-е изд. ― СПб.: Питер, 2007. ― 637 с.: ил.
    Глава 7. Команды обмена данными. Ввод из порта и вывод в порт.
Загрузка драйвера с помощью функций Service Control Manager'a и загрузка с помощью функции ZwLoadDriver:
  • KmdTutRu.chm "Драйверы режима ядра" by Four-F главы:
    1. Установка канала связи с SCM
    2. Регистрация драйвера
    3. Запуск драйвера
Загрузка драйвера через ZwSetSystemInformation
  • Драйвер m1gB0t by Greg Hoglund, 2004, исходный текст m1gloader
  • Грег Хогланд, Гари Мак-Гроу. Взлом программного обеспечения: анализ и использование кода.: Пер. с англ. ― М.: Издательский дом "Вильямс", 2005. ― 400 с.: ил. ― Парал. тит. англ.
    Глава 8. Наборы средств для взлома. Текст программы для загрузки драйвера c:\_root_.sys
_________________________________________________________________
© Mikl___ 2011
23
Vadimych
635 / 478 / 12
Регистрация: 10.01.2011
Сообщений: 1,047
10.10.2012, 19:31 #5
Mikl___, попробовал в windows 7x32 загрузить драйвер с помощью ZwSetSystemInformation. Возвращает 0xC0000061. Не помогает и полученная SE_LOAD_DRIVER_PRIVILEGE.
0
Mikl___
Автор FAQ
11029 / 5803 / 513
Регистрация: 11.11.2010
Сообщений: 10,814
11.10.2012, 03:24 #6
Vadimych, там если внимательно читать, то есть фраза
Цитата Сообщение от Mikl___ Посмотреть сообщение
здесь должна была быть статья с рабочим названием «Доступ к портам ввода/вывода под Windows XP».
Под семеркой через ZwSetSystemInformation загрузка драйвера не пошла, а вот загрузка через ZwLoadDriver работает, сейчас разбираюсь с упрощением загрузки через inf-файлы
0
Vadimych
635 / 478 / 12
Регистрация: 10.01.2011
Сообщений: 1,047
11.10.2012, 05:00 #7
Цитата Сообщение от Mikl___ Посмотреть сообщение
Vadimych, там если внимательно читать, то есть фраза
Да я без претензий, просто констатировал факт.
0
Mikl___
Автор FAQ
11029 / 5803 / 513
Регистрация: 11.11.2010
Сообщений: 10,814
12.10.2012, 04:22 #8
Доступ к командам In/Out через драйвер режима ядра

команды читающие или пишущие в порт ввода/вывода могут быть расположены в «теле» user-mode приложения, но чтобы они выполнились, необходимо оформить этот фрагмент как процедуру и на исполнение ее запустить из kernel-mode драйвера. При этом в этой процедуре не должны встречаться WinAPI функции, используемые в user-mode, иначе BSOD обеспечен. Адрес процедуры в драйвер можно передать:
  • через реестр,
  • через WriteFile "\\.\driver"
  • или через DeviceIoControl.
Переделываю драйвер <R>ing-<0> <P>rocedure <C>all & Direct Port I/O (r0pc.sys) by @L.chemist (Andrey A. Meshkov). Драйвер scp01 передает управление на фрагмент кода из scp01-00.exe в котором содержится команда outsb, синхронизация производится через предварительный подсчет тиков. Адрес процедуры musik передается через DeviceIoControl. Полнофункциональный драйвер.

Текст драйвера scp01.sys


Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
; masm windows native #
;написано на основе драйвера режима ядра <R>ing-<0> <P>rocedure 
;<C>all & Direct Port I/O (r0pc.sys) by @L.chemist (Andrey A. Meshkov)
.686p
.model flat
include ntstatus.inc
include ntddk.inc
include Strings.mac
includelib ntoskrnl.lib
; --------------------------------------------------------------------------------
extern _imp__IoCreateDevice:dword
extern _imp__IoCreateSymbolicLink:dword
extern _imp__IoDeleteDevice:dword
extern _imp__IoDeleteSymbolicLink:dword
extern _imp__IofCompleteRequest:dword
 
DRIVER_QUERY_PROC_NOARGS    = 10h
; --------------------------------------------------------------------------------
; structure for driver query
DriverQuery struct 
  iocode dd ? ; user I/O code
  wparam dd ? ; parameter
  lparam dd ? ; parameter
DriverQuery ends
PDriverQuery equ dd
; --------------------------------------------------------------------------------
.const
CCOUNTED_UNICODE_STRING "\\Device\\scp01", cusDevice, 4
CCOUNTED_UNICODE_STRING "\\DosDevices\\scp01", cusSymbolicLink, 4
 
.code
; Процедура входа драйвера. Эта процедура вызывается только раз после загрузки
; драйвера в память. Она выделяет необходимые ресурсы для работы драйвера. В
; нашем случае
DriverEntry proc lpDriverObject:PDRIVER_OBJECT, lpusRegistryPath:PUNICODE_STRING
local deviceObject:PDEVICE_OBJECT
local status:NTSTATUS
; инициализируем драйвер устройства и объект устройства (Device Object)
    lea eax,deviceObject
    push eax;&deviceObject
    push 0
    push 0
    push FILE_DEVICE_UNKNOWN;22h
    push offset cusDevice
    push sizeof(DriverQuery);0Ch
    push lpDriverObject
    call _imp__IoCreateDevice
    test eax,eax;cmp eax,STATUS_SUCCESS; 0
    jnz short exit; break on error
; create symbolic link to the user-visible name
; создаем символическую ссылку на драйвер устройства, что позволяет user-mode
; приложению получить доступ к нашему драйверу, используя "\\.\scp01" нотацию
    push offset cusDevice
    push offset cusSymbolicLink
    call _imp__IoCreateSymbolicLink
        mov status,eax; save status                
    test eax,eax;cmp eax,STATUS_SUCCESS; check result
    jz short success                
    push deviceObject
    call _imp__IoDeleteDevice; delete device object if not successful
    jmp short exit
success:    ; continue on success
; load structure to point to IRP handlers
; инициализируем точки входа драйвера в объект драйвера
; всё, что нам нужно, это операция создания (Create), управления (Control) 
; и выгрузки (Unload)
    mov eax,lpDriverObject
    mov (DRIVER_OBJECT ptr [eax]).DriverUnload,offset DriverUnload
    mov (DRIVER_OBJECT ptr [eax]).MajorFunction[IRP_MJ_CREATE*4],offset DispatchCreate
    mov (DRIVER_OBJECT ptr [eax]).MajorFunction[IRP_MJ_DEVICE_CONTROL*4],offset DispatchControl                
    mov eax,status; assign result
exit:   leave
    retn 8
DriverEntry endp
;------------------------------------------------------
;освобождаем все выделенные ранее объекты
DriverUnload:
lpDriverObject  equ dword ptr [esp+4];:PDRIVER_OBJECT
; delete symbolic link to the user-visible name
    push offset cusSymbolicLink
    call _imp__IoDeleteSymbolicLink
; delete device object
    mov ecx,lpDriverObject
    push dword ptr (DRIVER_OBJECT ptr [ecx]).DeviceObject
    call _imp__IoDeleteDevice
    retn 4
;--------------------------------------------------
DispatchCreate:
lIrp equ dword ptr [esp+8]
    mov ecx,lIrp
    and (_IRP ptr [ecx]).IoStatus.Status,STATUS_SUCCESS;0
    and (_IRP ptr [ecx]).IoStatus.Information,0
    xor edx,edx;edx = IO_NO_INCREMENT
    call _imp__IofCompleteRequest;IofCompleteRequest (lpIrp, IO_NO_INCREMENT)
    xor eax,eax;mov eax,STATUS_SUCCESS; 0
    retn 8
;---------------------------------------------------------
DispatchControl proc pDeviceObject:PDRIVER_OBJECT, lpIrp:PIRP 
local status:NTSTATUS
 
    push edi
    mov status,STATUS_UNSUCCESSFUL; 0C0000001h
    mov edi,lpIrp
    assume edi: ptr _IRP
    and [edi].IoStatus.Information,0;
    mov eax,[edi].Tail.Overlay.CurrentStackLocation
    cmp (IO_STACK_LOCATION ptr [eax]).Parameters.DeviceIoControl.InputBufferLength,4
    jne @f
        mov status,STATUS_NOT_IMPLEMENTED; 0C0000002h
    cmp (IO_STACK_LOCATION ptr [eax]).Parameters.DeviceIoControl.IoControlCode,DRIVER_QUERY_PROC_NOARGS
    jne @f
    mov eax,[edi].AssociatedIrp.SystemBuffer;ioBuffer = pIrp->AssociatedIrp.SystemBuffer
    call dword ptr [eax]
    and status,STATUS_SUCCESS;status = 0
@@: push status
    pop [edi].IoStatus.Status
    assume edi:nothing
    mov ecx,edi
    xor edx,edx;edx = IO_NO_INCREMENT
    call _imp__IofCompleteRequest;IofCompleteRequest (lpIrp, IO_NO_INCREMENT)
    mov eax,status
    pop edi
    leave
    retn 8
DispatchControl endp
;----------------------------------------------------
end DriverEntry
Первый вариант user-mode приложения, которое запускает драйвер scp01.sys


user-mode приложение, которое запускает scp01.sys драйвер, используя API-функции Service Control Manager'a: OpenSCManager, CreateService, StartService, CloseServiceHandle и DeleteService.
Этот способ очень прост и хорошо документирован, он подходит для постоянной установки драйверов.

Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
; masm windows gui #
.686P
.model flat
include windows.inc
 
includelib kernel32.lib
includelib user32.lib
includelib advapi32.lib
 
extern _imp__ExitProcess@4:dword 
extern _imp__GetFullPathNameA@16:dword
extern _imp__MessageBoxA@16:dword
extern _imp__CloseServiceHandle@4:dword
extern _imp__DeleteService@4:dword
extern _imp__StartServiceA@12:dword
extern _imp__CreateServiceA@52:dword
extern _imp__OpenSCManagerA@12:dword
extern _imp__Sleep@4:dword
extern _imp__OpenServiceA@12:dword
extern _imp__QueryServiceStatus@8:dword
extern _imp__CreateFileA@28:dword
extern _imp__DeviceIoControl@32:dword
extern _imp__CloseHandle@4:dword
extern _imp__ControlService@12:dword
 
SERVICE_ERROR_NORMAL        equ 1
MAX_PATH            equ 260
DRIVER_QUERY_PROC_NOARGS    equ 10h
 
.code
 
start proc
local DrvFile:dword
local Driver:HANDLE
local Service:HANDLE
local Manager:HANDLE
local acDriverPath[MAX_PATH]:CHAR
        xor esi,esi
    xor ebx,ebx
    rdtsc; замеряем скольким тикам соответствует 40 мСек
        mov TimerLo,eax
        mov TimerHi,edx
    push 40
    call _imp__Sleep@4
    rdtsc
        sub eax,TimerLo
        sbb edx,TimerHi
        mov TimerLo,eax
        mov TimerHi,edx
    mov edi,offset DrvFilename+4;&edi='scp01.sys',0
;-----инициализируем драйвер
    push eax
    push esp
        lea eax,acDriverPath
    push eax
    push MAX_PATH
    push edi
    call _imp__GetFullPathNameA@16
    pop eax
    ; Open a handle to the SC Manager database
    push SC_MANAGER_ALL_ACCESS;CREATE_SERVICE
    push ebx;NULL 
    push ebx;NULL 
    call _imp__OpenSCManagerA@12
;control manager on the specified computer and opens the specified database
    mov Manager,eax 
        mov [edi+5],ebx;&edi=Drvname='scp01',0
    test eax,eax
    jz err;if eax != NULL
    inc esi
        push SERVICE_ALL_ACCESS
    push edi
    push eax
    call _imp__OpenServiceA@12
    test eax,eax
    jne short a0    
    ; Register driver in SCM active database
    push ebx;NULL
    push ebx;NULL 
    push ebx;NULL 
    push ebx;NULL 
    push ebx;NULL 
        lea ecx,acDriverPath 
    push ecx;DrvPath 
    push SERVICE_ERROR_NORMAL;IGNORE
    push SERVICE_DEMAND_START
    push SERVICE_KERNEL_DRIVER 
    push SERVICE_ALL_ACCESS;START + DELETE 
    push edi 
    push edi
    push Manager
    call _imp__CreateServiceA@52
    test eax,eax
    jz a3;if eax != NULL
a0: mov Service,eax
    push offset Status
    push eax
    call _imp__QueryServiceStatus@8
    xchg eax,ecx
    jecxz wmDESTROY
    cmp Status.SERVICE_STATUS.dwCurrentState,SERVICE_RUNNING
    je short a10
    push ebx;offset Vectors
    push ebx;0 
    push Service 
    call _imp__StartServiceA@12 
a10:    sub edi,4;&edi='\\.\scp01',0
    push ebx
    push ebx
    push OPEN_EXISTING
    push ebx
    push FILE_SHARE_READ; or FILE_SHARE_WRITE
    push GENERIC_READ; or GENERIC_WRITE 
    push edi
    call _imp__CreateFileA@28   
    mov Driver,eax
    inc eax;cmp eax,INVALID_HANDLE_VALUE
    je short a4
    dec eax
    ; Here driver beeper.sys plays melody
        mov edi,offset Query
    mov [edi],offset musik
    push ebx;адрес OVERLAPPED-структуры
    push offset Bytes;адрес переменой, куда будет занесено количество байт, помещенных в буфер драйвером
        push ebx; длина буфера
    push ebx; буфер, куда драйвер поместит свои данные
    push 4;длина данных
    push edi;адрес данных для драйвера
    push DRIVER_QUERY_PROC_NOARGS;номер необходимой операции
    push eax;дескриптор драйвера, полученный через функцию CreateFile
    call _imp__DeviceIoControl@32
    ; and reports error to be removed from memory
    ; Remove driver from SCM database
wmDESTROY: push Driver
    call _imp__CloseHandle@4
a4: mov eax,Service
        push eax;Service
        push eax;Service
    push offset Status
    push SERVICE_CONTROL_STOP
    push eax;Service
    call _imp__ControlService@12; Send a control code to a Win32 service 
    call _imp__DeleteService@4
    call _imp__CloseServiceHandle@4
a3: push Manager
    call _imp__CloseServiceHandle@4
    jmp short a11
err:    push MB_ICONSTOP        
    push ebx;NULL
    push handle[esi*4];offset can_t_connect
    push ebx;NULL
    call _imp__MessageBoxA@16 
a11:    push ebx;0
    call _imp__ExitProcess@4
start endp
;--------------------------------------------------------------
musik:  ;set bits 0,1 of PC speaker control register:
        in al,61h;текущее состояние порта 61h в AL
    or al,00000011b;установить биты 0 и 1 в 1
    out 61h,al ;теперь динамик включен
    mov al,0B6h
    out 43h,al  ;Timer  8253-5 (AT: 8254.2).
    mov esi,offset melody; данные 
    mov ecx,size_melody  ; счетчик
    mov dx,42h ;Timer 8253-5 (AT: 8254.2).
    push edi
a15:    push edx   ;PC/XT PPI port B bits:
    push ecx   ;0: Timer 2 gate OR  03h= speaker ON
    rdtsc      ;1: Timer 2 data AND 0FCh= speaker OFF
    mov ecx,eax;2:
    mov edi,edx;3: 1=read high switches
    add ecx,TimerLo;4: 0=enable RAM parity checking
    adc edi,TimerHi;5: 0=enable I/O channel check           
@@: rdtsc; крутимся до тех пор пока не получится
    sub eax,ecx; задержка в 55 мСек
    sbb edx,edi
    jnz @b;6: 0=hold keyboard clock low    
    pop ecx   ;7: 0=enable keyboard
    pop edx   ;Команда выводит данные в порт ввода-вывода, 
    outsb     ;номер которого загружен в регистр DX, 
    loop a15  ;из ячейки памяти по адресу DS:ESI
    pop edi
    in al,61h
    and al,11111100b;4Dh 
    out 61h,al          
    retn      
;----------------------------------------------------------------
.data
melody  dw 2 dup(354h),2,2,2 dup(387h),2,2,2 dup(3BDh),2 dup(387h),2 dup(3BDh)
dw 2 dup(3F5h),2 dup(432h),2,2,2 dup(472h),2,2,4 dup(4B5h),4 dup(472h),2 dup(3F5h)
dw 2,2,2 dup(432h),2,2,2 dup(472h),2 dup(432h),2 dup(472h),2 dup(4B5h),2 dup(4FDh)
dw 2,2,2 dup(549h),2,2,4 dup(599h),4 dup(549h),2 dup(472h),2,2,2 dup(5EEh,2)
dw 4 dup(649h),4 dup(5EEh),2 dup(472h),2,2,2 dup(5EEh,2),4 dup(649h),4 dup(5EEh)
dw 2 dup(70Eh),2 dup(6A8h),2 dup(649h),2 dup(5EEh),2 dup(599h),2 dup(549h)
dw 2 dup(4FDh),2 dup(4B5h),2 dup(472h),2,2,2 dup(432h),2,2,2 dup(3F5h),2,2
dw 2 dup(387h),2,2,8 dup(354h),2
size_melody = $ - melody
;----------------------------------------------------------------
TimerLo dd 0
TimerHi dd 0
DrvFilename db '\\.\scp01.sys',0
Query dd ?
Status  db sizeof(SERVICE_STATUS) dup (?)
Bytes   dd ?
handle dd can_t_connect,can_t_register
can_t_connect db "Can't connect to Service Control Manager.",0
can_t_register db "Can't register driver.",0
end start
Второй вариант user-mode приложения, которое запускает драйвер scp01.sys


Предварительно прописываем драйвер scp01.sys в реестре «вручную» (используем функции RegOpenKey, RegCreateKey, RegSetValue) и загружаем драйвер scp00.sys с помощью функции ZwLoadDriver. В реестре создается минимум необходимых записей, запускаем драйвер, выгружаем драйвер функцией ZwUnloadDriver и удаляем его раздел из реестра (используем функции RegCloseKey, SHDeleteKey).
Этот способ позволяет запускать драйвер быстро и незаметно и подходит для маленьких программ не требующих установки, но требующих запуска своего драйвера.

Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
; masm windows gui #
.686P
.model flat
include windows.inc
 
includelib kernel32.lib
includelib advapi32.lib
includelib ntdll.lib
includelib shlwapi.lib
 
extern _imp__ExitProcess@4:dword 
extern _imp__GetFullPathNameA@16:dword
extern _imp__Sleep@4:dword
extern _imp__CreateFileA@28:dword
extern _imp__DeviceIoControl@32:dword
extern _imp__CloseHandle@4:dword
extern _imp__RegOpenKeyA@12:dword
extern _imp__RegCreateKeyA@12:dword
extern _imp__RegSetValueExA@24:dword
extern _imp__RegCloseKey@4:dword
extern _imp__SHDeleteKeyA@8:dword
extern _imp__ZwLoadDriver@4:dword
extern _imp__ZwUnloadDriver@4:dword
 
SERVICE_ERROR_NORMAL        equ 1
MAX_PATH            equ 260
DRIVER_QUERY_PROC_NOARGS    equ 10h
;--------macros-------------------
du  macro string
    irpc c,<string>
    if '&c'gt 127
    db ('&c'- 0B0h),4
    else
    dw '&c'
    endif
    endm
    dw 0
    endm
.const
align 4
us: du <\registry\machine\SYSTEM\CurrentControlSet\Services\scp01>
len_us = $-us
align 4
cusDevice dw (len_us - 2)
          dw (len_us)
      dd us
 
.code
 
start proc
local Key2:HKEY
local Key:HKEY
local acDriverPath[MAX_PATH]:CHAR
 
    xor ebx,ebx
    rdtsc; замеряем скольким тикам соответствует 40 мСек
        mov TimerLo,eax
        mov TimerHi,edx
    push 40
    call _imp__Sleep@4
    rdtsc
        sub eax,TimerLo
        sbb edx,TimerHi
        mov TimerLo,eax
        mov TimerHi,edx
    mov esi,offset scp01_sys_name+4;&esi='scp01.sys',0
        lea edi,acDriverPath
    mov eax,'\??\'
    stosd;путь к драйверу должен начаться с '\??\'
;-----инициализируем драйвер
    push eax;резервирую место в стеке
    push esp;указатель на пустое место в стеке
    push edi;&acDriverPath+4
    sub edi,4
    push MAX_PATH
    push esi
    call _imp__GetFullPathNameA@16
    add eax,4
    push eax
    lea eax,Key
    push eax
    push offset aSystem 
    push HKEY_LOCAL_MACHINE
    call _imp__RegOpenKeyA@12
        mov [esi+5],ebx;&esi=Drvname='scp01',0
        lea eax,Key2
        push eax
    push esi
    push Key
    call _imp__RegCreateKeyA@12
    push edi;&acDriverPath
    push REG_SZ
    push ebx;NULL 
    push offset aImagePath 
    push Key2
    call _imp__RegSetValueExA@24
    mov eax,esp;указатель на пустое место в стеке
        push sizeof(dword)
    mov dword ptr [eax],1;в пустое место в стеке поместим переменную dType=1
    push eax;&dType
    push REG_DWORD;тип переменной dType
    push ebx;0
    push offset aType;название переменной dType
    push Key2
    call _imp__RegSetValueExA@24
    push Key2
    call _imp__RegCloseKey@4
    mov [esp],offset cusDevice
    call _imp__ZwLoadDriver@4; выравниваем стек после GetFullPathNameA 
    sub esi,4;&esi='\\.\scp01',0
    push ebx
    push ebx
    push OPEN_EXISTING
    push ebx
    push FILE_SHARE_READ; or FILE_SHARE_WRITE
    push GENERIC_READ; or GENERIC_WRITE 
    push esi
    call _imp__CreateFileA@28   
    inc eax;cmp eax,INVALID_HANDLE_VALUE
    je short @f
    dec eax
    push eax;дескриптор драйвера для CloseHandle
        mov ecx,offset Query
    mov [ecx],offset musik
    push ebx;адрес OVERLAPPED-структуры
    push offset Bytes;адрес переменой, куда будет занесено количество байт, помещенных в буфер драйвером
        push ebx; длина буфера
    push ebx; буфер, куда драйвер поместит свои данные
    push 4;длина данных
    push ecx;адрес данных для драйвера
    push DRIVER_QUERY_PROC_NOARGS;номер необходимой операции
    push eax;дескриптор драйвера, полученный через функцию CreateFile
    call _imp__DeviceIoControl@32
    call _imp__CloseHandle@4
@@: push offset cusDevice
    call _imp__ZwUnloadDriver@4
    lodsd;add esi,4 
        push esi;&esi='scp01',0 
    push Key
    call _imp__SHDeleteKeyA@8
    push Key
    call _imp__RegCloseKey@4
    push ebx;0
    call _imp__ExitProcess@4
start endp
;--------------------------------------------------------------
musik:  ;set bits 0,1 of PC speaker control register:
        in al,61h;текущее состояние порта 61h в AL
    or al,00000011b;установить 0-ой и 1-ый биты 
    out 61h,al ;теперь динамик включен
    mov al,0B6h
    out 43h,al  ;Timer  8253-5 (AT: 8254.2).
    mov esi,offset melody; данные 
    mov ecx,size_melody  ; счетчик
    mov dx,42h ;Timer 8253-5 (AT: 8254.2).
    push edi
a15:    push edx   ;PC/XT PPI port B bits:
    push ecx   ;0: Timer 2 gate OR  03h= speaker ON
    rdtsc      ;1: Timer 2 data AND 0FCh= speaker OFF
    mov ecx,eax;2:
    mov edi,edx;3: 1=read high switches
    add ecx,TimerLo;4: 0=enable RAM parity checking
    adc edi,TimerHi;5: 0=enable I/O channel check           
@@: rdtsc; крутимся до тех пор пока не получится
    sub eax,ecx; задержка в 55 мСек
    sbb edx,edi
    jnz @b;6: 0=hold keyboard clock low    
    pop ecx   ;7: 0=enable keyboard
    pop edx   ;Команда выводит данные в порт ввода-вывода, 
    outsb     ;номер которого загружен в регистр DX, 
    loop a15  ;из ячейки памяти по адресу DS:ESI
    pop edi
    in al,61h
    and al,11111100b;сбросить 0-ой и 1-ый биты 
    out 61h,al  ;теперь динамик выключен
    retn      
;----------------------------------------------------------------
.data
melody  dw 2 dup(354h),2,2,2 dup(387h),2,2,2 dup(3BDh),2 dup(387h),2 dup(3BDh)
dw 2 dup(3F5h),2 dup(432h),2,2,2 dup(472h),2,2,4 dup(4B5h),4 dup(472h),2 dup(3F5h)
dw 2,2,2 dup(432h),2,2,2 dup(472h),2 dup(432h),2 dup(472h),2 dup(4B5h),2 dup(4FDh)
dw 2,2,2 dup(549h),2,2,4 dup(599h),4 dup(549h),2 dup(472h),2,2,2 dup(5EEh,2)
dw 4 dup(649h),4 dup(5EEh),2 dup(472h),2,2,2 dup(5EEh,2),4 dup(649h),4 dup(5EEh)
dw 2 dup(70Eh),2 dup(6A8h),2 dup(649h),2 dup(5EEh),2 dup(599h),2 dup(549h)
dw 2 dup(4FDh),2 dup(4B5h),2 dup(472h),2,2,2 dup(432h),2,2,2 dup(3F5h),2,2
dw 2 dup(387h),2,2,8 dup(354h),2
size_melody = $ - melody
;----------------------------------------------------------------
TimerLo dd 0
TimerHi dd 0
scp01_sys_name db '\\.\scp01.sys',0
Query dd ?
Bytes   dd ?
aSystem db 'SYSTEM\CurrentControlSet\Services',0
aType   db "Type",0
aImagePath db "ImagePath",0
end start
Третий вариант user-mode приложения, которое запускает драйвер scp01.sys


Устанавливаем драйвер при помощи функции ZwSetSystemInformation

Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
; masm windows gui #
.686P
.model flat
include windows.inc
 
includelib kernel32.lib
includelib advapi32.lib
includelib ntdll.lib
includelib shlwapi.lib
 
extern _imp__ExitProcess@4:dword 
extern _imp__GetFullPathNameA@16:dword
extern _imp__Sleep@4:dword
extern _imp__CreateFileA@28:dword
extern _imp__DeviceIoControl@32:dword
extern _imp__CloseHandle@4:dword
extern _imp__ZwSetSystemInformation@12:dword
 
SERVICE_ERROR_NORMAL        equ 1
MAX_PATH            equ 260
DRIVER_QUERY_PROC_NOARGS    equ 10h
SystemLoadAndCallImage      equ 26h
 
.code
start proc
local GregsImage:qword
local daPath[MAX_PATH]:CHAR
local acDriverPath[MAX_PATH]:CHAR
 
    xor ebx,ebx
    rdtsc; замеряем скольким тикам соответствует 40 мСек
        mov TimerLo,eax
        mov TimerHi,edx
    push 40
    call _imp__Sleep@4
    rdtsc
        sub eax,TimerLo
        sbb edx,TimerHi
        mov TimerLo,eax
        mov TimerHi,edx
    mov esi,offset scp01_sys_name+4;&esi='scp01.sys',0
        lea edi,acDriverPath
    mov eax,'\??\'
    stosd;путь к драйверу должен начаться с '\??\'
;-----инициализируем драйвер
    push eax;резервирую место в стеке
    push esp;указатель на пустое место в стеке
    push edi;&acDriverPath+4
    push MAX_PATH
    push esi
    call _imp__GetFullPathNameA@16
    pop ecx
    add eax,4
        mov ecx,eax
    imul eax,20002h
    add eax,2
    mov dword ptr GregsImage,eax
    lea edi,daPath
    mov dword ptr GregsImage+4,edi
    xor eax,eax
    lea esi,acDriverPath
@@: lodsb
    stosw
    loop @b
    push sizeof GregsImage;8
    lea edi,GregsImage
    push edi;&GregsImage
    push SystemLoadAndCallImage;=26h
    call _imp__ZwSetSystemInformation@12
        mov esi,offset scp01_sys_name
        mov [esi+5],ebx;&esi=Drvname='scp01',0
    push ebx
    push ebx
    push OPEN_EXISTING
    push ebx
    push FILE_SHARE_READ; or FILE_SHARE_WRITE
    push GENERIC_READ; or GENERIC_WRITE 
    push esi
    call _imp__CreateFileA@28   
    inc eax;cmp eax,INVALID_HANDLE_VALUE
    je short @f
    dec eax
    push eax;дескриптор драйвера для CloseHandle
        mov ecx,offset Query
    mov [ecx],offset musik
    push ebx;адрес OVERLAPPED-структуры
    push offset Bytes;адрес переменой, куда будет занесено количество байт, помещенных в буфер драйвером
        push ebx; длина буфера
    push ebx; буфер, куда драйвер поместит свои данные
    push 4;длина данных
    push ecx;адрес данных для драйвера
    push DRIVER_QUERY_PROC_NOARGS;номер необходимой операции
    push eax;дескриптор драйвера, полученный через функцию CreateFile
    call _imp__DeviceIoControl@32
    call _imp__CloseHandle@4
@@: push ebx;0
    call _imp__ExitProcess@4
start endp
;--------------------------------------------------------------
musik:  ;set bits 0,1 of PC speaker control register:
        in al,61h;текущее состояние порта 61h в AL
    or al,00000011b;установить 0-ой и 1-ый биты 
    out 61h,al ;теперь динамик включен
    mov al,0B6h
    out 43h,al  ;Timer  8253-5 (AT: 8254.2).
    mov esi,offset melody; данные 
    mov ecx,size_melody  ; счетчик
    mov dx,42h ;Timer 8253-5 (AT: 8254.2).
    push edi
a15:    push edx   ;PC/XT PPI port B bits:
    push ecx   ;0: Timer 2 gate OR  03h= speaker ON
    rdtsc      ;1: Timer 2 data AND 0FCh= speaker OFF
    mov ecx,eax;2:
    mov edi,edx;3: 1=read high switches
    add ecx,TimerLo;4: 0=enable RAM parity checking
    adc edi,TimerHi;5: 0=enable I/O channel check           
@@: rdtsc; крутимся до тех пор пока не получится
    sub eax,ecx; задержка в 55 мСек
    sbb edx,edi
    jnz @b;6: 0=hold keyboard clock low    
    pop ecx   ;7: 0=enable keyboard
    pop edx   ;Команда выводит данные в порт ввода-вывода, 
    outsb     ;номер которого загружен в регистр DX, 
    loop a15  ;из ячейки памяти по адресу DS:ESI
    pop edi
    in al,61h
    and al,11111100b;сбросить 0-ой и 1-ый биты 
    out 61h,al  ;теперь динамик выключен
    retn      
;----------------------------------------------------------------
.data
melody  dw 2 dup(354h),2,2,2 dup(387h),2,2,2 dup(3BDh),2 dup(387h),2 dup(3BDh)
dw 2 dup(3F5h),2 dup(432h),2,2,2 dup(472h),2,2,4 dup(4B5h),4 dup(472h),2 dup(3F5h)
dw 2,2,2 dup(432h),2,2,2 dup(472h),2 dup(432h),2 dup(472h),2 dup(4B5h),2 dup(4FDh)
dw 2,2,2 dup(549h),2,2,4 dup(599h),4 dup(549h),2 dup(472h),2,2,2 dup(5EEh,2)
dw 4 dup(649h),4 dup(5EEh),2 dup(472h),2,2,2 dup(5EEh,2),4 dup(649h),4 dup(5EEh)
dw 2 dup(70Eh),2 dup(6A8h),2 dup(649h),2 dup(5EEh),2 dup(599h),2 dup(549h)
dw 2 dup(4FDh),2 dup(4B5h),2 dup(472h),2,2,2 dup(432h),2,2,2 dup(3F5h),2,2
dw 2 dup(387h),2,2,8 dup(354h),2
size_melody = $ - melody
;----------------------------------------------------------------
TimerLo dd 0
TimerHi dd 0
scp01_sys_name db '\\.\scp01.sys',0
Query dd ?
Bytes   dd ?
end start
_________________________________________________________
© Mikl___ 2011
12
ASDFD12
57 / 57 / 13
Регистрация: 15.09.2012
Сообщений: 542
12.10.2012, 22:22  [ТС] #9
Miki / Спасибо за написаную статью, но честно говоря из написаного выше я мало что понял. Естественно что для понимания даного кода нужно немало прочитать. Нада на уровне регистров понимать как работает ОС Windows, например чтоб передать число на какой то порт, сначала записать его в регистр al, и только после этого можна передать его содержимое в порт. Где эту информацию брать, сколько времени на это уйдет - думаю очень много. Хотелось бы примеров "более высокого уровня интеграции".Читал что есть модель драйвера WDM, а сейчас уже и WDF. Например, раньше было очень сложно писать пользовательские Windows приложения. Нада было знать очень много кода, перелопатить API функции. Сейчас ( из того немногого что я знаю) в C# создавать приложения буквально играясь в конструктора в визуальном режиме ( заполняем окно менюшками, кнопками, тексбоксами и определяем для них обработчики). Так у меня вышло написать простейший интернет браузер буквально за 5 минут, приэтом не сильно ламая голову.
Надеюсь что в мире програмирование есть подобная ситуация. Особенно после выхода Visual Studio 2012. Мало информации про WDF/ Надеюсь что это такая же "револючия" (как C#), которая поможет создавать драйвера не вникая (сильно в низкоуровневое програмирование). Лично мне интересно и низкоуровневое програмирование так как щитаю это проффесионализмом, но хотелось бы на пути начального изучения, начать с высокоуровневого програмирование - отдельно понять что как работает, глянуть на драйвер свысока, потом набравсь опыта понять как работает конкретная функция и далее уже разобрав низкоуровневые методы ее реализации научиться писать ассемблерные вставки в код драйвера при необходимости или когда это требуется.
Сейчас же хотелось бы (был бы очень рад) увидеть код драйвера WDF. Понять что это за "зверь", понять его структуру. Ожидаю од него что это будет какой то общий шаблон драйвера с возможностью его наполнять как стандартными функциями так и собственными - игра в "конструктор".
Хотелось бы чтобы эта тема помогла - многих именно заинтересовать в написании драйверов, показать что это не очень сильно сложно, а при прикладании постепенно усилий можна что-то научиться.
При прочтении вашой статьи - как я уже казал я почти ничего не понял - переписываем какието переменные из одного регистра в другой, выполняем функции, все очень для начального уровня сложно. Естественно если человек допустим учиться на прграмиста и постепенно с обяснеиями обучает все на уровне електроники, то может ему такой пример и легок.
Мне например более наглядным был пример драйвера (на сайте хабрахабр) который выдает сообщение в режиме ядра (Hell World - при запуске драйвера, и Gydbye - при его завершении. Конешно понимаю что никакой практической пользы от него нету, но все же это просто - можна самому с первого раза попробовать, это увлекательно, вызывает интерес к изучению.
Итак заключение моей мысли. Что лично вызвало у меня интерес к написанию драйверов. Не секрет что компютеры проникают у все сферы деятельности. Все больше выпускается так званых умных устройств на микроконтроллерах. Хотелось бы научится ими управлять с помощью ПК.
Какую мне бы хотелось увидеть здесь статью. Пример простейшого регулятора напряжения на МК. который бы управлял минидвигателем или освещением. Устройство подключается через любой порт ( что бы пороще было реализовать). У нас есть драйвер и пользовательское приложение. В пользовательском приложении допустим есть кнопки включить , выключить, и регулировка оборотов с помощью ползунка или чего то подобного. Хотелось бы это увидеть на примере драйвера WDF на основе C# ( или что то подобное).
0
Vadimych
635 / 478 / 12
Регистрация: 10.01.2011
Сообщений: 1,047
13.10.2012, 03:31 #10
Цитата Сообщение от ASDFD12 Посмотреть сообщение
Какую мне бы хотелось увидеть здесь статью. Пример простейшого регулятора напряжения на МК

Не по теме:

ASDFD12, я правильно выбрал из Вашей пространной писанины ключевую фразу? Примерчик Вам подай. Мда, голь на выдумки хитра.

0
ASDFD12
57 / 57 / 13
Регистрация: 15.09.2012
Сообщений: 542
13.10.2012, 10:13  [ТС] #11
Цитата Сообщение от Vadimych Посмотреть сообщение

Не по теме:

ASDFD12, я правильно выбрал из Вашей пространной писанины ключевую фразу? Примерчик Вам подай. Мда, голь на выдумки хитра.

Правильно. Почему выдумки? Статья может помочь не только мне, а и другим пользователям. Думаю для продвинутого программера это не такая и сложная задача. Не знаю чем плоха эта идея.
0
Vadimych
13.10.2012, 13:22
  #12

Не по теме:

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

0
Памирыч
Почетный модератор
20824 / 8706 / 1032
Регистрация: 11.04.2010
Сообщений: 11,010
13.10.2012, 17:08 #13
Оффтоп прекращаем
0
Mikl___
Автор FAQ
11029 / 5803 / 513
Регистрация: 11.11.2010
Сообщений: 10,814
15.10.2012, 12:30 #14
Цитата Сообщение от ASDFD12 Посмотреть сообщение
но честно говоря из написаного выше я мало что понял. Естественно что для понимания даного кода нужно немало прочитать
ASDFD12,
литературу в школе учат десять лет, начиная с букваря и простейших сказок, год за годом сложность прочитанного увеличивается и к 10-11 году обучаемый в состоянии разобраться в идеях и творчестве Чехова, Пастернака, Толстова... А здесь ты хочешь после прочтения одной единственной статьи начать писать kernel-mode драйвера?

Добавлено через 5 часов 22 минуты
Доступ к командам In/Out через драйвер режима ядра

Переделываю драйвер <R>ing-<0> <P>rocedure <C>all & Direct Port I/O (r0pc.sys) by @L.chemist (Andrey A. Meshkov). Драйвер scp02 передает управление на фрагмент кода из scp02-00.exe в котором содержится команда outsb, синхронизация производится через предварительный подсчет тиков. Адрес процедуры передается через WriteFile("\\.\scp02"). Полнофункциональный драйвер.

Далее исходный текст драйвера scp02.sys
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
; masm windows native #
;написано на основе драйвера режима ядра <R>ing-<0> <P>rocedure 
;<C>all & Direct Port I/O (r0pc.sys) by @L.chemist (Andrey A. Meshkov)
.686p
.model flat
include ntstatus.inc
include ntddk.inc
include Strings.mac
includelib ntoskrnl.lib
; --------------------------------------------------------------------------------
extern _imp__IoCreateDevice@28:dword
extern _imp__IoCreateSymbolicLink@8:dword
extern _imp__IoDeleteDevice@4:dword
extern _imp__IoDeleteSymbolicLink@4:dword
extern _imp_@IofCompleteRequest@8:dword
 
IOPM_SIZE equ 2000h             ; sizeof I/O permission map
DRIVER_QUERY_PROC_NOARGS    = 10h
; --------------------------------------------------------------------------------
; structure for driver query
DriverQuery struct 
  iocode dd ? ; user I/O code
  wparam dd ? ; parameter
  lparam dd ? ; parameter
DriverQuery ends
PDriverQuery equ dd
; --------------------------------------------------------------------------------
.const
CCOUNTED_UNICODE_STRING "\\Device\\scp02", cusDevice, 4
CCOUNTED_UNICODE_STRING "\\DosDevices\\scp02", cusSymbolicLink, 4
 
.code
; Процедура входа драйвера. Эта процедура вызывается только раз после загрузки
; драйвера в память. Она выделяет необходимые ресурсы для работы драйвера. В
; нашем случае
DriverEntry proc lpDriverObject:PDRIVER_OBJECT, lpusRegistryPath:PUNICODE_STRING
local deviceObject:PDEVICE_OBJECT
local status:NTSTATUS
; инициализируем драйвер устройства и объект устройства (Device Object)
    lea eax,deviceObject
    push eax;&deviceObject
    push 0
    push 0
    push FILE_DEVICE_UNKNOWN;22h
    push offset cusDevice
    push sizeof(DriverQuery);0Ch
    push lpDriverObject
    call _imp__IoCreateDevice@28
    test eax,eax;cmp eax,STATUS_SUCCESS; 0
    jnz short exit; break on error
; create symbolic link to the user-visible name
; создаем символическую ссылку на драйвер устройства, что позволяет user-mode
; приложению получить доступ к нашему драйверу, используя "\\.\scp02" нотацию
    push offset cusDevice
    push offset cusSymbolicLink
    call _imp__IoCreateSymbolicLink@8
        mov status,eax; save status                
    test eax,eax;cmp eax,STATUS_SUCCESS; check result
    jz short success                
    push deviceObject
    call _imp__IoDeleteDevice@4; delete device object if not successful
    jmp short exit
success:    ; continue on success
; load structure to point to IRP handlers
; инициализируем точки входа драйвера в объект драйвера
; всё, что нам нужно, это операция создания (Create), записи (Write) 
; и выгрузки (Unload)
    mov eax,lpDriverObject
    mov (DRIVER_OBJECT ptr [eax]).DriverUnload,offset DriverUnload
    mov (DRIVER_OBJECT ptr [eax]).MajorFunction[IRP_MJ_CREATE*4],offset DispatchCreate
    mov (DRIVER_OBJECT ptr [eax]).MajorFunction[IRP_MJ_WRITE*4],offset DispatchWrite                
    mov eax,status; assign result
exit:   leave
    retn 8
DriverEntry endp
;------------------------------------------------------
;освобождаем все выделенные ранее объекты
DriverUnload:
lpDriverObject  equ dword ptr [esp+4];:PDRIVER_OBJECT
; delete symbolic link to the user-visible name
    push offset cusSymbolicLink
    call _imp__IoDeleteSymbolicLink@4
; delete device object
    mov ecx,lpDriverObject
    push dword ptr (DRIVER_OBJECT ptr [ecx]).DeviceObject
    call _imp__IoDeleteDevice@4
    retn 4
;--------------------------------------------------
DispatchCreate:
lIrp equ dword ptr [esp+8]
    mov ecx,lIrp
    and (_IRP ptr [ecx]).IoStatus.Status,STATUS_SUCCESS;0
    and (_IRP ptr [ecx]).IoStatus.Information,0
    xor edx,edx;edx = IO_NO_INCREMENT
    call _imp_@IofCompleteRequest@8;IofCompleteRequest (lpIrp, IO_NO_INCREMENT)
    xor eax,eax;mov eax,STATUS_SUCCESS; 0
    retn 8
;---------------------------------------------------------
DispatchWrite   proc pDeviceObject:PDRIVER_OBJECT, lpIrp:PIRP 
local status:NTSTATUS
 
    push edi
    mov status,STATUS_UNSUCCESSFUL; 0C0000001h
    mov edi,lpIrp
    and (_IRP ptr [edi]).IoStatus.Information,0;
    mov eax,(_IRP ptr [edi]).Tail.Overlay.CurrentStackLocation
    cmp [eax].IO_STACK_LOCATION.Parameters.Write._Length, sizeof(DriverQuery)
    jnz a0
    mov status,STATUS_NOT_IMPLEMENTED; 0C0000002h
    mov eax,(_IRP ptr [edi]).UserBuffer 
    cmp (DriverQuery ptr [eax]).iocode,DRIVER_QUERY_PROC_NOARGS
    jne a0
    call (DriverQuery ptr [eax]).wparam
    and status,STATUS_SUCCESS;status = 0
a0: push status
    pop (_IRP ptr [edi]).IoStatus.Status
    mov ecx,edi
    xor edx,edx;edx = IO_NO_INCREMENT
    call _imp_@IofCompleteRequest@8;IofCompleteRequest (lpIrp, IO_NO_INCREMENT)
    mov eax,status
    pop edi
    leave
    retn 8
DispatchWrite   endp
;----------------------------------------------------
end DriverEntry
Первый вариант user-mode приложения, которое запускает драйвер scp02.sys

user-mode приложение, которое запускает scp02.sys драйвер, используя API-функции Service Control Manager'a: OpenSCManager, CreateService, StartService, CloseServiceHandle и DeleteService.
Этот способ очень прост и хорошо документирован, он подходит для постоянной установки драйверов.
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
; masm windows gui #
.686P
.model flat
include windows.inc
 
includelib kernel32.lib
includelib user32.lib
includelib advapi32.lib
 
extern _imp__ExitProcess@4:dword 
extern _imp__GetFullPathNameA@16:dword
extern _imp__MessageBoxA@16:dword
extern _imp__CloseServiceHandle@4:dword
extern _imp__DeleteService@4:dword
extern _imp__StartServiceA@12:dword
extern _imp__CreateServiceA@52:dword
extern _imp__OpenSCManagerA@12:dword
extern _imp__Sleep@4:dword
extern _imp__OpenServiceA@12:dword
extern _imp__QueryServiceStatus@8:dword
extern _imp__CreateFileA@28:dword
extern _imp__WriteFile@20:dword
extern _imp__CloseHandle@4:dword
extern _imp__ControlService@12:dword
 
SERVICE_ERROR_NORMAL        equ 1
MAX_PATH            equ 260
DRIVER_QUERY_PROC_NOARGS    equ 10h
; structure for driver query
R0DriverQuery STRUCT 
    iocode dd ? ; user I/O code
    wparam dd ? ; parameter
    lparam dd ? ; parameter
R0DriverQuery ENDS
 
.code
 
start proc
local DrvFile:dword
local Driver:HANDLE
local Service:HANDLE
local Manager:HANDLE
local acDriverPath[MAX_PATH]:CHAR
        xor esi,esi
    xchg eax,ebx
    rdtsc; замеряем скольким тикам соответствует 40 мСек
        mov TimerLo,eax
        mov TimerHi,edx
    push 40
    call _imp__Sleep@4
    rdtsc
        sub eax,TimerLo
        sbb edx,TimerHi
        mov TimerLo,eax
        mov TimerHi,edx
    mov edi,offset DrvFilename+4;&edi='scp02.sys',0
;-----инициализируем драйвер
    push eax
    push esp
        lea eax,acDriverPath
    push eax
    push MAX_PATH
    push edi
    call _imp__GetFullPathNameA@16
    pop eax
    ; Open a handle to the SC Manager database
    push SC_MANAGER_ALL_ACCESS;CREATE_SERVICE
    push ebx;NULL 
    push ebx;NULL 
    call _imp__OpenSCManagerA@12
;control manager on the specified computer and opens the specified database
    mov Manager,eax 
        mov [edi+5],ebx;&edi=Drvname='scp02',0
    test eax,eax
    jz err;if eax != NULL
    inc esi
        push SERVICE_ALL_ACCESS
    push edi
    push eax
    call _imp__OpenServiceA@12
    test eax,eax
    jne short a0    
    ; Register driver in SCM active database
    push ebx;NULL
    push ebx;NULL 
    push ebx;NULL 
    push ebx;NULL 
    push ebx;NULL 
        lea ecx,acDriverPath 
    push ecx;DrvPath 
    push SERVICE_ERROR_NORMAL;IGNORE
    push SERVICE_DEMAND_START
    push SERVICE_KERNEL_DRIVER 
    push SERVICE_ALL_ACCESS;START + DELETE 
    push edi 
    push edi
    push Manager
    call _imp__CreateServiceA@52
    test eax,eax
    jz a3;if eax != NULL
a0: mov Service,eax
    push offset Status
    push eax
    call _imp__QueryServiceStatus@8
    xchg eax,ecx
    jecxz wmDESTROY
    cmp Status.SERVICE_STATUS.dwCurrentState,SERVICE_RUNNING
    je short a10
    push ebx;offset Vectors
    push ebx;0 
    push Service 
    call _imp__StartServiceA@12 
a10:    sub edi,4;&edi='\\.\scp02',0
    push ebx
    push ebx
    push OPEN_EXISTING
    push ebx
    push FILE_SHARE_READ or FILE_SHARE_WRITE
    push GENERIC_READ or GENERIC_WRITE 
    push edi
    call _imp__CreateFileA@28   
    mov Driver,eax
    inc eax;cmp eax,INVALID_HANDLE_VALUE
    je short a4
    dec eax
    ; Here driver beeper.sys plays melody
        mov edi,offset Query
    assume edi: ptr R0DriverQuery
    mov [edi].wparam,offset musik
        mov [edi].iocode,DRIVER_QUERY_PROC_NOARGS
    assume edi: nothing
    push ebx
    push offset Bytes
    push sizeof R0DriverQuery
    push edi
    push eax;Driver
    call _imp__WriteFile@20
    ; and reports error to be removed from memory
    ; Remove driver from SCM database
wmDESTROY: push Driver
    call _imp__CloseHandle@4
a4: mov eax,Service
        push eax;Service
        push eax;Service
    push offset Status
    push SERVICE_CONTROL_STOP
    push eax;Service
    call _imp__ControlService@12; Send a control code to a Win32 service 
    call _imp__DeleteService@4
    call _imp__CloseServiceHandle@4
a3: push Manager
    call _imp__CloseServiceHandle@4
    jmp short a11
err:    push MB_ICONSTOP        
    push ebx;NULL
    push handle[esi*4];offset can_t_connect
    push ebx;NULL
    call _imp__MessageBoxA@16 
a11:    push ebx;0
    call _imp__ExitProcess@4
start endp
;--------------------------------------------------------------
musik:  ;set bits 0,1 of PC speaker control register:
        in al,61h;текущее состояние порта 61h в AL
    or al,00000011b;установить биты 0 и 1 в 1
    out 61h,al ;теперь динамик включен
    mov al,0B6h
    out 43h,al  ;Timer  8253-5 (AT: 8254.2).
    mov esi,offset melody; данные 
    mov ecx,size_melody  ; счетчик
    mov dx,42h ;Timer 8253-5 (AT: 8254.2).
    push edi
a15:    push edx   ;PC/XT PPI port B bits:
    push ecx   ;0: Timer 2 gate OR  03h= speaker ON
    rdtsc      ;1: Timer 2 data AND 0FCh= speaker OFF
    mov ecx,eax;2:
    mov edi,edx;3: 1=read high switches
    add ecx,TimerLo;4: 0=enable RAM parity checking
    adc edi,TimerHi;5: 0=enable I/O channel check           
@@: rdtsc; крутимся до тех пор пока не получится
    sub eax,ecx; задержка в 55 мСек
    sbb edx,edi
    jnz @b;6: 0=hold keyboard clock low    
    pop ecx   ;7: 0=enable keyboard
    pop edx   ;Команда выводит данные в порт ввода-вывода, 
    outsb     ;номер которого загружен в регистр DX, 
    loop a15  ;из ячейки памяти по адресу DS:ESI
    pop edi
    in al,61h
    and al,11111100b;4Dh 
    out 61h,al          
    retn      
;----------------------------------------------------------------
melody  dw 2 dup(354h),2,2,2 dup(387h),2,2,2 dup(3BDh),2 dup(387h),2 dup(3BDh)
dw 2 dup(3F5h),2 dup(432h),2,2,2 dup(472h),2,2,4 dup(4B5h),4 dup(472h),2 dup(3F5h)
dw 2,2,2 dup(432h),2,2,2 dup(472h),2 dup(432h),2 dup(472h),2 dup(4B5h),2 dup(4FDh)
dw 2,2,2 dup(549h),2,2,4 dup(599h),4 dup(549h),2 dup(472h),2,2,2 dup(5EEh,2)
dw 4 dup(649h),4 dup(5EEh),2 dup(472h),2,2,2 dup(5EEh,2),4 dup(649h),4 dup(5EEh)
dw 2 dup(70Eh),2 dup(6A8h),2 dup(649h),2 dup(5EEh),2 dup(599h),2 dup(549h)
dw 2 dup(4FDh),2 dup(4B5h),2 dup(472h),2,2,2 dup(432h),2,2,2 dup(3F5h),2,2
dw 2 dup(387h),2,2,8 dup(354h),2
size_melody = $ - melody
;----------------------------------------------------------------
TimerLo dd 0
TimerHi dd 0
DrvFilename db '\\.\scp02.sys',0
Query R0DriverQuery <DRIVER_QUERY_PROC_NOARGS,0,0> ; user I/O code
Status  db sizeof(SERVICE_STATUS) dup (?)
Bytes   dd ?
handle dd can_t_connect,can_t_register
can_t_connect db "Can't connect to Service Control Manager.",0
can_t_register db "Can't register driver.",0
end start
Второй вариант user-mode приложения, которое запускает драйвер scp02.sys
Предварительно прописываем драйвер scp02.sys в реестре «вручную» (используем функции RegOpenKey, RegCreateKey, RegSetValue) и загружаем драйвер scp02.sys с помощью функции ZwLoadDriver. В реестре создается минимум необходимых записей, запускаем драйвер, выгружаем драйвер функцией ZwUnloadDriver и удаляем его раздел из реестра (используем функции RegCloseKey, SHDeleteKey).
Этот способ позволяет запускать драйвер быстро и незаметно и подходит для маленьких программ не требующих установки, но требующих запуска своего драйвера.
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
; masm windows gui #
.686P
.model flat
include windows.inc
 
includelib kernel32.lib
includelib advapi32.lib
includelib ntdll.lib
includelib shlwapi.lib
 
extern _imp__ExitProcess@4:dword 
extern _imp__GetFullPathNameA@16:dword
extern _imp__Sleep@4:dword
extern _imp__CreateFileA@28:dword
extern _imp__WriteFile@20:dword
extern _imp__CloseHandle@4:dword
extern _imp__RegOpenKeyA@12:dword
extern _imp__RegCreateKeyA@12:dword
extern _imp__RegSetValueExA@24:dword
extern _imp__RegCloseKey@4:dword
extern _imp__SHDeleteKeyA@8:dword
extern _imp__ZwLoadDriver@4:dword
extern _imp__ZwUnloadDriver@4:dword
 
MAX_PATH            equ 260
DRIVER_QUERY_PROC_NOARGS    equ 10h
; structure for driver query
R0DriverQuery STRUCT 
    iocode dd ? ; user I/O code
    wparam dd ? ; parameter
    lparam dd ? ; parameter
R0DriverQuery ENDS
;--------macros-------------------
du  macro string
    irpc c,<string>
    if '&c'gt 127
    db ('&c'- 0B0h),4
    else
    dw '&c'
    endif
    endm
    dw 0
    endm
.const
align 4
us: du <\registry\machine\SYSTEM\CurrentControlSet\Services\scp02>
len_us = $-us
align 4
cusDevice dw (len_us - 2)
          dw (len_us)
      dd us
.code
 
start proc
local Key2:HKEY
local Key:HKEY
local acDriverPath[MAX_PATH]:CHAR
 
    xchg eax,ebx
    rdtsc; замеряем скольким тикам соответствует 40 мСек
        mov TimerLo,eax
        mov TimerHi,edx
    push 40
    call _imp__Sleep@4
    rdtsc
        sub eax,TimerLo
        sbb edx,TimerHi
        mov TimerLo,eax
        mov TimerHi,edx
    mov esi,offset scp02_sys_name+4;&esi='scp02.sys',0
        lea edi,acDriverPath
    mov eax,'\??\'
    stosd;путь к драйверу должен начаться с '\??\'
;-----инициализируем драйвер
    push eax
    push esp
    push edi;&acDriverPath+4
    sub edi,4
    push MAX_PATH
    push esi;&esi='scp02.sys',0
    call _imp__GetFullPathNameA@16
    add eax,4
    push eax
    lea eax,Key
    push eax
    push offset aSystem
    push HKEY_LOCAL_MACHINE 
    call _imp__RegOpenKeyA@12
        mov [esi+5],ebx;&esi=Drvname='scp02',0
        lea eax,Key2
        push eax
    push esi
    push Key
    call _imp__RegCreateKeyA@12
    push edi;&acDriverPath
    push REG_SZ
    push ebx;NULL 
    push offset aImagePath 
    push Key2
    call _imp__RegSetValueExA@24
    mov eax,esp
    push sizeof(dword)
    mov dword ptr [eax],1;dType := 1
    push eax
    push REG_DWORD
    push ebx;0 
    push offset aType 
    push Key2
    call _imp__RegSetValueExA@24
        push Key2
    call _imp__RegCloseKey@4
    mov [esp],offset cusDevice
    call _imp__ZwLoadDriver@4 
    sub esi,4;&esi='\\.\scp02',0
    push ebx
    push ebx
    push OPEN_EXISTING
    push ebx
    push FILE_SHARE_READ or FILE_SHARE_WRITE
    push GENERIC_READ or GENERIC_WRITE 
    push esi
    call _imp__CreateFileA@28   
    inc eax;cmp eax,INVALID_HANDLE_VALUE
    je short @f
    dec eax
        push eax;дескриптор драйвера для CloseHandle
        mov ecx,offset Query
    assume ecx: ptr R0DriverQuery
    mov [ecx].wparam,offset musik
        mov [ecx].iocode,DRIVER_QUERY_PROC_NOARGS
    assume ecx: nothing
    push ebx
    push offset Bytes
    push sizeof R0DriverQuery
    push ecx
    push eax;Driver
    call _imp__WriteFile@20
    call _imp__CloseHandle@4
@@: push offset cusDevice           
    call _imp__ZwUnloadDriver@4
    lodsd;add esi,4
    push esi;&esi='scp02',0
    push Key
    call _imp__SHDeleteKeyA@8
    push Key
    call _imp__RegCloseKey@4
    push ebx;0
    call _imp__ExitProcess@4
start endp
;--------------------------------------------------------------
musik:  ;set bits 0,1 of PC speaker control register:
        in al,61h;текущее состояние порта 61h в AL
    or al,00000011b;установить биты 0 и 1 в 1
    out 61h,al ;теперь динамик включен
    mov al,0B6h
    out 43h,al  ;Timer  8253-5 (AT: 8254.2).
    mov esi,offset melody; данные 
    mov ecx,size_melody  ; счетчик
    mov dx,42h ;Timer 8253-5 (AT: 8254.2).
    push edi
a15:    push edx   ;PC/XT PPI port B bits:
    push ecx   ;0: Timer 2 gate OR  03h= speaker ON
    rdtsc      ;1: Timer 2 data AND 0FCh= speaker OFF
    mov ecx,eax;2:
    mov edi,edx;3: 1=read high switches
    add ecx,TimerLo;4: 0=enable RAM parity checking
    adc edi,TimerHi;5: 0=enable I/O channel check           
@@: rdtsc; крутимся до тех пор пока не получится
    sub eax,ecx; задержка в 55 мСек
    sbb edx,edi
    jnz @b;6: 0=hold keyboard clock low    
    pop ecx   ;7: 0=enable keyboard
    pop edx   ;Команда выводит данные в порт ввода-вывода, 
    outsb     ;номер которого загружен в регистр DX, 
    loop a15  ;из ячейки памяти по адресу DS:ESI
    pop edi
    in al,61h
    and al,11111100b;4Dh 
    out 61h,al          
    retn      
;----------------------------------------------------------------
melody  dw 2 dup(354h),2,2,2 dup(387h),2,2,2 dup(3BDh),2 dup(387h),2 dup(3BDh)
dw 2 dup(3F5h),2 dup(432h),2,2,2 dup(472h),2,2,4 dup(4B5h),4 dup(472h),2 dup(3F5h)
dw 2,2,2 dup(432h),2,2,2 dup(472h),2 dup(432h),2 dup(472h),2 dup(4B5h),2 dup(4FDh)
dw 2,2,2 dup(549h),2,2,4 dup(599h),4 dup(549h),2 dup(472h),2,2,2 dup(5EEh,2)
dw 4 dup(649h),4 dup(5EEh),2 dup(472h),2,2,2 dup(5EEh,2),4 dup(649h),4 dup(5EEh)
dw 2 dup(70Eh),2 dup(6A8h),2 dup(649h),2 dup(5EEh),2 dup(599h),2 dup(549h)
dw 2 dup(4FDh),2 dup(4B5h),2 dup(472h),2,2,2 dup(432h),2,2,2 dup(3F5h),2,2
dw 2 dup(387h),2,2,8 dup(354h),2
size_melody = $ - melody
;----------------------------------------------------------------
TimerLo dd 0
TimerHi dd 0
scp02_sys_name db '\\.\scp02.sys',0
Query R0DriverQuery <DRIVER_QUERY_PROC_NOARGS,0,0> ; user I/O code
Bytes   dd ?
aSystem db 'SYSTEM\CurrentControlSet\Services',0
aType   db "Type",0
aImagePath db "ImagePath",0
end start
________________________________
© Mikl___ 2011
9
taras atavin
3888 / 1762 / 92
Регистрация: 24.11.2009
Сообщений: 27,565
15.10.2012, 12:40 #15
Цитата Сообщение от ASDFD12 Посмотреть сообщение
Хотя в интернете и есть на русском языке некоторые обяснения что такое драйвер для его програмирования считаю это довольно узко.
Но ведь всё элементарно до безобразия: драйвером называется системная программа, обеспечивающая работоспособность конкретного перифирийного устройства, или меняющая её характеристики. На спектрумах водились проги для ускоренной загрузки файлов с магнитофона. По моим прикидкам раза в 2. Чем не драйвера? Явно не стандартные, но всё таки.
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
15.10.2012, 12:40
Привет! Вот еще темы с ответами:

Как работает драйвер swapBuffers - Программирование драйверов
В SDK есть такой стандартный сэмпл SwapBuffer File System Minifilter Driver. Просмотрел пару раз процедуры: SwapPreReadBuffers ...

Как скорректировать драйвер принтера - Программирование драйверов
Нужно снять ограничение по размеру печати в драйвере. Может кто-то сталкивался с этим вопросом. И сколько будет стоить корректировка.

Написать драйвер для планшета WACOM для xp64 или win7(64) - Программирование драйверов
Имею древний планшет WACOM. Последний драйвер, который удалось к нему найти, работал под xp32. Поменял машину, теперь 64. А планшет...

Необходимо написать драйвер для тачпада для windows 7 x64 - Программирование драйверов
Здравствуйте, дорогие форумчане.Я недавно купил ноутбук asus x556uf поставил win 7 при установке винды тачпад нормально работал вот после...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru