58 / 57 / 15
Регистрация: 15.09.2012
Сообщений: 557

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

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

Author24 — интернет-сервис помощи студентам
Хотя в интернете и есть на русском языке некоторые обяснения что такое драйвер для его програмирования считаю это довольно узко. Рускоязычные книги тоже не совсем понятно написаны. Вобщем мои рассуждения ( правильны ли они). Расссматриваю написания драйверов под виндовс. Для стабильности ОС програмисты разделиль функционирование ОС на две части - пользовательский режим и режим ядра, так как в пользовательском режиме возможности малы, то и испортить систему меньше шансов разным софтом. Драйвера работают в режиме ядра. Соответственно есть уже готовые функции API которые реализуют низкоуровневые операции и с помощью которых в основном и пишутся драйвера. Думаю что почти любой драйвер можна написать на основании этих функций + некоторые созданные собственно + асемблерные вставки. Соответственно драйвер считаю - это добавка до кода ОС, которая обясняяет как ей общаться с ОС. А как это делается ? Предполагаю что драйвер указывает какие низкоуровневые функции мы можем применить по отношению до даного устройства, указать какой приоритет у даного устройства. Неукладывается в голове что конкретно он делает. Вот подключаем мы какое-то неизвестное устройство до ПК. Оно подает какие то сигналы, и должно обрабатывать входящие. Для того чтобы просто работать с устройством ( ближе до человеческого языка) думаю что драйвер - это "образ" устройства в програмной форме - что то наподобе применения обектов в пользовательских приложениях (ООП). Тоесть мы создаем клас даного устройства, который описывает функции которые имеет даный обект и его свойства - не знаю какие. Кто как понимает - что делает драйвер. С чего начинается создание драйвера. Если допустим управлять внешним контроллером как выключателем. Почему написания драйверов кардинально отличается от написания пользовательського кода. Эсть ли какая то аналогичность. Очень хотелось бы чтобы человек который уже писал драйвера и четко все себе уяснил постарался по простому тезисно обяснить суть, самые важные аспекты по написанию драйверов.
2
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
23.09.2012, 14:50
Ответы с готовыми решениями:

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

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

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

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

Решение

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

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

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

Code
1
2
3
4
5
6
7
8
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\CurentControlS et\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\CurrentControl Set\Control\ServiceGroupOrder
lpdwTagId
Указатель на переменную, которая получает значение признака, являющееся уникальным в группе, заданной в параметре lpLoadOrderGroup. Задайте значение ПУСТО (NULL), если Вы не изменяете существующий признак. Вы можете использовать признак для того, чтобы упорядочить запуск службы в пределах очередности загрузки группы, определяя вектор очередности признака в следующем значении реестра:
HKEY_LOCAL_MACHINE\System\CurrentControl Set\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\CurrentContro lSet\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-строками в нулевом кольце

Code
1
2
3
4
5
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
24
 Аватар для Vadimych
639 / 482 / 12
Регистрация: 10.01.2011
Сообщений: 1,045
10.10.2012, 19:31
Mikl___, попробовал в windows 7x32 загрузить драйвер с помощью ZwSetSystemInformation. Возвращает 0xC0000061. Не помогает и полученная SE_LOAD_DRIVER_PRIVILEGE.
1
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16355 / 7671 / 1078
Регистрация: 11.11.2010
Сообщений: 13,734
11.10.2012, 03:24
Vadimych, там если внимательно читать, то есть фраза
Цитата Сообщение от Mikl___ Посмотреть сообщение
здесь должна была быть статья с рабочим названием «Доступ к портам ввода/вывода под Windows XP».
Под семеркой через ZwSetSystemInformation загрузка драйвера не пошла, а вот загрузка через ZwLoadDriver работает, сейчас разбираюсь с упрощением загрузки через inf-файлы
0
 Аватар для Vadimych
639 / 482 / 12
Регистрация: 10.01.2011
Сообщений: 1,045
11.10.2012, 05:00
Цитата Сообщение от Mikl___ Посмотреть сообщение
Vadimych, там если внимательно читать, то есть фраза
Да я без претензий, просто констатировал факт.
1
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16355 / 7671 / 1078
Регистрация: 11.11.2010
Сообщений: 13,734
12.10.2012, 04:22
Лучший ответ Сообщение было отмечено R71MT как решение

Решение

Доступ к командам 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
13
58 / 57 / 15
Регистрация: 15.09.2012
Сообщений: 557
12.10.2012, 22:22  [ТС]
Miki / Спасибо за написаную статью, но честно говоря из написаного выше я мало что понял. Естественно что для понимания даного кода нужно немало прочитать. Нада на уровне регистров понимать как работает ОС Windows, например чтоб передать число на какой то порт, сначала записать его в регистр al, и только после этого можна передать его содержимое в порт. Где эту информацию брать, сколько времени на это уйдет - думаю очень много. Хотелось бы примеров "более высокого уровня интеграции".Читал что есть модель драйвера WDM, а сейчас уже и WDF. Например, раньше было очень сложно писать пользовательские Windows приложения. Нада было знать очень много кода, перелопатить API функции. Сейчас ( из того немногого что я знаю) в C# создавать приложения буквально играясь в конструктора в визуальном режиме ( заполняем окно менюшками, кнопками, тексбоксами и определяем для них обработчики). Так у меня вышло написать простейший интернет браузер буквально за 5 минут, приэтом не сильно ламая голову.
Надеюсь что в мире програмирование есть подобная ситуация. Особенно после выхода Visual Studio 2012. Мало информации про WDF/ Надеюсь что это такая же "револючия" (как C#), которая поможет создавать драйвера не вникая (сильно в низкоуровневое програмирование). Лично мне интересно и низкоуровневое програмирование так как щитаю это проффесионализмом, но хотелось бы на пути начального изучения, начать с высокоуровневого програмирование - отдельно понять что как работает, глянуть на драйвер свысока, потом набравсь опыта понять как работает конкретная функция и далее уже разобрав низкоуровневые методы ее реализации научиться писать ассемблерные вставки в код драйвера при необходимости или когда это требуется.
Сейчас же хотелось бы (был бы очень рад) увидеть код драйвера WDF. Понять что это за "зверь", понять его структуру. Ожидаю од него что это будет какой то общий шаблон драйвера с возможностью его наполнять как стандартными функциями так и собственными - игра в "конструктор".
Хотелось бы чтобы эта тема помогла - многих именно заинтересовать в написании драйверов, показать что это не очень сильно сложно, а при прикладании постепенно усилий можна что-то научиться.
При прочтении вашой статьи - как я уже казал я почти ничего не понял - переписываем какието переменные из одного регистра в другой, выполняем функции, все очень для начального уровня сложно. Естественно если человек допустим учиться на прграмиста и постепенно с обяснеиями обучает все на уровне електроники, то может ему такой пример и легок.
Мне например более наглядным был пример драйвера (на сайте хабрахабр) который выдает сообщение в режиме ядра (Hell World - при запуске драйвера, и Gydbye - при его завершении. Конешно понимаю что никакой практической пользы от него нету, но все же это просто - можна самому с первого раза попробовать, это увлекательно, вызывает интерес к изучению.
Итак заключение моей мысли. Что лично вызвало у меня интерес к написанию драйверов. Не секрет что компютеры проникают у все сферы деятельности. Все больше выпускается так званых умных устройств на микроконтроллерах. Хотелось бы научится ими управлять с помощью ПК.
Какую мне бы хотелось увидеть здесь статью. Пример простейшого регулятора напряжения на МК. который бы управлял минидвигателем или освещением. Устройство подключается через любой порт ( что бы пороще было реализовать). У нас есть драйвер и пользовательское приложение. В пользовательском приложении допустим есть кнопки включить , выключить, и регулировка оборотов с помощью ползунка или чего то подобного. Хотелось бы это увидеть на примере драйвера WDF на основе C# ( или что то подобное).
0
 Аватар для Vadimych
639 / 482 / 12
Регистрация: 10.01.2011
Сообщений: 1,045
13.10.2012, 03:31
Цитата Сообщение от ASDFD12 Посмотреть сообщение
Какую мне бы хотелось увидеть здесь статью. Пример простейшого регулятора напряжения на МК

Не по теме:

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

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

Не по теме:

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

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

Не по теме:

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

0
Почетный модератор
 Аватар для Памирыч
23246 / 9158 / 1084
Регистрация: 11.04.2010
Сообщений: 11,014
13.10.2012, 17:08
Оффтоп прекращаем
0
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16355 / 7671 / 1078
Регистрация: 11.11.2010
Сообщений: 13,734
15.10.2012, 12:30
Цитата Сообщение от 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
10
 Аватар для taras atavin
4226 / 1796 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
15.10.2012, 12:40
Цитата Сообщение от ASDFD12 Посмотреть сообщение
Хотя в интернете и есть на русском языке некоторые обяснения что такое драйвер для его програмирования считаю это довольно узко.
Но ведь всё элементарно до безобразия: драйвером называется системная программа, обеспечивающая работоспособность конкретного перифирийного устройства, или меняющая её характеристики. На спектрумах водились проги для ускоренной загрузки файлов с магнитофона. По моим прикидкам раза в 2. Чем не драйвера? Явно не стандартные, но всё таки.
0
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16355 / 7671 / 1078
Регистрация: 11.11.2010
Сообщений: 13,734
15.10.2012, 13:00
Доступ к командам In/Out через изменение карты IOPM

Manipulating the IOPM (I/O Permission Bitmap)
Changing the IOPM within your Kernel Mode Drivers requires
the knowledge of a couple of undocumented calls.
These are Ke386IoSetAccessProcess, Ke386SetIoAccessMap
and PsLookupProcessByProcessId

На написание статьи меня подтолкнуло чтение Криса Касперски «Методы низкоуровневого управления приводами» и упомянутая в этой работе статья Dale Roberts от 01 мая 1996 «Direct Port I/O and Windows NT». Позже в KmdTutor by Four-F я нашел драйвер giveio, который используя функции Ke386SetIoAccessMap, Ke386QueryIoAccessMap и Ke386IoSetAccessProcess предоставлял доступ к портам ввода/вывода user-mode приложениям.

Теория


Считается, что в Windows NT/2k/XP прямое обращение к портам возможно только на уровне ядра, а приложения вынуждены общаться с портами через высокоуровневый интерфейс, предоставляемый драйвером. На самом деле, выполнять команды IN/OUT можно и на прикладном уровне, правда не без помощи недокументированных возможностей операционной системы и документированных, но малоизвестных особенностей реализации защищенного режима работы в процессорах Intel.
В «Instruction Set Reference» приведен псевдокод инструкций IN и OUT:
Code
1
2
3
4
5
6
7
8
9
10
11
IF ((PE = 1) and ((CPL > IOPL) or (VM = 1)))
    THEN (* Protected mode with CPL > IOPL or virtual-8086 mode *)
        IF (Any I/O Permission Bit for I/O port being accessed = 1)
            THEN (* I/O operation is not allowed *)
                #GP(0);
            ELSE ( * I/O operation is allowed *)
                DEST <- SRC; (* Read from selected I/O port *)
        FI;
    ELSE (* Real Mode or Protected Mode with CPL  <= IOPL *)
        DEST <- SRC; (* Read from selected I/O port *)
FI;
псевдокод инструкции IN
Code
1
2
3
4
5
6
7
8
9
10
11
IF ((PE = 1) and ((CPL > IOPL) or (VM = 1)))
    THEN (* Protected mode with CPL > IOPL or virtual-8086 mode *)
        IF (Any I/O Permission Bit for I/O port being accessed = 1)
            THEN (* I/O operation is not allowed *)
                #GP(0);
            ELSE ( * I/O operation is allowed *)
                DEST <- SRC; (* Writes to selected I/O port *)
        FI;
    ELSE (* Real Mode or Protected Mode with CPL <= IOPL *)
        DEST <- SRC; (* Writes to selected I/O port *)
FI;
псевдокод инструкции OUT

Обнаружив, что полномочий текущего уровня привилегий недостаточно для выполнения команды IN/OUT, процессор не спешит выбросить исключение general protection fault, а осуществляет дополнительную проверку на предмет состояния карты разрешения ввода/вывода (IOPM ― I/O Permission bitMap) и, если бит памяти, соответствующий данному порту равен нулю, то вывод в порт осуществляется несмотря на запрет со стороны CPL.
Таким образом, для взаимодействия с портами с прикладного уровня достаточно скорректировать карту разрешения ввода/вывода, после чего подсистема защиты операционной системы Windows NT перестает мешать, поскольку контроль доступа к портам осуществляется не на программном, а на аппаратном уровне и, если процессор перестанет выбрасывать исключения, операционная система ничего не узнает о происходящем.
Из «Architecture Software Developer's Manual Volume 1: Basic Architecture», узнаем, что карта ввода/вывода находится в сегменте состояния задачи (TSS ― Task State Segment), смещение IOPM относительно начала TSS определяется 32-битным полем, расположенном в 66h и 67h байтах сегмента состояния задачи. Нулевой бит карты IOPM отвечает за нулевой порт, первый - за первый, второй - за второй и т.д. вплоть до старшего бита 2000h-байта, отвечающего за 65535 порт. Битовую карту завершает так называемый байт-терминатор, имеющий значение 0FFh. Порты, чьи биты сброшены в нулевое значение, доступны с прикладного уровня без ограничений. Сама карта ввода/вывода доступа лишь драйверам, но не приложениям, поэтому без написания собственного драйвера не обойтись. Однако этот драйвер будет работать только на стадии инициализации, а весь дальнейший ввод/вывод пойдет напрямую, даже если выгрузить драйвер из памяти.
В Windows NT смещение карты ввода/вывода по умолчанию находится за пределами сегмента состояния задачи и потому модифицировать карту ввода/вывода не так-то просто. То есть карта ввода/вывода в TSS есть, но она заблокирована системой.
Попытка подкорректировать указатель на карту ввода/вывода ни к чему не приводит, поскольку Windows NT хранит копию этого значения в контексте процесса, а потому при переключении контекста указатель на прежнюю карту автоматически восстанавливается.
Можно увеличить размер сегмента состояния задачи так, чтобы адрес карты ввода/вывода, прежде указывающий за его конец, теперь приходился на подвластную нам область памяти. Поскольку в хвосте последней страницы, занятой TSS, имеется всего лишь 0F55h байт, максимальный размер карты, которую мы можем создать в этом промежутке, охватывает всего лишь 31392 портов ввода/вывода.
Дейлом Робертсом («Direct Port I/O and Windows NT» by Dale Roberts) были обнаружены три недокументированные функции: Ke386SetIoAccessMap, Ke386QueryIoAccessMap и Ke386IoSetAccessProcess, которые обеспечивают управление картой ввода/вывода. Эти функции находятся в NTOSKRNL.EXE и они доступы с уровня драйверов.

Функция Ke386SetIoAccessMap принимает два аргумента: dwFlag ― длинное целое, которое нужно установить в 1, чтоб функция работала, и pIopm ― указатель на буфер. Функция копирует переданную карту доступа к портам ввода/вывода длинной 2000h из буфера в TSS по смещению 88h.
Параметр Описание
dwFlag только 1 - разрешает копирование. При любом другом значении функция возвращает ошибку
pIopm указатель на блок памяти для приема IOPM, размером не менее 2000h байт.
Функция Ke386QueryIoAccessMap принимает те же аргументы, но делает прямопротивоположное, копируя текущую IOPM из TSS в буфер длинной 2000h. Если аргумент dwFlag установлен в 0, set-функция копирует в IOPM 0FFh, а query-функция копирует 0FFh в пользовательский буфер.

Параметр Описание
dwFlag 0 - заполнить буфер единичными битами (то есть запретить доступ ко всем портам);
 1 - скопировать текущую IOPM из TSS в буфер.
pIopm указатель на блок памяти для приема IOPM, размером не менее 2000h байт.
Функция Ke386IoSetAccessProcess принимает два аргумента: pProcess ― указатель на структуру процесса, полученный вызовом функции PsGetCurrentProcess и dwFlag ― целое, которое должно быть установлено в 1 чтобы разрешить доступ к портам ввода/вывода, или 0 чтоб запретить его. Когда аргумент dwFlag равен 0, функция запрещает доступ к портам ввода/вывода установкой смещения IOPM переданного процесса за границу сегмента TSS. Когда аргумент dwFlag равен 1, функция разрешает доступ к портам ввода/вывода, устанавливая смещение IOPM переданного процесса на начало IOPM по смещению 88h в TSS.

Параметр Описание
pProcess указатель на структуру KPROCESS
dwFlag 0 - запретить доступ к портам ввода-вывода, установкой смещения IOPM за границу сегмента TSS;
 1 - разрешить доступ к портам ввода-вывода, устанавливая смещение IOPM в пределах TSS равным 88h.
Используя set- и query- функции можно читать, изменять, и записывать обратно IOPM, предоставляя доступ к нужным портам, устанавливая соответствующие биты для них в 0.
Практика

Драйвер scp04 написан на основе драйвера giveio by Four-F, открывает порты ввода/вывода через изменение карты IOPM и использует функции Ke386SetIoAccessMap, Ke386QueryIoAccessMap, Ke386IoSetAccessProcess. Значение ProcessId драйвер получает через реестр. Использование драйвера scp04 позволяет одновременно использовать команду outsb и WinAPI функции пользовательского режима, например функцию Sleep. scp04 представляет собой неполнофункциональный драйвер, то есть самостоятельно только стартует и открывает порты ввода/вывода после чего возвращает код ошибки и система удаляет его из памяти.

Функции Ke386SetIoAccessMap, Ke386QueryIoAccessMap и Ke386IoSetAccessProcess это только «обертки» для функций вызываемых из hal.dll. Правда, как показала проверка, при запуске на Celeron 466 и на двухядерном Pentium 4 функции из hal.dll, заменяющие функции из ntoskernl.exe могут отличаться, я попытался найти компромиссное решение. В результате команды IN и OUT удалось поместить в user-mode приложение, что дает возможность «написания быстрой программы для взаимодействия с устройством, в которой printf()'ы и getchar()'ы чередовались бы с командами ввода/вывода» (Dale Roberts).

Далее исходный текст драйвера scp04.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
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
; masm windows native #
;написано на основе драйвера режима ядра giveio из KmdTutor by Four-F
.686
.model flat
 
include ntddk.inc
include Strings.mac
includelib ntoskrnl.lib
 
extern _imp__ZwQueryValueKey@24:dword
extern _imp__ZwOpenKey@12:dword
extern _imp__ZwClose@4:dword
extern _imp__MmAllocateNonCachedMemory@4:dword
extern _imp__PsLookupProcessByProcessId@8:dword
extern _imp__ObDereferenceObject@4:dword
extern _imp__MmFreeNonCachedMemory@8:dword
extern _imp__Ke386SetIoAccessMap@8:dword
extern _imp__Ke386QueryIoAccessMap@8:dword
extern _imp__Ke386IoSetAccessProcess@8:dword
;--------------------------------------------
IOPM_SIZE equ 2000h ; sizeof I/O permission map
.const
CCOUNTED_UNICODE_STRING "ProcessId", cusProcessid, 4
;--------------------------------------------
.code
;--------------------------------------------
DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING
 
local status:NTSTATUS
local oa:OBJECT_ATTRIBUTES
local hKey:HANDLE
local kvpi:KEY_VALUE_PARTIAL_INFORMATION
local pIopm:PVOID
local pProcess:PVOID
 
    xor ebx,ebx 
    mov status, STATUS_DEVICE_CONFIGURATION_ERROR 
;Для последующего вызова функции ZwOpenKey нам потребуется указатель на 
;заполненную структуру OBJECT_ATTRIBUTES 
    lea ecx, oa
        mov (OBJECT_ATTRIBUTES ptr [ecx])._Length,sizeof(OBJECT_ATTRIBUTES)
    mov (OBJECT_ATTRIBUTES ptr [ecx]).RootDirectory,ebx
    push pusRegistryPath
    pop (OBJECT_ATTRIBUTES ptr [ecx]).ObjectName
    mov (OBJECT_ATTRIBUTES ptr [ecx]).Attributes,ebx
    mov (OBJECT_ATTRIBUTES ptr [ecx]).SecurityDescriptor,ebx
    mov (OBJECT_ATTRIBUTES ptr [ecx]).SecurityQualityOfService,ebx
;Вызовом функции ZwOpenKey получаем описатель раздела реестра в переменной 
;hKey. Вторым параметром в эту функцию передаются права доступа, третьим - 
;указатель на структуру OBJECT_ATTRIBUTES, заполненную на предыдущем этапе.
    push ecx
    push KEY_READ
    lea eax,hKey
    push eax
    call _imp__ZwOpenKey@12
    test eax,eax
    jnz a7;.if eax == STATUS_SUCCESS
;С помощью функции ZwQueryValueKey получаем значение идентификатора 
;процесса, записанное в параметре реестра ProcessId. Вторым параметром 
;в эту функцию передается указатель на инициализированную структуру 
;UNICODE_STRING, содержащую имя параметра реестра, значение которого мы 
;хотим получить. Третий параметр функции ZwQueryValueKey определяет тип 
;запрашиваемой информации. KeyValuePartialInformation - символьная константа 
;равная 2. Четвертый и пятый параметры - указатель на структуру 
;KEY_VALUE_PARTIAL_INFORMATION и ее размер соответственно. В члене Data этой 
;структуры мы и получим значение идентификатора процесса. Последний параметр 
;указатель на переменную, размером DWORD, в которую будет записано количество 
;скопированных из реестра байт. Перед самым вызовом ZwQueryValueKey, мы 
;резервируем на стеке для него место, а после вызова извлекаем значение
        push eax
    push esp
    push sizeof(KEY_VALUE_PARTIAL_INFORMATION)
    lea eax,kvpi
    push eax
    push KeyValuePartialInformation
    push offset cusProcessid
    push hKey
    call _imp__ZwQueryValueKey@24
    pop ecx
    cmp eax,STATUS_OBJECT_NAME_NOT_FOUND
    je a6
    test ecx,ecx
    je a6;.if ( eax != STATUS_OBJECT_NAME_NOT_FOUND ) && ( ecx != 0 )
;Если вызов ZwQueryValueKey прошел успешно, выделяем с помощью функции 
;MmAllocateNonCachedMemory кусок памяти размером 2000h байт - максимальный 
;размер карты разрешения ввода-вывода. Сохраняем указатель в переменной pIopm
    push IOPM_SIZE
    call _imp__MmAllocateNonCachedMemory@4
    xchg eax,ecx
    jecxz a5;if eax != NULL
    mov pIopm,ecx
;Передавая в функцию PsLookupProcessByProcessId полученный ранее идентификатор 
;процесса, получаем указатель на KPROCESS в переменной pProcess
        lea ecx,kvpi
    lea eax,pProcess
    push eax
    push dword ptr (KEY_VALUE_PARTIAL_INFORMATION PTR [ecx]).Data
    call _imp__PsLookupProcessByProcessId@8
    test eax,eax
    jnz short a3;.if eax == STATUS_SUCCESS
;Копируем текущую IOPM размером 2000h из TSS в буфер, указатель на который 
;содержится в параметре pIopm
    push pIopm
    push ebx;0
    call _imp__Ke386QueryIoAccessMap@8
    test al,al
    jz short a1;.if al != 0
;Открываем доступ к портам 42h, 43h, 61h. Сбрасываем биты соответствующие 
;этим портам ввода-вывода и записываем модифицированную IOPM.
    mov ecx,pIopm
    and byte ptr [ecx + 42h/8],not(1 shl (42h MOD 8) or (1 shl (43h MOD 8))); I/O access for 42h & 43h port
    and byte ptr [ecx + 61h/8],not(1 shl (61h MOD 8)); I/O access for 61h port
;Копируем переданную IOPM длинной 2000h из буфера, указатель на который 
;содержится в параметре pIopm, в TSS
    push ecx;pIopm
    push 1
    call _imp__Ke386SetIoAccessMap@8; Set modified IOPM
    test al,al; If second parameter to Ke386IoSetAccessProcess is 1, 
    jz short a1;the process is given I/O access. If it is 0, access is removed.
;Разрешаем/запрещаем использование IOPM для процесса. Если второй параметр
;равен 1 разрешаем доступ к портам ввода-вывода, устанавливаем смещение 
;IOPM в пределах TSS равным 88h.
    push 1
    push pProcess
    call _imp__Ke386IoSetAccessProcess@8
    test al,al
    jnz short a2
a1: mov status,STATUS_IO_PRIVILEGE_FAILED
;Предыдущий вызов функции PsLookupProcessByProcessId, увеличил количество 
;ссылок на обьект "процесс". Система раздельно хранит количество открытых 
;описателей обьекта и количество предоставленных ссылок на объект. 
;Описателями, в основном, пользуется код режима пользователя, ссылками - 
;только код режима ядра. Пока, хотя бы одно из этих значений, не равно нулю, 
;система не удаляет объект из памяти, считая что он еще используется 
;каким-то кодом. Вызовом функции ObDereferenceObject мы уменьшаем количество 
;ссылок на обьект процесса.
a2: push pProcess
    call _imp__ObDereferenceObject@4
    jmp short a4
a3: mov status,STATUS_OBJECT_TYPE_MISMATCH
;С помощью функции MmFreeNonCachedMemory освобождаем выделенный буфер
a4: push IOPM_SIZE
    push pIopm
    call _imp__MmFreeNonCachedMemory@8
    jmp short a6
a5: mov status, STATUS_INSUFFICIENT_RESOURCES
;вызовом функции ZwClose закрываем описатель раздела реестра
a6: push hKey
    call _imp__ZwClose@4
;Т.к. драйвер возвращает один из кодов ошибки, система удаляет его из памяти.
;а user-mode программа получила доступ к 42h, 43h, 61h портам ввода-выводаv
a7: mov eax, status
    leave
    retn 8
DriverEntry endp
 
end DriverEntry
Первый вариант user-mode приложения, которое запускает драйвер scp04.sys

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

Перед запуском драйвера, мы создаем в подразделе реестра, соответствующем драйверу, дополнительный параметр ProcessId, и устанавливаем его значение равным идентификатору текущего процесса, то есть процесса программы управления. Если добавление параметра прошло без ошибок, то запускаем драйвер. Получив управление от функции StartService, мы считаем, что драйвер успешно отработал и устанавливаем флаг fOK. Вызов функции RegDeleteValue делать не обязательно. Все равно, весь раздел реестра будет удален последующим вызовом DeleteService. Удаляем драйвер из базы данных 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
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
; masm windows gui #
.686P
.model flat;, stdcall
 
include windows.inc
includelib kernel32.lib
includelib user32.lib
includelib advapi32.lib
 
extern _imp__ExitProcess@4:dword 
extern _imp__OpenSCManagerA@12:dword
extern _imp__GetFullPathNameA@16:dword
extern _imp__CreateServiceA@52:dword
extern _imp__MessageBoxA@16:dword
extern _imp__CloseServiceHandle@4:dword
extern _imp__DeleteService@4:dword
extern _imp__RegCloseKey@4:dword
extern _imp__RegDeleteValueA@8:dword
extern _imp__StartServiceA@12:dword
extern _imp__RegSetValueExA@24:dword
extern _imp__GetCurrentProcessId@0:dword
extern _imp__RegOpenKeyExA@20:dword
extern _imp__Sleep@4:dword
 
.code
start proc
 
local fOK:BOOL
local hSCManager:HANDLE
local hService:HANDLE
local acDriverPath[MAX_PATH]:CHAR
local hKey:HANDLE
local dwProcessId:DWORD
    xor esi,esi
    xor ebx,ebx
        mov edi,offset Drvname
    and fOK,ebx     ; assume an error
    ; Open a handle to the SC Manager database
        push SC_MANAGER_CREATE_SERVICE
    push ebx;NULL 
    push ebx;NULL 
    call _imp__OpenSCManagerA@12
    test eax,eax;.if eax != NULL
    je a1
    mov hSCManager, eax
    push eax
    push esp
    lea eax,acDriverPath
    push eax
    push MAX_PATH;sizeof acDriverPath
    push edi 
    call _imp__GetFullPathNameA@16
        pop eax
    ; Register driver in SCM active database
        mov [edi+5],ebx
    push ebx;NULL
    push ebx;NULL 
    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;offset nice_melody 
    push edi;offset beeper_name
    push hSCManager
    call _imp__CreateServiceA@52
    test eax,eax    ;.if eax != NULL
    jz a2
    mov hService, eax
        lea ecx,hKey
    push ecx
    push KEY_CREATE_SUB_KEY + KEY_SET_VALUE
    push ebx 
    push offset scp04_path
    push HKEY_LOCAL_MACHINE
    call _imp__RegOpenKeyExA@20                         
    test eax,eax;.if eax == ERROR_SUCCESS
    jne a3
    call _imp__GetCurrentProcessId@0
    mov dwProcessId, eax
        push sizeof DWORD
    lea ecx,dwProcessId
    push ecx
    push REG_DWORD
    push ebx
    push offset szProcessId
    push hKey
    call _imp__RegSetValueExA@24
    test eax,eax;.if eax == ERROR_SUCCESS
    jne @f
        push ebx
    push ebx
    push hService
    call _imp__StartServiceA@12
    inc fOK ; set flag
        lea ecx,szProcessId
    push ecx
    push hKey
    call _imp__RegDeleteValueA@8
    jmp short a5;.else
@@: push MB_ICONSTOP
    push ebx;NULL 
    push offset can_t_add
    push ebx;NULL
    call _imp__MessageBoxA@16
a5: push hKey
    call _imp__RegCloseKey@4
    jmp short a6;.else
a3:     push MB_ICONSTOP
    push ebx;NULL 
    push offset can_t_open
    push ebx;NULL
    call _imp__MessageBoxA@16 
; Remove driver from SCM database
a6: push hService
    call _imp__DeleteService@4
    push hService
    call _imp__CloseServiceHandle@4
    jmp short a7;.else
a2:     push MB_ICONSTOP
    push ebx;NULL 
    push offset can_t_register
    push ebx;NULL
    call _imp__MessageBoxA@16 
a7: push hSCManager
    call _imp__CloseServiceHandle@4
    jmp short a8;.else
a1:     push MB_ICONSTOP
    push ebx;NULL
    push offset can_t_connect
    push ebx;NULL
    call _imp__MessageBoxA@16 
a8: cmp fOK,ebx
    je a9
    in al,61h
    mov al,4Fh
    out 61h,al
    mov al,0B6h
    out 43h, al
        mov esi,offset melody; данные
    mov ecx,size_melody  ; счетчик
    mov dx,42h 
@@: push edx   
    push ecx   
    push 40    ; задержка в 40 мСек
    call _imp__Sleep@4
    pop ecx   
    pop edx ;Команда OUTS выводит данные в порт ввода-вывода,
    outsb   ;номер которого загружен в регистр DX,
    loop @b ;из ячейки памяти по адресу DS:ESI
    mov al,4Dh 
    out 61h,al
a9:     push ebx
    call _imp__ExitProcess@4
start endp
;данные--------------------------------
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),2,2
    dw 5EEh,2,5EEh,2,4 dup(649h),4 dup(5EEh),2 dup(472h),2,2,5EEh
    dw 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
Drvname     db "scp04.sys",0
can_t_connect   db "Can't connect to Service Control Manager.",0
can_t_register  db "Can't register driver.",0
can_t_open  db "Can't open registry.",0
can_t_add   db "Can't add Process ID into registry.",0
szProcessId db "ProcessId",0
scp04_path  db "SYSTEM\CurrentControlSet\Services\scp04",0
end start
Второй вариант user-mode приложения, которое запускает драйвер scp04.sys

Предварительно прописываем драйвер scp04.sys в реестре «вручную» (используем функции RegOpenKey, RegCreateKey, RegSetValue) и загружаем драйвер scp04.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
; 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__RegCloseKey@4:dword
extern _imp__SHDeleteKeyA@8:dword
extern _imp__RegSetValueExA@24:dword
extern _imp__GetCurrentProcessId@0:dword
extern _imp__RegOpenKeyA@12:dword
extern _imp__RegCreateKeyA@12:dword
extern _imp__Sleep@4: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\scp04>
len_us = $-us
align 4
cusDevice dw (len_us - 2)
          dw (len_us)
      dd us
 
.code
 
start proc
local Key2:HANDLE
local Key:HANDLE
local acDriverPath[MAX_PATH]:CHAR
 
    xchg eax,ebx
        mov esi,offset scp04_sys_name
        lea edi,acDriverPath
        mov eax,'\??\'
    stosd;путь к драйверу должен начаться с '\??\'
    push eax
    push esp    
    push edi;&acDriverPath+4
        sub edi,4
    push MAX_PATH;sizeof acDriverPath
    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
        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
    call _imp__GetCurrentProcessId@0
    mov ecx,esp
        push sizeof(dword)
    mov [ecx],eax;dwProcessId, eax
    push ecx
    push REG_DWORD
    push ebx
    push offset szProcessId
    push Key2
    call _imp__RegSetValueExA@24
        push Key2
    call _imp__RegCloseKey@4
    mov [esp],offset cusDevice
    call _imp__ZwLoadDriver@4 
        push offset cusDevice
    call _imp__ZwUnloadDriver@4
        push esi;'scp04' 
    push Key
    call _imp__SHDeleteKeyA@8
    push Key
    call _imp__RegCloseKey@4
    in al,61h
    or al,00000011b
    out 61h,al
    mov al,0B6h
    out 43h, al
        mov esi,offset melody; данные
    mov ecx,size_melody  ; счетчик
    mov dx,42h 
@@: push edx   
    push ecx   
    push 40    ; задержка в 40 мСек
    call _imp__Sleep@4
    pop ecx   
    pop edx
    outsb 
    loop @b
    in al,61h
    and al,11111100b 
    out 61h,al
    push ebx
    call _imp__ExitProcess@4
start endp
;данные---------------------------------------------------
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),2
    dw 2,5EEh,2,5EEh,2,4 dup(649h),4 dup(5EEh),2 dup(472h),2,2,5EEh
    dw 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
scp04_sys_name  db "scp04.sys",0
szProcessId db "ProcessId",0
aSystem     db "SYSTEM\CurrentControlSet\Services",0
aType       db "Type",0
aImagePath  db "ImagePath",0
end start
_________________
© Mikl___ 2011
8
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16355 / 7671 / 1078
Регистрация: 11.11.2010
Сообщений: 13,734
19.10.2012, 04:01
Доступ к командам In/Out через изменение карты IOPM

Драйвер giveio.sys отработав, возвращает один из кодов ошибки, система удаляет его из памяти, но теперь, любое user-mode приложение имеет доступ к трем портам ввода-вывода до тех пор, пока вы не перезагрузите компьютер. Это дает возможность запускать приложения написанные под DOS или Wind95/98, но всёравно не очень безопасно. Драйвер, написанный по мотивам kernel-mode драйвера PortTalk 2.0 by Craig Peacock, предоставляет доступ к портам 42h, 43h и 61h только тому процессу, который вызывает этот драйвер, а перед выгрузкой из памяти драйвер восстанавливает карту IOPM.

Открывает порты IOPM и использует Ke386SetIoAccessMap, Ke386QueryIoAccessMap, Ke386IoSetAccessProcess. ProcessId получает через DeviceIoControl. Сочетание команд outsb и UserMode-WinAPI функции Sleep. Полнофункциональный драйвер.

Далее исходный текст драйвера scp05.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
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
; masm windows native #
;написано на основе драйвера режима ядра PortTalk 2.0 by Craig Peacock
.686P
.model flat
;---------------------------------------------------------------------------
include ntddk.inc
include ntstatus.inc
include w2kundoc.inc
include Strings.mac
includelib ntoskrnl.lib
includelib hal.lib
;---------------------------------------------------------------------------
extern _imp__IoCreateDevice@28:dword
extern _imp__IoCreateSymbolicLink@8:dword
extern _imp__IoDeleteDevice@4:dword
extern _imp__IoDeleteSymbolicLink@4:dword
extern _imp__MmAllocateNonCachedMemory@4:dword
extern _imp__MmFreeNonCachedMemory@8:dword
extern _imp__Ke386SetIoAccessMap@8:dword
extern _imp_@IofCompleteRequest@8:dword
extern _imp__PsLookupProcessByProcessId@8:dword
extern _imp_@KfLowerIrql@4:dword
extern _imp__KeRaiseIrqlToSynchLevel@0:dword
;---------------------------------------------------------------------------
IOPM_SIZE equ 2000h             ; sizeof I/O permission map
IOCTL_IOPM_RESTRICT_ALL_ACCESS      equ 9C402400h
IOCTL_ENABLE_IOPM_ON_PROCESSID      equ 9C40240Ch
;---------------------------------------------------------------------------
.const
CCOUNTED_UNICODE_STRING "\\Device\\scp05", cusDevice, 4
CCOUNTED_UNICODE_STRING "\\DosDevices\\scp05", cusSymbolicLink, 4
;---------------------------------------------------------------------------
.code
;---------------------------------------------------------------------------
CreateDispatch proc 
lpIrp        equ dword ptr [esp+8];:PIRP
                
    mov ecx,lpIrp
    xor edx,edx
    mov (_IRP PTR [ecx]).IoStatus.Information,edx;Irp->IoStatus.Information = 0;
    mov (_IRP PTR [ecx]).IoStatus.Status,edx;Irp->IoStatus.Status = STATUS_SUCCESS
    call _imp_@IofCompleteRequest@8;IoCompleteRequest(Irp, IO_NO_INCREMENT)
    xor eax,eax;return STATUS_SUCCESS
    retn 8
CreateDispatch endp
;---------------------------------------------------------------------------
DriverEntry proc DriverObject:PDRIVER_OBJECT, RegistryPath:PUNICODE_STRING
local deviceObject:PDEVICE_OBJECT
 
    push esi
    push IOPM_SIZE
    call _imp__MmAllocateNonCachedMemory@4;IOPM_local = MmAllocateNonCachedMemory(sizeof(IOPM))
    test eax,eax
    jz @f
    mov IOPM_local,eax
;---------------------------------------------------------------------------
    lea ecx,deviceObject
    push ecx;&deviceObject
    push 0;FALSE
    push 0
    push FILE_DEVICE_UNKNOWN;22h
    push offset cusDevice;eax;&uniNameString
    push 0                  ;for IoCreateDevice
    mov esi,DriverObject
    push esi;DriverObject
    call _imp__IoCreateDevice@28;status = IoCreateDevice(DriverObject, 
; 0, &uniNameString, FILE_DEVICE_UNKNOWN, 0, FALSE, &deviceObject)
    test eax,eax
    jl short a0;if(!NT_SUCCESS(status)) return status
    push offset cusDevice
    push offset cusSymbolicLink
    call _imp__IoCreateSymbolicLink@8;status = IoCreateSymbolicLink (&uniDOSString, &uniNameString)
    test eax,eax
    jl short a0;if (!NT_SUCCESS(status)) return status
    mov (DRIVER_OBJECT PTR [esi]).MajorFunction[IRP_MJ_CREATE*4],offset CreateDispatch  
    mov (DRIVER_OBJECT PTR [esi]).MajorFunction[IRP_MJ_DEVICE_CONTROL*4],offset DeviceControl   
    mov (DRIVER_OBJECT PTR [esi]).DriverUnload,offset DriverUnload
    xor eax,eax;return STATUS_SUCCESS
    jmp short a0
@@:     mov eax,STATUS_INSUFFICIENT_RESOURCES;return STATUS_INSUFFICIENT_RESOURCES
a0: pop esi
    leave
    retn 8
DriverEntry endp
;---------------------------------------------------------------------------
DeviceControl proc pDeviceObject,pIrp
 
Process     equ dword ptr [ebp+0Ch]
 
    push esi
    push edi
    mov esi,Process
; eax = irpSp  esi = pIrp  edi = ioBuffer  ecx = inBufLength
    mov eax,(_IRP PTR [esi]).Tail.Overlay.CurrentStackLocation;irpSp = IoGetCurrentIrpStackLocation( pIrp )
    mov edi,(_IRP PTR [esi]).AssociatedIrp.SystemBuffer;ioBuffer = pIrp->AssociatedIrp.SystemBuffer
        mov ecx,(IO_STACK_LOCATION ptr [eax]).Parameters.DeviceIoControl.InputBufferLength;inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength
;switch ( irpSp->Parameters.DeviceIoControl.IoControlCode )
    mov eax,(IO_STACK_LOCATION ptr [eax]).Parameters.DeviceIoControl.IoControlCode
    sub eax,IOCTL_IOPM_RESTRICT_ALL_ACCESS
    jz @IOCTL_IOPM_RESTRICT_ALL_ACCESS
    sub eax,IOCTL_ENABLE_IOPM_ON_PROCESSID-IOCTL_IOPM_RESTRICT_ALL_ACCESS; 9C40240Ch
    jz short @IOCTL_ENABLE_IOPM_ON_PROCESSID
default: and (_IRP PTR [esi]).IoStatus.Information, 0;pIrp->IoStatus.Information = 0
    mov edi,STATUS_UNSUCCESSFUL; ntStatus = STATUS_UNSUCCESSFUL;
    jmp break
;--------------------------------------------------------------------------- 
@IOCTL_ENABLE_IOPM_ON_PROCESSID:
    cmp ecx,4 ;if (inBufLength >= 4) 
    jb short @f
    lea eax,Process
    push eax;&Process
    push dword ptr [edi];ProcessID
    call _imp__PsLookupProcessByProcessId@8
;Открываем доступ к портам 42h, 43h, 61h. Сбрасываем биты соответствующие 
;этим портам ввода-вывода и записываем модифицированную IOPM.
        mov ecx,IOPM_local
    and byte ptr [ecx + 42h/8],not((1 shl (42h MOD 8)) or (1 shl (43h MOD 8))); I/O access for 42h and 43h ports
    and byte ptr [ecx + 61h/8],not (1 shl (61h MOD 8)); I/O access for 61h port
    push ecx;IOPM_local
    push 1
    call _imp__Ke386SetIoAccessMap@8;Ke386SetIoAccessMap(1, IOPM_local)
;Разрешаем использование IOPM для процесса. Устанавливаем смещение 
;IOPM в пределах TSS равным 88h.
    call _imp__KeRaiseIrqlToSynchLevel@0
    mov cl,al
    mov eax,Process
    mov edx,(KPROCESS ptr [eax]).ActiveProcessors
    mov (KPROCESS ptr [eax]).IopmOffset,88h
    mov eax,ds:0FFDFF020h
    test [eax+14h],edx
    jz short @f
    mov eax,ds:0FFDFF040h
    mov word ptr [eax+66h],88h
@@: call _imp_@KfLowerIrql@4
    jmp short @f
;---------------------------------------------------------------------------
@IOCTL_IOPM_RESTRICT_ALL_ACCESS:
    mov ecx,IOPM_SIZE/4
    or eax,-1
    mov edi,IOPM_local
    rep stosd;RtlFillMemory(IOPM_local, sizeof(IOPM), 0xFF)
@@:     xor edi,edi;ntStatus = STATUS_SUCCESS
    mov (_IRP PTR [esi]).IoStatus.Information,edi;pIrp->IoStatus.Information = 0; /* Output Buffer Size */  
break:  xor edx,edx; edx = IO_NO_INCREMENT 
    mov ecx,esi
    mov (_IRP PTR [esi]).IoStatus.Status,edi;pIrp->IoStatus.Status = ntStatus
    call _imp_@IofCompleteRequest@8;IoCompleteRequest( pIrp, IO_NO_INCREMENT )
    mov eax,edi;return ntStatus
    pop edi
    pop esi
    leave
    retn 8
DeviceControl endp
;---------------------------------------------------------------------------
DriverUnload:
DriverObject    equ dword ptr [esp+4];:PDRIVER_OBJECT
 
    mov eax,IOPM_local
    test eax,eax
    jz @f
    push IOPM_SIZE
    push eax
    call _imp__MmFreeNonCachedMemory@8;if(IOPM_local) MmFreeNonCachedMemory(IOPM_local, sizeof(IOPM))
@@: push offset cusSymbolicLink;eax;&uniDOSString
    call _imp__IoDeleteSymbolicLink@4;IoDeleteSymbolicLink (&uniDOSString)
    mov eax,DriverObject
    push dword ptr (DRIVER_OBJECT ptr [eax]).DeviceObject
    call _imp__IoDeleteDevice@4;IoDeleteDevice(DriverObject->DeviceObject)
    retn 4
;---------------------------------------------------------------------------
.data
IOPM_local  dd 0
end DriverEntry
Первый вариант user-mode приложения, которое запускает драйвер scp05.sys

user-mode приложение, которое запускает scp05.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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
; 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__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__CreateFileA@28:dword
extern _imp__CloseHandle@4:dword
extern _imp__GetCurrentProcessId@0:dword
extern _imp__GetLastError@0:dword
extern _imp__DeviceIoControl@32:dword
extern _imp__DeleteService@4:dword
extern _imp__ControlService@12:dword
extern _imp__QueryServiceStatus@8:dword
 
ascp05 equ  a_scp05+4
 
IOCTL_IOPM_RESTRICT_ALL_ACCESS      equ 9C402400h
IOCTL_IOPM_ALLOW_EXCUSIVE_ACCESS    equ 9C402404h
IOCTL_ENABLE_IOPM_ON_PROCESSID      equ 9C40240Ch
 
.code
 
 
start   proc
local   scp05_Handle:HANDLE
local   SchSCManager:SC_HANDLE  
local   schService:SC_HANDLE  ;
local   acDriverPath[MAX_PATH]:byte
 
    xor ebx,ebx;ebx:=0
;Install scp05 Driver
    push eax
    push esp
    lea edi,acDriverPath
    push edi
    push MAX_PATH
    push offset ascp05
    call _imp__GetFullPathNameA@16
        pop eax
 
;Open Handle to Service Control Manager 
        push SC_MANAGER_ALL_ACCESS;access required
    push ebx;lpDatabaseName (NULL == default)
    push ebx;lpMachineName (NULL == local)
    call _imp__OpenSCManagerA@12 ; Establish a connection to the service
; control manager on the specified computer and opens the specified database               
    mov SchSCManager,eax
 
;Create Service/Driver - This adds the appropriate registry keys in 
;HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services - It doesn't  
;care if the driver exists, or if the path is correct.              
    push ebx; lpPassword == NULL no password
    push ebx; lpServiceStartName == NULL LocalSystem account
    push ebx; lpDependencies == NULL no dependencies
    push ebx; lpdwTagId == NULL no tag identifier
    push ebx; lpLoadOrderGroup == NULL no load ordering group
    push edi; lpBinaryPathName
 
    push SERVICE_ERROR_NORMAL;1 ; dwErrorControl error control type
    push SERVICE_DEMAND_START;3 ; dwStartType    start type
    push SERVICE_KERNEL_DRIVER;1; dwServiceType  service type
    push SERVICE_ALL_ACCESS; dwDesiredAccess     desired access
    mov ecx, offset ascp05 ;    "scp05"      name to display and name of service
    mov [ecx+5],ebx; делаю из "\\.\scp05.sys" "\\.\scp05"
    push ecx; lpDisplayName         name to display = scp05
    push ecx; lpServiceName         name of service = scp05
    push SchSCManager; hSCManager            SCManager database
    call _imp__CreateServiceA@52
        mov edi,_imp__GetLastError@0
    mov esi,_imp__MessageBoxA@16
 
    mov schService,eax;    schService = CreateService (,,,,,)
    test eax,eax
    jnz short a12
    call edi;_imp__GetLastError@0
    cmp eax,ERROR_SERVICE_EXISTS;431h
    push ebx;0
    push ebx;0
    jnz short a8
    push offset err1 ; "Driver already exists. No action taken"
    jmp short a10
; ---------------------------------------------------------------------------
a8: push offset err2 ; "Unknown error while creating Service"
a10:    push ebx;0
    call esi;_imp__MessageBoxA@16
; ---------------------------------------------------------------------------
a12:    push offset Status
    push schService
    call _imp__QueryServiceStatus@8
;Start the scp05 Driver. Errors will occur here if scp05.SYS file doesn't exist */
    push ebx;pointer to arguments
    push ebx;number of arguments
    push schService;service identifier
    call _imp__StartServiceA@12
    test eax,eax
    jnz a9
    call edi ; GetLastError
    cmp eax,ERROR_SERVICE_ALREADY_RUNNING   
    push ebx; if (err == ERROR_SERVICE_ALREADY_RUNNING)
    push ebx;print("The driver is already running")
        jnz a7
    push offset err3; "The driver is already running"
    jmp short a3
;-------------------------------------------------------------------------
a7: push offset err4;"Unknown error while starting driver service"
a3: push ebx
    call esi;_imp__MessageBoxA@16
;Then try to open once more, before failing
a9: push ebx        ; hTemplateFile
    push FILE_ATTRIBUTE_NORMAL; dwFlagsAndAttributes
    push OPEN_EXISTING  ; dwCreationDisposition
    push ebx        ; lpSecurityAttributes
    push ebx        ; dwShareMode
    push GENERIC_READ   ; dwDesiredAccess
    push offset a_scp05 ; "\\\\.\\scp05"; lpFileName
    call _imp__CreateFileA@28
    inc eax;cmp eax,INVALID_HANDLE_VALUE
    jnz a1
a2: push ebx;if(scp05_Handle == INVALID_HANDLE_VALUE) 
    push ebx;print("Couldn't access driver, please ensure driver is loaded"
    push offset err5
    push ebx
    call esi;_imp__MessageBoxA@16
    jmp a0
a1: dec eax
    mov scp05_Handle,eax
;Once we have successfully opened a handle to the scp05 Driver, we must 
;fill the driver's IOPM with 0xFF to restrict access to all ports */
    mov edi,_imp__DeviceIoControl@32
    push ebx        ; lpOverlapped
    push offset BytesReturned; lpBytesReturned
    push ebx        ; nOutBufferSize
    push ebx        ; lpOutBuffer
    push ebx        ; nInBufferSize
    push ebx        ; lpInBuffer
    push IOCTL_IOPM_RESTRICT_ALL_ACCESS; dwIoControlCode
    push eax;scp05_Handle   ; hDevice
    call edi;_imp__DeviceIoControl@32
    call _imp__GetCurrentProcessId@0
    mov pi.dwProcessId,eax
    push ebx        ; lpOverlapped
    push offset BytesReturned; lpBytesReturned
    push ebx        ; nOutBufferSize
    push ebx        ; lpOutBuffer
    push 4      ; nInBufferSize
    push offset pi.dwProcessId  ; lpInBuffer
    push IOCTL_ENABLE_IOPM_ON_PROCESSID; dwIoControlCode
    push scp05_Handle   ; hDevice
    call edi;_imp__DeviceIoControl@32
;----------------------------------------------------------------------------
    push 1   ; задержка чтобы драйвер успел отработать
    mov edi,_imp__Sleep@4
    call edi;_imp__Sleep@4
;-----------------------------------------------------------------------
        in al,61h;текущее состояние порта 61h в AL
    or al,00000011b;установить биты 0 и 1 в 1
    out 61h,al ;теперь динамик включен
    mov al,0B6h
    out 43h,al  
    mov esi,offset melody; данные 
    mov ecx,size_melody  ; счетчик
    mov dx,42h ;Timer 8253-5 (AT: 8254.2).
@@: push edx   
    push ecx   
    push 40    ; задержка в 40 мСек
    call edi;_imp__Sleep@4     
    pop ecx   
    pop edx   ;Команда выводит данные в порт ввода-вывода, 
    outsb     ;номер которого загружен в регистр DX, 
    loop @b  ;из ячейки памяти по адресу DS:ESI
    in al,61h
    and al,11111100b;теперь динамик выключен
    out 61h,al
;-----------------------------------------------------------            
    mov edi,_imp__MessageBoxA@16
        push scp05_Handle   ; hObject
    call _imp__CloseHandle@4; CloseHandle(scp05_Handle)
; ---------------------------------------------------------------------------
    push offset Status      ; lpServiceStatus
    push SERVICE_CONTROL_STOP   ; dwControl
    push schService         ; hService
    call _imp__ControlService@12 ; Send a control code to a Win32 service   
    test eax,eax
    jnz short a5
; ---------------------------------------------------------------------------
    push ebx
    push ebx
    push offset err6; "Unknown error while stopping driver service"
    push ebx
    call edi;_imp__MessageBoxA@16
a5: push schService;esi
    call _imp__DeleteService@4
    push ebx
    push ebx
    test eax,eax
    jnz short a4
; ---------------------------------------------------------------------------
    push ebx
    push ebx
    push offset err7; "Error removing driver service - driver hasn't been successfully removed"
    push ebx
    call edi;_imp__MessageBoxA@16
a4: mov edi,_imp__CloseServiceHandle@4 
    push SchSCManager   ; hSCObject
    call edi;_imp__CloseServiceHandle@4
; Close handle to Service Control Manager
    push schService ; hSCObject
    call edi;_imp__CloseServiceHandle@4 
a0: push ebx
    call _imp__ExitProcess@4
start endp
;----------------------------------------------------------------
.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
;----------------------------------------------------------------
BytesReturned dd ?
pi PROCESS_INFORMATION <>;   /* Process Info Structure - Contains Process ID Information
Status  SERVICE_STATUS <>
a_scp05 db "\\.\scp05.sys",0
err1    db "Driver already exists. No action taken",0
err2    db "Unknown error while creating Service",0
err3    db "Driver is already running",0
err4    db "Unknown error while starting driver service",0
err5    db "Couldn't access Driver, please ensure driver is loaded",0
err6    db "Unknown error while stopping driver service",0
err7    db "Error removing driver service - Driver hasn't been successfully removed",0
end start
Второй вариант user-mode приложения, которое запускает драйвер scp05.sys

Предварительно прописываем драйвер scp05.sys в реестре "вручную" (используем функции RegOpenKey, RegCreateKey, RegSetValue) и загружаем драйвер scp05.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__CloseHandle@4:dword
extern _imp__GetCurrentProcessId@0:dword
extern _imp__DeviceIoControl@32: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
 
 
IOCTL_IOPM_RESTRICT_ALL_ACCESS      equ 9C402400h
IOCTL_IOPM_ALLOW_EXCUSIVE_ACCESS    equ 9C402404h
IOCTL_ENABLE_IOPM_ON_PROCESSID      equ 9C40240Ch
;--------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\scp05>
len_us = $-us
align 4
cusDevice dw (len_us - 2)
          dw (len_us)
      dd us
.code
 
 
start   proc
local   scp05_Handle:HANDLE
local   Key2:HKEY
local   Key:HKEY
local   acDriverPath[MAX_PATH]:byte
 
    xor ebx,ebx;ebx:=0
    mov esi,offset a_scp05+4
    lea edi,acDriverPath
        mov eax,'\??\'
    stosd;путь к драйверу должен начаться с '\??\'
;Install scp05 Driver
    push eax
    push esp
    push edi
    sub edi,4
    push MAX_PATH
    push esi;&ascp05
    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; делаю из "\\.\scp05.sys" "\\.\scp05"
        lea eax,Key2
    push eax
    push esi
    push Key
    call _imp__RegCreateKeyA@12
    push edi
    push REG_SZ
    push ebx;0
    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
    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; выравниваем стек после GetFullPathNameA
    sub esi,4;&esi='\\.\scp05',0
;Then try to open once more, before failing
a9: push ebx        ; hTemplateFile
    push FILE_ATTRIBUTE_NORMAL; dwFlagsAndAttributes
    push OPEN_EXISTING  ; dwCreationDisposition
    push ebx        ; lpSecurityAttributes
    push ebx        ; dwShareMode
    push GENERIC_READ   ; dwDesiredAccess
    push esi ; "\\\\.\\scp05"; lpFileName
    call _imp__CreateFileA@28
    inc eax;cmp eax,INVALID_HANDLE_VALUE
    je short a0
a1: dec eax
    mov scp05_Handle,eax
;Once we have successfully opened a handle to the scp05 Driver, we must 
;fill the driver's IOPM with 0xFF to restrict access to all ports */
    mov edi,_imp__DeviceIoControl@32
    push ebx        ; lpOverlapped
    push offset BytesReturned; lpBytesReturned
    push ebx        ; nOutBufferSize
    push ebx        ; lpOutBuffer
    push ebx        ; nInBufferSize
    push ebx        ; lpInBuffer
    push IOCTL_IOPM_RESTRICT_ALL_ACCESS; dwIoControlCode
    push eax;scp05_Handle   ; hDevice
    call edi;_imp__DeviceIoControl@32
    call _imp__GetCurrentProcessId@0
    mov pi.dwProcessId,eax
    push ebx        ; lpOverlapped
    push offset BytesReturned; lpBytesReturned
    push ebx        ; nOutBufferSize
    push ebx        ; lpOutBuffer
    push 4      ; nInBufferSize
    push offset pi.dwProcessId  ; lpInBuffer
    push IOCTL_ENABLE_IOPM_ON_PROCESSID; dwIoControlCode
    push scp05_Handle   ; hDevice
    call edi;_imp__DeviceIoControl@32
;----------------------------------------------------------------------------
    push 1   ; задержка чтобы драйвер успел отработать
    mov edi,_imp__Sleep@4
    call edi;_imp__Sleep@4
;-----------------------------------------------------------------------
        in al,61h;текущее состояние порта 61h в AL
    or al,00000011b;установить биты 0 и 1 в 1
    out 61h,al ;теперь динамик включен
    mov al,0B6h
    out 43h,al  
    mov esi,offset melody; данные 
    mov ecx,size_melody  ; счетчик
    mov dx,42h ;Timer 8253-5 (AT: 8254.2).
@@: push edx   
    push ecx   
    push 40    ; задержка в 40 мСек
    call edi;_imp__Sleep@4     
    pop ecx   
    pop edx   ;Команда выводит данные в порт ввода-вывода, 
    outsb     ;номер которого загружен в регистр DX, 
    loop @b  ;из ячейки памяти по адресу DS:ESI
    in al,61h
    and al,11111100b;теперь динамик выключен
    out 61h,al
;-----------------------------------------------------------            
    push scp05_Handle   ; hObject
    call _imp__CloseHandle@4; CloseHandle(scp05_Handle)
; ---------------------------------------------------------------------------
a0: lodsd;add esi,4 из '\\.\scp05' делаем 'scp05'
    push offset cusDevice           
    call _imp__ZwUnloadDriver@4
    push esi
    push Key
    call _imp__SHDeleteKeyA@8;удаляем непустой ключ из реестра 
    push Key
    call _imp__RegCloseKey@4
; ---------------------------------------------------------------------------
    push ebx
    call _imp__ExitProcess@4
start endp
;----------------------------------------------------------------
.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
;----------------------------------------------------------------
BytesReturned dd ?
pi PROCESS_INFORMATION <>;   /* Process Info Structure - Contains Process ID Information
Status  SERVICE_STATUS <>
a_scp05 db "\\.\scp05.sys",0
aSystem     db "SYSTEM\CurrentControlSet\Services",0
aType       db "Type",0
aImagePath  db "ImagePath",0
end start
________________________________________ ___
© Mikl___ 2011
7
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16355 / 7671 / 1078
Регистрация: 11.11.2010
Сообщений: 13,734
19.10.2012, 04:04
Доступ к командам In/Out через изменение карты IOPM

Драйвер scp06.sys написан на основе драйвера режима ядра UserPort 2.0 by Tomas Franzon changed to PsSetCreateProcessNotifyRoutin method. адресный диапазон расширен до 7A80h для всех процессов и до 0FFFFh для \\.\scp06 процессов. Выполнение Ke386IoSetAccessProcess, сопровождается вызовом функции ZwYieldExecution, которая форсирует процесс переключения. Сочетание команд outsb и user mode WinAPI-функции Sleep. Полнофункциональный драйвер.

Далее исходный текст драйвера scp06.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
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
; masm windows native #
;написано на основе драйвера режима ядра UserPort 2.0 by Tomas Franzon
.686P
.model flat
;---------------------------------------------------------------------------
include ntddk.inc
include ntstatus.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__Ke386IoSetAccessProcess@8:dword
extern _imp__Ke386SetIoAccessMap@8:dword
extern _imp_@IofCompleteRequest@8:dword
extern _imp__PsSetCreateProcessNotifyRoutine@8:dword
extern _imp__PsLookupProcessByProcessId@8:dword
extern _imp__ZwYieldExecution@0:dword
extern _imp__IoGetCurrentProcess@0:dword
extern _imp__Ke386QueryIoAccessMap@8:dword
extern _imp__MmAllocateNonCachedMemory@4:dword
extern _imp__MmFreeNonCachedMemory@8:dword
;---------------------------------------------------------------------------
IOPM_SIZE equ 2004h ; sizeof I/O permission map
;---------------------------------------------------------------------------
.const
CCOUNTED_UNICODE_STRING "\\Device\\scp06", cusDevice, 4
CCOUNTED_UNICODE_STRING "\\DosDevices\\scp06", cusSymbolicLink, 4
;---------------------------------------------------------------------------
.code
;---------------------------------------------------------------------------
; This routine is called every time a new process is created. This is
; where scp06 gets activated by swithing the IOPM
CreateProcessNotifyRoutine proc ParentId:HANDLE, ProcessId:HANDLE, Create:BOOLEAN
 
local Process:dword
 
    lea eax,Process
    push eax        ; &Process
    push ProcessId
    and Process,0 ; PEPROCESS Process=NULL
    call _imp__PsLookupProcessByProcessId@8; Give the new process IO access
    cmp Process,0 ; if  (Process != NULL)
    jz short @f
    push 1
    push Process
    call _imp__Ke386IoSetAccessProcess@8
    call _imp__ZwYieldExecution@0 ; форсирует процесс переключения
@@: leave
    retn 0Ch
CreateProcessNotifyRoutine endp
;*********************************************************************
;  Служебный обработчик для user-mode вызова CreateFile().
 
; Эта функция введенав таблицу вызовов функций объекта драйверов с помощью
;DriverEntry(). Когда user-mode приложение вызывает CreateFile(), эта
;функция получаетуправление всё ещё в контексте вызвавшего приложения, но
;с CPL (текущий уровеньпривелегий процессора) установленным в 0. Это
;позволяет производить операции возможные только в kernel mode. Процедура
;вызывается для предоставления вызывающему процессу доступ к портам в/в.
;Всё что user-mode приложение, которому нужен доступ к портам в/в должно
;сделать -- это открыть устройство используя CreateFile(). Никаких других
;действий не нужно.
;*********************************************************************
CreateDispatch proc 
lpIrp        equ dword ptr [esp+8]
 
    push 1
    call _imp__IoGetCurrentProcess@0
    push eax
    call _imp__Ke386IoSetAccessProcess@8;предоставить доступ к портам ввода/вывода текущему процессу
    call _imp__ZwYieldExecution@0 ; форсирует процесс переключения          
    mov ecx,lpIrp
    xor edx,edx
    and (_IRP PTR [ecx]).IoStatus.Information,edx
    and (_IRP PTR [ecx]).IoStatus.Status,edx
    call _imp_@IofCompleteRequest@8;IoCompleteRequest (Irp, IO_NO_INCREMENT)
    xor eax,eax;return STATUS_SUCCESS
    retn 8
CreateDispatch endp
;****************************************************************
;                 Процедура входа в драйвер.
 
;Эта процедура вызывается только раз после загрузки драйвера в память. Она
;выделяет необходимые ресурсы для работы драйвера. В нашем случае она выделяет
;память для массива IOPM, и создает устройство,которое может открыть user-mode 
;приложение. Она также создает символическую ссылку на драйвер устройства. Это
;позволяет user-mode приложению получить доступ к нашему драйверу используя
;"\\.\scp06" нотацию.
;*****************************************************************
DriverEntry proc DriverObject:PDRIVER_OBJECT, RegistryPath:PUNICODE_STRING
local deviceObject:PDEVICE_OBJECT
 
        push ebx
    push esi
        push edi
    xor ebx,ebx
;---------------------------------------------------------------------------
    push IOPM_SIZE*2
    call _imp__MmAllocateNonCachedMemory@4
    mov IOPM,eax
    mov edi,eax;edi = IOPM
    or eax,-1
    mov ecx,(IOPM_SIZE)/4
    rep stosd
;---------------------------------------------------------------------------
    mov OriginalIOPMCopy,edi; OriginalIOPMCopy = IOPM + IOPM_SIZE
 
        push edi;OriginalIOPMCopy
    push 1
    call _imp__Ke386QueryIoAccessMap@8 ;    Update the IOPM map
;There might be an other driver using the IOPM so lets merge them together
    mov ecx,IOPM_SIZE/4;sizeof(OriginalIOPMCopy)
@@: lodsd
    and dword ptr [edi-4+IOPM_SIZE],eax;IOPM[i] = OriginalIOPMCopy[i] & IOPM[i]
    loop @b
;---------------------------------------------------------------------------
    and byte ptr [edi + 42h/8],not((1 shl (42h MOD 8)) or (1 shl (43h MOD 8)));0F3h; I/O access for 42h & 43h ports
    and byte ptr [edi + 61h/8],not(1 shl (61h MOD 8)); I/O access for 61h port
;---------------------------------------------------------------------------
    push edi;edi = IOPM
    push 1
    call _imp__Ke386SetIoAccessMap@8
;Set up device driver name and device object.
;Make the driver accessable though the file \\.\scp06
    lea ecx,deviceObject
    push ecx;&deviceObject
    push ebx;FALSE
    push ebx;0
    push FILE_DEVICE_UNKNOWN;22h
    push offset cusDevice
    push ebx;0                  
    mov esi,DriverObject
    push esi;DriverObject
    call _imp__IoCreateDevice@28
;status = IoCreateDevice(DriverObject, 0, &uniNameString, FILE_DEVICE_UNKNOWN, 0, FALSE, &deviceObject)
    test eax,eax
    jl short @f;if(!NT_SUCCESS(status)) return status
    push offset cusDevice
    push offset cusSymbolicLink
    call _imp__IoCreateSymbolicLink@8;status = IoCreateSymbolicLink (&uniDOSString, &uniNameString)
    test eax,eax
    jl short @f;if (!NT_SUCCESS(status)) return status
    mov (DRIVER_OBJECT PTR [esi]).MajorFunction[IRP_MJ_CREATE*4],offset CreateDispatch
    mov (DRIVER_OBJECT PTR [esi]).DriverUnload,offset DriverUnload  
        push ebx;=0
    push offset CreateProcessNotifyRoutine
    call _imp__PsSetCreateProcessNotifyRoutine@8
    xor eax,eax;return STATUS_SUCCESS
@@:     pop edi
    pop esi
        pop ebx
    leave
    retn 8
DriverEntry endp
;---------------------------------------------------------------------------
;удалить ссылку "\\.\scp06" и восстановить IOPM 
DriverUnload:
DriverObject equ dword ptr [esp+4]
 
        push 0
    call _imp__IoGetCurrentProcess@0
    push eax
    call _imp__Ke386IoSetAccessProcess@8;Deny the current process IO access
 
    call _imp__ZwYieldExecution@0 ; форсирует процесс переключения
 
    push OriginalIOPMCopy
    push 1
    call _imp__Ke386SetIoAccessMap@8;Restore to the original map
;С помощью функции MmFreeNonCachedMemory освобождаем выделенный буфер
    push IOPM_SIZE*2
    push IOPM
    call _imp__MmFreeNonCachedMemory@8
 
    push 1
    push offset CreateProcessNotifyRoutine
    call _imp__PsSetCreateProcessNotifyRoutine@8
 
    push offset cusSymbolicLink
    call _imp__IoDeleteSymbolicLink@4
 
    mov eax,DriverObject
    push dword ptr (DRIVER_OBJECT ptr [eax]).DeviceObject
    call _imp__IoDeleteDevice@4
    retn 4
;---------------------------------------------------------------------------
.data
OriginalIOPMCopy dd ?
IOPM    dd ?
end DriverEntry
Первый вариант user-mode приложения, которое запускает драйвер scp06.sys


user-mode приложение, которое запускает scp06.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
; 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__CloseHandle@4:dword
extern _imp__ControlService@12:dword
 
SERVICE_ERROR_NORMAL        equ 1
MAX_PATH            equ 260
.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
    mov edi,offset DrvFilename+4;&edi='scp06.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='scp06',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 @f    
    ; 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 a1;if eax != NULL
@@: 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 @f;a10
    push ebx;offset Vectors
    push ebx;0 
    push Service 
    call _imp__StartServiceA@12 
@@: sub edi,4;&edi='\\.\scp06',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   
    inc eax;cmp eax,INVALID_HANDLE_VALUE
    je short a2
    dec eax
    mov Driver,eax
    push 1
    call _imp__Sleep@4
        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 edx   ;PC/XT PPI port B bits:
    push ecx   ;0: Timer 2 gate OR  03h= speaker ON
    push 40
    call _imp__Sleep@4
    pop ecx   ;7: 0=enable keyboard
    pop edx   ;Команда выводит данные в порт ввода-вывода, 
    outsb     ;номер которого загружен в регистр DX, 
    loop @b  ;из ячейки памяти по адресу DS:ESI
    pop edi
    in al,61h
    and al,11111100b;4Dh 
    out 61h,al          
 
    ; Remove driver from SCM database
wmDESTROY: push Driver
    call _imp__CloseHandle@4
a2: 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
a1: push Manager
    call _imp__CloseServiceHandle@4
    jmp short @f
err:    push MB_ICONSTOP        
    push ebx;NULL
    push handle[esi*4];offset can_t_connect
    push ebx;NULL
    call _imp__MessageBoxA@16 
@@: push ebx;0
    call _imp__ExitProcess@4
start endp
;----------------------------------------------------------------
.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
;----------------------------------------------------------------
DrvFilename db '\\.\scp06.sys',0
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 приложения, которое запускает драйвер scp06.sys

Предварительно прописываем драйвер scp06.sys в реестре "вручную" (используем функции RegOpenKey, RegCreateKey, RegSetValue) и загружаем драйвер scp06.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
; 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__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
;--------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\scp06>
len_us = $-us
align 4
cusDevice dw (len_us - 2)
          dw (len_us)
      dd us
.code
 
start proc
local   dType:dword
local   Key2:HKEY
local   Key:HKEY
local acDriverPath[MAX_PATH]:CHAR
 
    xor ebx,ebx
    mov esi,offset DrvFilename+4;&edi='scp06.sys',0
        lea edi,acDriverPath
        mov eax,'\??\'
    stosd;путь к драйверу должен начаться с '\??\'
;-----инициализируем драйвер
    push eax
    push esp
    push edi
    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='scp06',0
        lea eax,Key2
    push eax
    push esi
    push Key
    call _imp__RegCreateKeyA@12
    push edi
    push REG_SZ
    push ebx;0
    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
    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; выравниваем стек после GetFullPathNameA
@@: sub esi,4;&esi='\\.\scp06',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 a2
    dec eax
    push eax;push Driver для CloseHandle
    push 1
    call _imp__Sleep@4
        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 edx   ;PC/XT PPI port B bits:
    push ecx   ;0: Timer 2 gate OR  03h= speaker ON
    push 40
    call _imp__Sleep@4
    pop ecx   ;7: 0=enable keyboard
    pop edx   ;Команда выводит данные в порт ввода-вывода, 
    outsb     ;номер которого загружен в регистр DX, 
    loop @b  ;из ячейки памяти по адресу DS:ESI
    pop edi
    in al,61h
    and al,11111100b;4Dh 
    out 61h,al          
    ; Remove driver
    call _imp__CloseHandle@4
a2: lodsd;add esi,4 из '\\.\scp06' делаем 'scp06'
    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
;----------------------------------------------------------------
.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
;----------------------------------------------------------------
DrvFilename     db '\\.\scp06.sys',0
aSystem     db "SYSTEM\CurrentControlSet\Services",0
aType       db "Type",0
aImagePath  db "ImagePath",0
end start
________________________________________ _________
© Mikl___ 2011
6
Модератор
Эксперт по электронике
8962 / 6728 / 921
Регистрация: 14.02.2011
Сообщений: 23,752
19.10.2012, 04:42
Могу порекомендовать книгу
В. П. Солдатов
"Программирование драйверов Windows" Москва Издательство БИНОМ 2004
но для её прочтение нужно знать С, основы Windows, шестнадцатеричную арифметику,устройство компьютера
т.е не для начинающих(правда не понятно как может начинающий написать драйвер)
для написания компилирования и отладки драйверов необходимо скачать Microsoft Windows DDK ( для каждой системы свой) в этом пакете лежат примеры копайся не хочу..... но неплохо-бы знать английский
куча информации лежит в MSDN но тут английский обязателен

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

Добавлено через 2 минуты
Цитата Сообщение от Mikl___ Посмотреть сообщение
На многих современных материнских платах расположено два таких таймера,
к чему подключен второй таймер?
как его можно использовать?
не используется ли он виндой как мультимедийный таймер?
0
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16355 / 7671 / 1078
Регистрация: 11.11.2010
Сообщений: 13,734
19.10.2012, 06:13
Доступ к командам In/Out через изменение карты IOPM

указатель на карту ввода/вывода, который по умолчанию указывал за границу TSS, и устанавливаем начало IOPM на TSS+0x88. В отличии от UserPort.sys 1.0 драйвер поддерживает Hyper-Threading Technology ("UserPort 1.0 did not run stable on Hyperthreading machined (rebooted without bluescreen).")

Драйвер scp07 написан на основе драйвера режима ядра UserPort 1.0 by Tomas Franzon изменение адреса начала IOPM в TSS расширяет размер TSS до 2135h. адресный диапазон расширен до 7A80h для всех процессов и до 0FFFFh для \\.\scp07 процессов. Сочетание команд outsb и WinAPI функции Sleep. Для многопроцессорной или гипертрейдинговой машины может вызвать перезагрузку без BSOD. Полнофункциональный драйвер.

Далее исходный текст драйвера scp07.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
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
; masm windows native #
;написано на основе драйвера режима ядра UserPort 1.0 by Tomas Franzon
.686P
.model flat
;---------------------------------------------------------------------------
include ntddk.inc
include ntstatus.inc
include Strings.mac
includelib ntoskrnl.lib
;---------------------------------------------------------------------------
extern _imp__IoCreateDevice@28:dword
extern _imp__IoCreateSymbolicLink@8:dword
extern _imp__Ke386IoSetAccessProcess@8:dword
extern _imp__IoGetCurrentProcess@0:dword
extern _imp__IoDeleteDevice@4:dword
extern _imp__IoDeleteSymbolicLink@4:dword
extern _imp_@IofCompleteRequest@8:dword
;-------------------------------------------------------
KGDTENTRY STRUCT        ; sizeof = 8
    LimitLow        WORD    ?
    BaseLow         WORD    ?
    union _HighWord     ; original HighWord
        struct Bytes
            BaseMid BYTE    ?
            Flags1  BYTE    ?
            Flags2  BYTE    ?
            BaseHi  BYTE    ?
        ends
; Damn! ...record field names must be unique...
; kd displays it as __unnamed11, so i prepend each field name with 'u11'
    Bits RECORD \
        u11BaseHi:8,        ; bits24-31 BaseHi
        u11Granularity:1,   ; bit23 Granularity
        u11Default_Big:1,   ; bit22 Default_Big
        u11Reserved_0:1,    ; bit21 Reserved_0
        u11Sys:1,       ; bit20 Sys
        u11LimitHi:4,       ; bits16-19 LimitHi
        u11Pres:1,      ; bit15 Pres
        u11Dpl:2,       ; bits13-14 Dpl
        u11Type:5,      ; bits8-12  Type
        u11BaseMid:8        ; bits0-7   BaseMid
    ends ; HighWord
KGDTENTRY ENDS
 
GDTREG STRUC
    limit word ?
    base  KGDTENTRY <?> 
GDTREG ENDS
;-------------------------------------------------------
.const
CCOUNTED_UNICODE_STRING "\\Device\\scp07", cusDevice, 4
CCOUNTED_UNICODE_STRING "\\DosDevices\\scp07", cusSymbolicLink, 4
;-------------------------------------------------------
.code
 
CreateFileDispatch proc
lpIrp        equ dword ptr [esp+8]
 
        push 1
        call _imp__IoGetCurrentProcess@0
        push eax
        call _imp__Ke386IoSetAccessProcess@8    ; Give the current process IO access
        mov ecx,lpIrp   ; ecx = Irp
        xor edx, edx    ; edx =  IO_NO_INCREMENT
        mov (_IRP PTR [ecx]).IoStatus.Information,edx   ; Irp->IoStatus.Information = 0
        mov (_IRP PTR [ecx]).IoStatus.Status,edx    ; Irp->IoStatus.Status = STATUS_SUCCESS
        call _imp_@IofCompleteRequest@8 ;   IoCompleteRequest(Irp, IO_NO_INCREMENT)
        xor eax, eax    ; return STATUS_SUCCESS
        retn 8
CreateFileDispatch endp
;remove the link "\\.\scp07" and restore the IOPM
DriverUnload    proc DriverObject:PDRIVER_OBJECT
 
local TaskSeg:word
local gdtreg:GDTREG
 
    push esi
    cli              ;don't get interrupted!
    sgdt gdtreg   ;get the GDT address       
    str TaskSeg  ;get the TSS selector      
    movsx edx,TaskSeg;mov   ax,TaskSeg
    and dl,0F8h;and al,0F8h
    add edx,dword ptr gdtreg.base
    mov ax,word ptr OrgGDTSize;
    mov (GDTREG ptr [edx]).limit,ax;g->limit = OrgGDTSize
    and (KGDTENTRY ptr [edx])._HighWord,not(mask u11Type);mark TSS as "not busy"
    or  (KGDTENTRY ptr [edx])._HighWord,000000900h;g->type = 9
    ltr TaskSeg;reload task register (TR)
    sti        ;let interrupts continue
    mov ecx,(KGDTENTRY ptr [edx])._HighWord
    movzx esi,cl;esi=g->basemid
    shl esi,10h;esi=g->basemid << 16
    mov si,(KGDTENTRY ptr [edx]).BaseLow;si=g->baselo
    and ecx,0FF000000h;ecx=g->basehi << 24
    or esi, ecx;TSSbase = g->baselo | (g->basemid << 16) | (g->basehi << 24)
    movzx eax,word ptr [esi+66h];eax = *((USHORT *)(TSSbase + 0x66))
    add eax,esi; eax = *((USHORT *)(TSSbase + 0x66)) + TSSbase
    add esi,88h; TSSThroughCreateFileIOPM = TSSbase + 0x88
;Restore to the original map
    mov ecx,7Ch;sizeof(DefaultMap)-4
@@: mov edx,dword ptr OriginalAllProcIOPMCopy[ecx]
    mov [eax+ecx],edx
    mov edx,dword ptr OriginalThroughCreateFileIOPMCopy[ecx]
    mov [esi+ecx],edx
    sub ecx,4; i -= 4
    jns @b;while ( i >= 0 )
    push offset cusSymbolicLink
    call _imp__IoDeleteSymbolicLink@4
    mov ecx,DriverObject
    push dword ptr (DRIVER_OBJECT ptr [ecx]).DeviceObject
    call _imp__IoDeleteDevice@4 ; IoDeleteDevice(DriverObject->DeviceObject)
    pop esi
    leave
    retn 4
DriverUnload    endp
;---------------------------------------------------------------------------
DriverEntry proc near DriverObject:PDRIVER_OBJECT, RegistryPath:PUNICODE_STRING
 
local TaskSeg:word
local gdtreg:GDTREG
local deviceObject:PDEVICE_OBJECT
 
    push esi
    push edi
    cli;don't get interrupted!
    str TaskSeg;get the TSS selector
    sgdt gdtreg;get the GDT address
    movsx edx,TaskSeg;mov   ax, TaskSeg
    mov ecx,0FFFFh
    and dl,0F8h;and al, 0F8h
    add edx,dword ptr gdtreg.GDTREG.base;g = gdtreg.base + (TaskSeg >> 3)
    mov ax,(GDTREG ptr [edx]).limit; get the TSS address;mov eax,[edx]
    mov OrgGDTSize,ax
; modify TSS segment limit
    lea ecx,[eax+82h]
    mov (GDTREG ptr [edx]).limit,cx;g->limit += 0x082
    and (KGDTENTRY ptr [edx])._HighWord,not(mask u11Type); mark TSS as "not busy"
    or  (KGDTENTRY ptr [edx])._HighWord,000000900h; g->type = 9
    ltr TaskSeg
    sti
    mov eax,(KGDTENTRY ptr [edx])._HighWord
    movzx ecx,al;ecx=g->basemid
    and eax,0FF000000h;eax=g->basehi << 24
        shl ecx, 10h;ecx=g->basemid << 16
    mov cx,(KGDTENTRY ptr [edx]).BaseLow;cx=g->baselo
    or ecx, eax;ecx = g->baselo|(g->basemid << 16)|(g->basehi << 24)
    movzx eax,word ptr [ecx+66h]
    add eax,ecx
    add ecx,88h; TSSThroughCreateFileIOPM = TSSbase + 0x88
    mov esi,offset DefaultMap
    mov edi,7Ch;edi = sizeof(DefaultMap) - 4
@@: mov edx,[eax+edi]; bl = TSSAllProcessesIOPM[i]
    mov dword ptr OriginalAllProcIOPMCopy[edi],edx ; OriginalAllProcIOPMCopy[i] =   TSSAllProcessesIOPM[i]
    mov edx,[esi+edi]; bl = AllProcessesIOPM[i]
    mov [eax+edi],edx; TSSAllProcessesIOPM[i] = AllProcessesIOPM[i]
    mov edx,[ecx+edi]; bl = TSSThroughCreateFileIOPM[i]
    mov dword ptr OriginalThroughCreateFileIOPMCopy[edi],edx ; OriginalThroughCreateFileIOPMCopy[i] = TSSThroughCreateFileIOPM[i];
    mov edx,[esi+edi]; bl = ThroughCreateFileIOPM[i]
    and [ecx+edi],edx; TSSThroughCreateFileIOPM[i] = TSSThroughCreateFileIOPM[i] & ThroughCreateFileIOPM[i];
    sub edi,4   ;i -= 4 
    jns @b; while ( i >= 0 )
    add edi,4   ; edi = -4 + 4 = 0
    lea ecx, deviceObject
    push ecx    ; &deviceObject
    mov esi,DriverObject
    push edi    ; 0
    push edi    ; 0
    push FILE_DEVICE_UNKNOWN
    push offset cusDevice
    push edi    ; 0
    push esi    ; DriverObject
    call _imp__IoCreateDevice@28
    test eax,eax    ; if (!NT_SUCCESS(status))   
    js short @f     ; return status
    push offset cusDevice
    push offset cusSymbolicLink
    call _imp__IoCreateSymbolicLink@8
    test eax,eax    ; if (!NT_SUCCESS(status))   
    js short @f     ; return status
    mov (DRIVER_OBJECT PTR [esi]).MajorFunction[IRP_MJ_CREATE*4], offset CreateFileDispatch ; DriverObject->MajorFunction[IRP_MJ_CREATE] = CreateFileDispatch
    mov (DRIVER_OBJECT PTR [esi]).DriverUnload,offset DriverUnload ; DriverObject->DriverUnload = scp07Unload
    xchg eax,edi    ; return STATUS_SUCCESS
@@: pop edi
    pop esi
    leave
    retn 8
DriverEntry endp
.data
OriginalAllProcIOPMCopy db 80h dup(0)
OriginalThroughCreateFileIOPMCopy db 80h dup(0)
OrgGDTSize dw ?
DefaultMap db 8 dup(-1),0F3h,3 dup(-1),0FDh,72h dup(-1)
end DriverEntry
Первый вариант user-mode приложения, которое запускает драйвер scp07.sys

user-mode приложение, которое запускает scp07.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
; 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__CloseHandle@4:dword
extern _imp__ControlService@12:dword
 
SERVICE_ERROR_NORMAL        equ 1
MAX_PATH            equ 260
.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
    mov edi,offset DrvFilename+4;&edi='scp07.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='scp07',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 @f    
    ; 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 a1;if eax != NULL
@@: 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 @f;a10
    push ebx;offset Vectors
    push ebx;0 
    push Service 
    call _imp__StartServiceA@12 
@@: sub edi,4;&edi='\\.\scp07',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   
    inc eax;cmp eax,INVALID_HANDLE_VALUE
    je short a2
    dec eax
    mov Driver,eax
    push 1
    call _imp__Sleep@4
        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 edx   ;PC/XT PPI port B bits:
    push ecx   ;0: Timer 2 gate OR  03h= speaker ON
    push 40
    call _imp__Sleep@4
    pop ecx   ;7: 0=enable keyboard
    pop edx   ;Команда выводит данные в порт ввода-вывода, 
    outsb     ;номер которого загружен в регистр DX, 
    loop @b  ;из ячейки памяти по адресу DS:ESI
    pop edi
    in al,61h
    and al,11111100b;4Dh 
    out 61h,al          
 
    ; Remove driver from SCM database
wmDESTROY: push Driver
    call _imp__CloseHandle@4
a2: 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
a1: push Manager
    call _imp__CloseServiceHandle@4
    jmp short @f
err:    push MB_ICONSTOP        
    push ebx;NULL
    push handle[esi*4];offset can_t_connect
    push ebx;NULL
    call _imp__MessageBoxA@16 
@@: push ebx;0
    call _imp__ExitProcess@4
start endp
;----------------------------------------------------------------
.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
;----------------------------------------------------------------
DrvFilename db '\\.\scp07.sys',0
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 приложения, которое запускает драйвер scp07.sys

Предварительно прописываем драйвер scp07.sys в реестре "вручную" (используем функции RegOpenKey, RegCreateKey, RegSetValue) и загружаем драйвер scp07.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
; 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__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
;--------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\scp07>
len_us = $-us
align 4
cusDevice dw (len_us - 2)
          dw (len_us)
      dd us
 
.code
 
start proc
local   dType:dword
local   Key2:HKEY
local   Key:HKEY
local acDriverPath[MAX_PATH]:CHAR
 
    xor ebx,ebx
    mov esi,offset DrvFilename+4;&esi='scp07.sys',0
        lea edi,acDriverPath
        mov eax,'\??\'
    stosd;путь к драйверу должен начаться с '\??\'
;-----инициализируем драйвер
    push eax
    push esp
    push edi
    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='scp07',0
        lea eax,Key2
    push eax
    push esi
    push Key
    call _imp__RegCreateKeyA@12
    push edi
    push REG_SZ
    push ebx;0
    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
    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; выравниваем стек после GetFullPathNameA
    sub esi,4;&esi='\\.\scp07',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 a0
    dec eax
    push eax;mov Driver,eax
    push 1
    call _imp__Sleep@4
        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 edx   ;PC/XT PPI port B bits:
    push ecx   ;0: Timer 2 gate OR  03h= speaker ON
    push 40
    call _imp__Sleep@4
    pop ecx   ;7: 0=enable keyboard
    pop edx   ;Команда выводит данные в порт ввода-вывода, 
    outsb     ;номер которого загружен в регистр DX, 
    loop @b  ;из ячейки памяти по адресу DS:ESI
    pop edi
    in al,61h
    and al,11111100b;4Dh 
    out 61h,al          
    ; Remove driver
    call _imp__CloseHandle@4
a0: lodsd;add esi,4 из '\\.\scp07' делаем 'scp07'
    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
;----------------------------------------------------------------
.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
;----------------------------------------------------------------
DrvFilename     db '\\.\scp07.sys',0
aSystem     db "SYSTEM\CurrentControlSet\Services",0
aType       db "Type",0
aImagePath  db "ImagePath",0
end start
________________________________________ ______________
© Mikl___ 2011
7
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
19.10.2012, 06:13
Помогаю со студенческими работами здесь

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

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

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

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

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


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

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

Новые блоги и статьи
Очередные открытия мега простых чисел, сделанные добровольцами с помощью домашних компьютеров
Programma_Boinc 21.04.2025
Очередные открытия мега простых чисел, сделанные добровольцами с помощью домашних компьютеров. 3 марта 2025 года, в результате обобщенного поиска простых чисел Ферма в PrimeGrid был найден. . .
Система статов в Unity
GameUnited 20.04.2025
Статы — фундаментальный элемент игрового дизайна, который определяет характеристики персонажей, предметов и других объектов в игровом мире. Будь то показатель силы в RPG, скорость передвижения в. . .
Статические свойства и методы в TypeScript
run.dev 20.04.2025
TypeScript прочно занял своё место в системе современной веб-разработки. Этот строго типизированный язык программирования не просто расширяет возможности JavaScript — он делает разработку более. . .
Batch Transform и Batch Gizmo Drawing API в Unity
GameUnited 20.04.2025
В мире разработки игр и приложений на Unity производительность всегда была критическим фактором успеха. Создатели игр постоянно балансируют между визуальной привлекательностью и плавностью работы. . .
Звук в Unity: Рандомизация с Audio Random Container
GameUnited 20.04.2025
В современных играх звуковое оформление часто становится элементом, который либо полностью погружает игрока в виртуальный мир, либо разрушает атмосферу за считанные минуты. Представьте: вы исследуете. . .
Максимальная производительность C#: Советы, тестирование и заключение
stackOverflow 20.04.2025
Погружение в мир микрооптимизаций C# открывает перед разработчиком целый арсенал мощных техник. Но как определить, где и когда их применять? Ответ начинается с точных измерений и профилирования. . . .
Максимальная производительность C#: Предсказание ветвлений
stackOverflow 20.04.2025
Третий ключевой аспект низкоуровневой оптимизации — предсказание ветвлений. Эта тема менее известна среди разработчиков, но её влияние на производительность может быть колоссальным. Чтобы понять. . .
Максимальная производительность C#: Векторизация (SIMD)
stackOverflow 20.04.2025
Помимо работы с кэшем, другим ключевым аспектом низкоуровневой оптимизации является векторизация вычислений. SIMD (Single Instruction, Multiple Data) позволяет обрабатывать несколько элементов данных. . .
Максимальная производительность C#: Процессорный кэш
stackOverflow 20.04.2025
Знакомство с внутренним устройством процессорного кэша — ключевой шаг в написании по-настоящему быстрого кода на C#. Этот слой архитектуры компьютера часто ускользает от внимания разработчиков, но. . .
Максимальная производительность C#: Введение в микрооптимизации
stackOverflow 20.04.2025
В мире разработки на C# многие привыкли полагаться на . NET Runtime, который "магическим образом" сам оптимизирует код. И часто это работает - современные JIT-компиляторы творят чудеса. Но когда речь. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru