Форум программистов, компьютерный форум, киберфорум
Программирование драйверов
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.60/426: Рейтинг темы: голосов - 426, средняя оценка - 4.60
58 / 57 / 15
Регистрация: 15.09.2012
Сообщений: 557

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

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

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

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

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

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

38
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
22.10.2012, 12:53
Студворк — интернет-сервис помощи студентам
Доступ к командам In/Out через изменение карты IOPM

Драйвер scp08 написан на основе драйвера режима ядра UserPort 1.1 by Tomas Franzon изменение адреса начала IOPM в TSS расширяет размер TSS до 2FFFh работает с гипертрейдинговыми и многопроцессорными системами. Полнофункциональный драйвер.

Далее исходный текст драйвера scp08.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
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
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
; masm windows native #
;написано на основе драйвера режима ядра UserPort 1.1 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
extern _imp__ZwYieldExecution@0:dword
extern _imp__Ke386IoSetAccessProcess@8:dword
extern _imp__Ke386SetIoAccessMap@8:dword
extern _imp__ZwSetInformationThread@16:dword
extern _imp__KeNumberProcessors:dword
extern _imp__MmFreeContiguousMemory@4:dword
extern _imp__MmIsAddressValid@4:dword
extern _imp__Ke386QueryIoAccessMap@8:dword
extern _imp__MmAllocateContiguousMemory@12:dword
extern _imp__MmAllocateNonCachedMemory@4:dword
extern _imp__MmFreeNonCachedMemory@8:dword
 
.const
CCOUNTED_UNICODE_STRING "\\Device\\scp08", cusDevice, 4
CCOUNTED_UNICODE_STRING "\\DosDevices\\scp08", cusSymbolicLink, 4
 
;структуры для манипулирования регистром GDT и дескриптором сегмента в GDT.
;Документированы в книгах по процессорам Intel.
KGDTENTRY STRUCT        ; sizeof = 8
    LimitLow        WORD    ?
    BaseLow         WORD    ?
    union _HighWord     ; original HighWord
        struct Bytes
            BaseMid BYTE    ?
            Flags1  BYTE    ?
            Flags2  BYTE    ?
            BaseHi  BYTE    ?
        ends
;имя поля записи должно быть уникально. Отладчик kd показывает 
;их как  __unnamed11, поэтому каждоеимя начинается с "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
;структура 48 бит регистра GDT который сохраняется командой SGDT               
GDTREG STRUC
    limit word ?
    base  KGDTENTRY <?> 
GDTREG ENDS
.code
;*********************************************************************
;  Служебный обработчик для user-mode вызова CreateFile().
 
; Эта функция введенав таблицу вызовов функций объекта драйверов с помощью
;DriverEntry(). Когда user-mode приложение вызывает CreateFile(), эта
;функция получаетуправление всё ещё в контексте вызвавшего приложения, но
;с CPL (текущий уровеньпривелегий процессора) установленным в 0. Это
;позволяет производить операции возможные только в kernel mode. Процедура
;вызывается для предоставления вызывающему процессу доступ к портам в/в.
;Всё что user-mode приложение, которому нужен доступ к портам в/в должно
;сделать -- это открыть устройство используя CreateFile(). Никаких других
;действий не нужно.
;*********************************************************************
CreateFileDispatch proc
lpIrp        equ dword ptr [esp+8]
 
    cmp nMaxThroughCreateFileIOPM,0
    jz @f
    push 1
    call _imp__IoGetCurrentProcess@0
    push eax
    call _imp__Ke386IoSetAccessProcess@8;предоставить доступ к портам ввода/вывода текущему процессу
    call _imp__ZwYieldExecution@0;форсировать переключение процесса
@@: 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
    retn 8
CreateFileDispatch endp
;  Служебный обработчик для user-mode вызова CloseHandle().
CloseFileDispatch proc
 
    cmp nMaxThroughCreateFileIOPM,0
    jz @f
    push 0
    call _imp__IoGetCurrentProcess@0
    push eax
    call _imp__Ke386IoSetAccessProcess@8;запретить текущему процессу доступ к портам ввода/вывода 
    call _imp__ZwYieldExecution@0 ; форсировать переключение процесса
@@: mov ecx,lpIrp
    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
CloseFileDispatch endp
 
;удалить ссылку "\\.\scp08" и восстановить IOPM 
DriverUnload    proc DriverObject:PDRIVER_OBJECT
 
local TaskSeg:word
local gdtreg:GDTREG
local AffinityMask:dword
 
    push esi
    push edi
    push ebx
    cmp nMaxAllProcessesIOPM,0
    jz short a0
    mov eax,_imp__KeNumberProcessors
    movsx esi,byte ptr [eax]
    cmp esi,1       ; if(NoOfProc < 1) then NoOfProc = 1
    jnb @f
    mov esi,1
@@: cmp esi,32      ; if(NoOfProc > 32) then NoOfProc = 32
    jna @f
    mov esi,32
@@: xor ebx,ebx     ; i = 0
    test esi,esi
    jz short a0
;запустить команду "ltr" для каждого процессора в мультипроцессорных 
;и hyper threading системах
@@: mov eax,1
    mov cl,bl;ecx,esi
    shl eax,cl      
    push sizeof(KAFFINITY)
    lea ecx,AffinityMask
    mov [ecx],eax   ; AffinityMask = 1 << i
    push ecx    ; &AffinityMask
    push ThreadAffinityMask;=4
    push NtCurrentThread;=-2
    call _imp__ZwSetInformationThread@16
    cli ;нас не должны прерывать!
;получаем селектор по инструкции STR, находим в GDT дескриптор и подставляем
;новый предел. Чтобы новый предел применился, мы должны снова загрузить
;селектор в регистр задачи (TR)
    str TaskSeg ;получаем селектор TSS
    sgdt gdtreg ;получаем адрес GDT
;получаем указатель на дескриптор TSS
    movsx edx,TaskSeg
    and dl,0F8h
    add edx,dword ptr gdtreg.base;g = gdtreg.base + (TaskSeg >> 3)
    mov ax,OrgGDTSize;восстанавливаем первоначальный предел сегмента TSS
    mov (GDTREG ptr [edx]).limit,ax;g->limit = OrgGDTSize
;нужно установить тип селектора в 9, чтобы указать что задача НЕ ЗАНЯТА.
;Иначе команда LTR вызовет ошибку
    and (KGDTENTRY ptr [edx])._HighWord,not(mask u11Type)
;помечаем TSS как "не занятый"
    or  (KGDTENTRY ptr [edx])._HighWord,000000900h; g->type = 9
;мы должна произвести загрузку регистра, иначе процессор 
;не увидит новый предел TSS
    ltr TaskSeg;перезагрузка регистра задачи (TR)
    sti ;разрешаем прерывание
    inc ebx         ; i++
    cmp esi,ebx 
    ja @b           ; while(i < NoOfProc)
a0: cmp nMaxThroughCreateFileIOPM,0
    jz @f
;Восстанавливаем первоначальную карту IOPM
    push OriginalThroughCreateFileIOPMCopy
    push 1
    call _imp__Ke386SetIoAccessMap@8 
 
@@: cmp nMaxAllProcessesIOPM,0
    jz @f
    mov ecx,nMaxAllProcessesIOPM
    add ecx,4
    jz @f
    mov edi,OriginalAllProcIOPMCopy
        mov esi,TSSAllProcessesIOPM
    rep movsd
 
@@:;С помощью функции MmFreeNonCachedMemory освобождаем выделенный буфер
    push 2010h+2004h
    push OriginalAllProcIOPMCopy
    call _imp__MmFreeNonCachedMemory@8
 
    push offset cusSymbolicLink
    call _imp__IoDeleteSymbolicLink@4
    mov ecx, DriverObject
    push dword ptr (DRIVER_OBJECT ptr [ecx]).DeviceObject
    call _imp__IoDeleteDevice@4
    pop ebx
    pop edi
    pop esi
    leave
    retn 4
DriverUnload endp
;****************************************************************
;                 Процедура входа в драйвер.
 
;Эта процедура вызывается только раз после загрузки драйвера в память. Она
;выделяет необходимые ресурсы для работы драйвера. В нашем случае она выделяет
;память для массива IOPM, и создает устройство,которое может открыть user-mode 
;приложение. Она также создает символическую ссылку на драйвер устройства. Это
;позволяет user-mode приложению получить доступ к нашему драйверу используя
;"\\.\scp08" нотацию.
;*****************************************************************
DriverEntry proc DriverObject:PDRIVER_OBJECT, RegistryPath:PUNICODE_STRING
 
local TaskSeg:word
local gdtreg:GDTREG
local AffinityMask:dword
local Information1:dword
local Information2:dword
local AllProcessesIOPM:dword
local deviceObject:PDEVICE_OBJECT
 
    push esi
    push edi
    push ebx
;выделяем с помощью функции MmAllocateNonCachedMemory кусок памяти размером
;4014h байт. Сохраняем указатель в переменной OriginalAllProcIOPMCopy и 
;заполняем переменную OriginalThroughCreateFileIOPMCopy
    push 2010h+2004h
    call _imp__MmAllocateNonCachedMemory@4
    mov OriginalAllProcIOPMCopy,eax
    add eax,2004h
    mov OriginalThroughCreateFileIOPMCopy,eax
;------------------------------------------------------
;Extend the address range to 0xffff for all processes. To do this I need to 
;allocate memory at address 0x80045000 but I don't know how to do this. Another 
;method would be to change the default IOPM ponter from 0x20AC to 0x88 for all 
;processes.
;The original size of the TSS is 0x20ab and the driver extends it up to 0x2fff. 
;The limit 0x2fff is because there is only three pages (3*4096) of memory 
;allocated for the TSS. This means that the highest port address which can
;be grantes access for all processes is 0x7a80. If you need to access I/O ports 
;above this address you need to open the "\\.\scp08" file in your application. 
;The default IOPM offset is 0x20ac and this value is rewritten by the OS on 
;every task switch. The IOPM offset must therefore be changed with the 
;undocumented function Ke386IoSetAccessProcess, which sets the IOPM offset to 
;0x88. The AllProcessesIOPM is written to 0x20ac because this is the default 
;IOPM offset for all processes and the ThroughCreateFileIOPM is written to
;0x88 because the Ke386IoSetAccessProcess function sets the IOPM offset to 0x88. 
;The Ke386IoSetAccessProcess function is called when a user mode program opens 
;the file "\\.\scp08".
    mov eax,80h
    or edi,-1
    mov nMaxThroughCreateFileIOPM, eax
    mov nMaxAllProcessesIOPM, eax
    push edi
    push edi
    mov esi,2014h
    push esi
    call _imp__MmAllocateContiguousMemory@12
    mov Information1,eax
;------------------------------------------------------
    push edi
    push edi
    push esi
    call _imp__MmAllocateContiguousMemory@12
    mov Information2,eax
;------------------------------------------------------
    push edi
    mov edi,eax;edi = Information2
        add eax,0Ch
    mov AllProcessesIOPM,eax;AllProcessesIOPM = Information2+12
    pop eax;eax=-1
    mov ecx,2014h/4;размер памяти в dword'ах, на которую указывают Information1 и Information2
    push ecx
    rep stosd
    pop ecx
    mov edi,Information1
    rep stosd
; ---------------------------------------------------------------------------
    mov edi,AllProcessesIOPM
    mov esi,offset DefaultMap
    mov ecx,80h/4;sizeof(DefaultMap) в dword'ах
    push esi
    push ecx
    rep movsd
    pop ecx
    pop esi
    mov edi,Information1
    add edi,12
    push edi
    rep movsd
    pop edi
;------------------------------------------------
        mov nMaxAllProcessesIOPM,2000h
    mov nMaxThroughCreateFileIOPM,2000h
    mov eax,2003h
@@: cmp byte ptr [edi+eax],0FFh
    jnz @f
    mov nMaxThroughCreateFileIOPM,eax
    dec eax
    jns @b
; ---------------------------------------------------------------------------
@@: mov eax, 2003h
@@: mov ecx,AllProcessesIOPM
    cmp byte ptr [ecx+eax],0FFh
    jnz @f
    mov nMaxAllProcessesIOPM,eax
    dec eax
    jns @b
; ---------------------------------------------------------------------------
@@: cli ;нас не должны прерывать!
;получаем селектор по инструкции STR, находим в GDT дескриптор и подставляем
;новый предел. Чтобы новый предел применился, мы должны снова загрузить
;селектор в регистр задачи (TR)
    str TaskSeg;сохранение содержимого регистра задачи tr в слове памяти      
    sgdt gdtreg;извлекаем содержимое системного регистра gdtr, содержащего
;значение базового адреса и размера глобальной дескрипторной таблицы GDT
;получаем указатель на дескриптор TSS
    movsx ecx,TaskSeg;получаем селектор TSS
    and cl,0F8h
    add ecx,dword ptr gdtreg.base
    mov ax,(GDTREG ptr [ecx]).limit; g = gdtreg.base + (TaskSeg >>  3)
;запоминаем изначальный предел сегмента TSS в OrgGDTSize
    mov OrgGDTSize,ax   ; OrgGDTSize = g->limit
    sti;разрешаем прерывание
;получим адрес TSS
    mov eax,(KGDTENTRY ptr [ecx])._HighWord
    mov esi,eax
    and esi,mask u11BaseMid;esi=g->basemid
    shl esi,10h;esi=g->basemid << 16
    and eax,mask u11BaseHi;eax=g->basehi << 24
    or esi,eax
    mov si,(KGDTENTRY ptr [ecx]).BaseLow;si=g->baselo
; TSSbase = (UCHAR *) (g->baselo | (g->basemid << 16) | (g->basehi << 24))
    movzx eax,word ptr [esi+66h]
    mov _IOPMPtr,eax; IOPMPtr = *((USHORT *)(TSSbase + 0x66));
    cmp eax,20ADh ;if (IOPMPtr != 0x20AD)
    jz @f
;IOPMPtr is 0x20AC on Windows XP/2000 and 0x20AD on Windows NT4/3.51
;but some drivers (video??) on Windows XP sets this pointer incorrectly so 
;the safest way is to use the hard coded value 0x20AC when not running 
;Windows NT
    mov _IOPMPtr,20ACh
;Copy the AccessMap to TSSbase + 0x88 and save the original map
@@: cmp nMaxThroughCreateFileIOPM,0 ; if (nMaxThroughCreateFileIOPM != 0)
    jz short a0
 
    push OriginalThroughCreateFileIOPMCopy
    push 1
    call _imp__Ke386QueryIoAccessMap@8
;There might be an other driver using the IOPM so lets merge them together
    mov eax,2000h;i = sizeof(OriginalThroughCreateFileIOPMCopy)) - 4
    mov edx,OriginalThroughCreateFileIOPMCopy
@@: mov ecx,[edx+eax];dword ptr OriginalThroughCreateFileIOPMCopy[eax]
    and [edi+eax],ecx; ThroughCreateFileIOPM[i] = OriginalThroughCreateFileIOPMCopy[i] & ThroughCreateFileIOPM[i]
    sub eax,4   ; i -= 4
    jns @b  ;while( i >=0 ) 
 
    push edi; ThroughCreateFileIOPM
    push 1
    call _imp__Ke386SetIoAccessMap@8 ; Ke386SetIoAccessMap(1, ThroughCreateFileIOPM)
 
a0: mov eax,_IOPMPtr
    add eax,esi ; TSSbase + IOPMPtr
    add esi,2FFFh
    push esi        ; TSSbase + 0x3000-1
    mov TSSAllProcessesIOPM,eax ; TSSAllProcessesIOPM = TSSbase + IOPMPtr
    call _imp__MmIsAddressValid@4
    test al,al      ; if (!MmIsAddressValid(TSSbase + 0x3000-1))
    jnz @f
    mov nMaxAllProcessesIOPM, 0 ; nMaxAllProcessesIOPM = 0
 
@@: mov eax,2FFCh
    sub eax,_IOPMPtr
    cmp nMaxAllProcessesIOPM,eax ; if (nMaxAllProcessesIOPM > 0x2ffc -  IOPMPtr)
    jbe @f
    mov nMaxAllProcessesIOPM,eax ; nMaxAllProcessesIOPM = 0x2ffc - IOPMPtr
 
@@: mov ecx,nMaxAllProcessesIOPM
    push ecx
    mov edi,OriginalAllProcIOPMCopy;offset OriginalAllProcIOPMCopy
    mov esi,TSSAllProcessesIOPM
    rep movsb;RtlCopyMemory (OriginalAllProcIOPMCopy, TSSAllProcessesIOPM, nMaxAllProcessesIOPM);
    mov edi,TSSAllProcessesIOPM
    mov esi,AllProcessesIOPM
    pop ecx
    rep movsb;RtlCopyMemory (TSSAllProcessesIOPM, AllProcessesIOPM, nMaxAllProcessesIOPM);
    push Information1
    call _imp__MmFreeContiguousMemory@4
    push Information2
    call _imp__MmFreeContiguousMemory@4
    cmp nMaxAllProcessesIOPM,0  ; if (nMaxAllProcessesIOPM != 0)
    jz short a1
 
    mov eax,_imp__KeNumberProcessors
    movsx esi,byte ptr [eax] ; NoOfProc = *KeNumberProcessors
    cmp esi,1; if (NoOfProc < 1) then  NoOfProc = 1
    jnb @f  
    mov esi,1
@@: cmp esi,32; if (NoOfProc > 32) then  NoOfProc = 32
    jbe @f
    mov esi,32
@@: xor ebx,ebx     ; i = 0
    test esi,esi
    jz short a1
@@: mov eax,1
    mov cl,bl
    shl eax,cl  ;eax = 1 << i
    push sizeof(KAFFINITY);=4
    lea ecx,AffinityMask
    mov [ecx],eax   ; AffinityMask = 1 << i
    push ecx    ; &AffinityMask
    push ThreadAffinityMask;=4
    push NtCurrentThread;=-2
    call _imp__ZwSetInformationThread@16 ; ZwSetInformationThread(NtCurrentThread(), ThreadAffinityMask,&AffinityMask,sizeof(KAFFINITY));
    cli     ;нас не должны прерывать!
;получаем селектор по инструкции STR, находим в GDT дескриптор и подставляем
;новый предел. Чтобы новый предел применился, мы должны снова загрузить
;селектор в регистр задачи (TR)
    str TaskSeg;сохранение содержимого регистра задачи tr в слове памяти
    sgdt gdtreg;извлекаем содержимое системного регистра gdtr, содержащего
;значение базового адреса и размера глобальной дескрипторной таблицы GDT
;получаем указатель на дескриптор TSS       
    movsx edx,TaskSeg;получаем селектор TSS
    and dl,0F8h;g = gdtreg.base + (TaskSeg >> 3)
    add edx,dword ptr gdtreg.base
;изменяем предел сегмента TSS. 0x3000 это максимальный размер (три страницы), 
;который мы можем использовать
    mov ax,word ptr nMaxAllProcessesIOPM
    add ax,word ptr _IOPMPtr
    add ax,4
    mov (GDTREG ptr [edx]).limit,ax; g->limit = IOPMPtr + nMaxAllProcessesIOPM + 4
    and (KGDTENTRY ptr [edx])._HighWord,not(mask u11Type);mark TSS as "not busy"
    or  (KGDTENTRY ptr [edx])._HighWord,000000900h; g->type = 9
;мы должна произвести загрузку регистра, иначе процессор 
;не увидит новый предел TSS
    ltr TaskSeg;перезагрузка регистра задачи (TR)
    sti;разрешаем прерывание
    inc ebx                 ; i++
    cmp esi,ebx     
    ja @b                   ; while( i < NoOfProc )
;Set up device driver name and device object.
;Make the driver accessable though the file "\\.\scp08"
a1: lea ecx,deviceObject
    push ecx        ; &deviceObject
    mov edi,DriverObject
    xor esi,esi
    push esi;0
    push esi;0
    push FILE_DEVICE_UNKNOWN
    push offset cusDevice   ; &uniNameString
    push esi;0
    push edi        ; &DriverObject
    call _imp__IoCreateDevice@28
    test eax, eax
    js @f; if (!NT_SUCCESS(status))    return status
    push offset cusDevice
    push offset cusSymbolicLink
    call _imp__IoCreateSymbolicLink@8
    test eax,eax
    js @f; if (!NT_SUCCESS(status))    return status
;Инициализируем точки входа драйвера в объекте драйвера. Всё что нам нужно
;это операции создания (Create), закрытия (Close) и выгрузки (Unload)
    mov dword ptr (DRIVER_OBJECT PTR [edi]).MajorFunction[IRP_MJ_CREATE*4],offset CreateFileDispatch ; DriverObject->MajorFunction[IRP_MJ_CREATE] = CreateFileDispatch
    mov dword ptr (DRIVER_OBJECT PTR [edi]).MajorFunction[IRP_MJ_CLOSE*4],offset CloseFileDispatch ;    DriverObject->MajorFunction[IRP_MJ_CLOSE] = CloseFileDispatch
    mov dword ptr (DRIVER_OBJECT PTR [edi]).DriverUnload,offset DriverUnload;dword ptr [esi+34h], offset DriverUnload ; DriverObject->DriverUnload  = scp08Unload
    xchg esi,eax; eax=0 return STATUS_SUCCESS
@@: pop ebx
    pop edi
    pop esi
    leave
    retn 8
DriverEntry endp
.data
OriginalAllProcIOPMCopy dd ?
OriginalThroughCreateFileIOPMCopy dd ?
nMaxAllProcessesIOPM dd 0
OrgGDTSize  dw 0;The original sise of the TSS
_IOPMPtr    dd 0
TSSAllProcessesIOPM dd 0
nMaxThroughCreateFileIOPM dd 0
; разрешен доступ к портам 42h,43h,61h
DefaultMap  db 8 dup(-1),0F3h,3 dup(-1),0FDh,72h dup(-1)
end DriverEntry
Первый вариант user-mode приложения, которое запускает драйвер scp08.sys

user-mode приложение, которое запускает scp08.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='scp08.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='scp08',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='\\.\scp08',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 '\\.\scp08.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 приложения, которое запускает драйвер scp08.sys

Предварительно прописываем драйвер scp08.sys в реестре "вручную" (используем функции RegOpenKey, RegCreateKey, RegSetValue) и загружаем драйвер scp08.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
; 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\scp08>
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
    mov esi,offset DrvFilename+4;&esi='scp08.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='scp08',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='\\.\scp08',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;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
    push 43h
    pop edx ;Timer 8253-5 (AT: 8254.2).
    out dx,al;out 43h,al    ;Timer  8253-5 (AT: 8254.2).
    mov esi,offset melody; данные 
    mov ecx,size_melody  ; счетчик
    dec edx;dx=42h
@@: 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 из '\\.\scp08' делаем 'scp08'
    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 '\\.\scp08.sys',0
aSystem     db "SYSTEM\CurrentControlSet\Services",0
aType       db "Type",0
aImagePath  db "ImagePath",0
end start
________________________________________ __________________________________
© Mikl___ 2011
8
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
22.10.2012, 13:50
Доступ к командам In/Out через установку user-mode приложению IOPL=3

Теория

В процессорах Intel, начиная с i286, реализован четырехуровневый механизм защиты. Соответственно, имеется четыре уровня привилегий. Код или данные могут обладать каким-либо уровнем привилегии. Предполагалось, что прикладные программы, системные программы, ядро и т.д. будут работать на своих уровнях, и не будут иметь возможность произвольного доступа к более привилегированному коду или данным. На практике, ни одна ОС для Intel процессоров не использует все четыре уровня. Windows NT не является исключением, используются два уровня (кольца) привилегий. Уровень привилегий 0 (наиболее привилегированный уровень ― уровень супервизора) используется в режиме ядра с полным доступом (full-access kernel mode), и 3 уровень (наименее привилегированный) для более ограниченного режима пользователя (user mode). Текущий уровень привилегий ― Current Privilege Level (CPL) процессора хранится в двух младших битах регистра CS. CPU определяет уровень привилегий ввода/вывода ― I/O Privilege Level (IOPL), значение которого сравнивается с CPL чтобы узнать могут ли использоваться команды In/Out. IOPL хранится в двух битах регистра EFLAGS (биты 12, 13). Любой процесс с CPL большим, чем IOPL должен пройти через механизм защиты портов ввода/вывода. Так как IOPL не может быть меньше 0, программы, исполняющиеся на уровне привилегий 0 (kernel-mode драйвера устройств) будут всегда иметь прямой доступ к портам ввода/вывода. Windows NT устанавливает IOPL в 0. Код user-mode режима всегда имеет CPL равный 3, что больше чем IOPL. Следовательно, доступ к портам ввода/вывода в режиме user-mode должен проходить через механизм защиты. Определение того, что CPL меньше чем IOPL ― это первый этап в механизме защиты.

Еще раз вернемся к псевдокоду команд 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/Writes from/to selected I/O port *)
        FI;
    ELSE (* Real Mode or Protected Mode with CPL <= IOPL *)
        DEST <- SRC; (* Read/Writes from/to selected I/O port *)
FI;
обратите внимание на строку после последнего ELSE! Для kernel-mode режима CPL=0 IOPL=0 и опрерации обращения к портам В/В разрешены, для user-mode режима CPL=3 и IOPL=0 CPL > IOPL и обращение к портам В/В блокируется

Внимание, вопрос ― а что нам мешает сделать IOPL равным 3? CPL = IOPL и обращение к портам, согласно псевдокоду, переходит в разряд непривилегированных операций, доступных для user-mode приложений

Практика

значение PROCESSINFOCLASS
0 ProcessBasicInformation
1 ProcessQuotaLimits
2 ProcessIoCounters
3 ProcessVmCounters
4 ProcessTimes
5 ProcessBasePriority
6 ProcessRaisePriority
7 ProcessDebugPort
8 ProcessExceptionPort
9 ProcessAccessToken
10 ProcessLdtInformation
11 ProcessLdtSize
12 ProcessDefaultHardErrorMode
13 ProcessIoPortHandlers
14 ProcessPooledUsageAndLimits
15 ProcessWorkingSetWatch
16 ProcessUserModeIOPL
17 ProcessEnableAlignmentFaultFixup
18 ProcessPriorityClass
19 ProcessWx86Information
20 ProcessHandleCount
21 ProcessAffinityMask
22 ProcessPriorityBoost
23 ProcessDeviceMap
24 ProcessSessionInformation
25 ProcessForegroundInformation
26 ProcessWow64Information
таблица #1
Программа делает CPL = IOPL из user-mode режима, драйвер не нужен.

Для того, что бы эта программа работала требуется для аккаунта разрешить привилегию "Действовать как часть операционной системы" ("Act as part of the operating system"), она же SeTcbPrivilege, но не обязательно активный. Аккаунт SYSTEM имеет эту привилегию включенной и активной. По умолчанию эта привилегия отключена даже для админского аккаунта.

Описание привилегии "Работа в режиме операционной системы"

Это право пользователя позволяет процессу олицетворять любого пользователя без подтверждения подлинности. Таким образом, процесс может получить доступ к тем же локальным ресурсам, что и пользователь.
Процессы, которым необходима эта привилегия, должны использовать локальную учетную запись, уже включающую данную привилегию, а не отдельную учетную запись пользователя, которой эта привилегия была назначена специально. Если в организации используются только операционные системы семейства Windows Server 2003, предоставлять эту привилегию нет необходимости. Однако если в организации используются серверы под управлением Windows 2000 или Windows NT 4.0, может потребоваться предоставление этой привилегии программам, обменивающимся паролями в текстовом виде.
По умолчанию данной привилегией обладает пользователь "Локальный компьютер".
Предостережение!
Назначение этой привилегии связано с риском для безопасности компьютера. Предоставляйте эту привилегию только надежным пользователям!

Три способа получения привилегии SeTcbPrivilege:
  1. вызвать оснастку "Групповая политика" в Microsoft Management Console (MMC) (Консоль управления Microsoft) и предоставить политику "Действовать как часть операционной системы" пользователю через: клавиша "Пуск" -> "Выполнить" -> "mmc gpedit.msc". Чтобы добраться до раздела "Назначение прав пользователей" в "Локальные политики", последовательно раскройте узлы "Политика "Локальный компьютер" (Local Computer Policy) ->"Конфигурация компьютера" (Computer Configuration) -> "Конфигурация Windows" (Windows Settings) -> "Параметры безопасности" (Security Settings) -> "Локальные политики" (Local Policies) -> "Назначение прав пользователей" (User Rights Management), как показано ниже
  2. нажмите правую клавишу мыши на "Работа в режиме операционной системы" -> "Свойства"-> "Добавить пользователя или группу"-> Вводите имя пользователя->ОК
    Вам нужно будет выйти из системы и снова зайти обратно в систему под логином пользователя, чтобы получить привилегию "Работа в режиме операционной системы",
  3. Вы также можете присвоить привилегию SeTcbPrivilege аккаунту программно,
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
start proc
local hToken:HANDLE
local atr:LUID_AND_ATTRIBUTES 
local privs:TOKEN_PRIVILEGES
        xor ebx,ebx
; устанавливаем привелегию на дейстиве от имени системы 
; Открыть маркер доступа (access token), ассоциирующийся с процессом       
    lea eax,hToken
    push eax; &hToken
    push TOKEN_QUERY or TOKEN_ADJUST_PRIVILEGES; DesiredAccess
    call _imp__GetCurrentProcess@0
    push eax        ; ProcessHandle
    call _imp__OpenProcessToken@12
; Получить текущее значение привилегии
    lea eax,atr.Luid
    push eax        ; lpLuid=&atr.Luid
    push offset aSetcbprivilege ; lpName
    push ebx;0      ; lpSystemName=NULL 
    call _imp__LookupPrivilegeValueA@12 
; Заполнить структуры
    mov ecx,atr.Luid.LowPart
    mov privs.Privileges.Luid.LowPart,ecx
    mov edx,atr.Luid.HighPart
    mov privs.Privileges.Luid.HighPart,edx
;tokenPrivilege.Privileges[0].Luid = luid
    mov privs.Privileges.Attributes,SE_PRIVILEGE_ENABLED
;tokenPrivilege.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED
    mov privs.PrivilegeCount,1;tokenPrivilege.PrivilegeCount = 1  
;Assign the given privilege
    push ebx;0      ; ReturnLength
    push ebx;0      ; PreviousState
    push sizeof(TOKEN_PRIVILEGES);BufferLength
    lea edx,privs
    push edx        ;&tokenPrivilege
    push ebx;FALSE      ; DisableAllPrivileges
    push hToken     ; TokenHandle
    call _imp__AdjustTokenPrivileges@24 
; Enable/disable privileges in the specified access token
        push hToken     ; TokenHandle
    call _imp__CloseHandle@4
Либо выполнить код с правами SYSTEM, что можно сделать, если работать как сервис.
После повышения текущей привелегии до SeTcbPrivilege запускается функция ZwSetInformationProcess, которая имеет четыре параметра:

C++
1
2
3
4
5
6
ZwSetInformationProcess(
    IN HANDLE ProcessHandle,
    IN PROCESSINFOCLASS ProcessInformationClass,
    IN PVOID ProcessInformation,
    IN ULONG ProcessInformationLength
    );
Передаем функции ZwSetInformationProcess в качестве первого параметра ― значение полученное с помощью функции GetCurrentProcess, в качестве второго параметра ― константу ProcessUserModeIOPL = 16 (смотри таблицу #1), в качестве третьего и четвертого параметров ― нули. Функция ZwSetInformationProcess установит IOPL=3 текущему процессу, который получит прямой доступ к портам В/В из User-mode режима.

Далее исходный текст

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
; masm windows gui #
.686P
.model flat
include windows.inc
includelib kernel32.lib
includelib advapi32.lib
includelib ntdll.lib
 
extern _imp__ExitProcess@4:dword 
extern _imp__GetCurrentProcess@0:dword
extern _imp__OpenProcessToken@12:dword
extern _imp__AdjustTokenPrivileges@24:dword
extern _imp__LookupPrivilegeValueA@12:dword
extern _imp__Sleep@4:dword
extern _imp__ZwSetInformationProcess@16:dword
;--------------------------------------
ProcessUserModeIOPL equ 16
.code
 
start proc
local hToken:HANDLE
local atr:LUID_AND_ATTRIBUTES 
local privs:TOKEN_PRIVILEGES
        xor ebx,ebx
; Получить текущее значение привилегии
    lea eax,atr.Luid
    push eax        ; lpLuid=&atr.Luid
    push offset aSetcbprivilege ; lpName
    push ebx;0      ; lpSystemName=NULL 
    call _imp__LookupPrivilegeValueA@12 
; Заполнить структуры
    mov ecx,atr.Luid.LowPart
    mov privs.Privileges.Luid.LowPart,ecx
    mov edx,atr.Luid.HighPart
    mov privs.Privileges.Luid.HighPart,edx
    mov privs.Privileges.Attributes,SE_PRIVILEGE_ENABLED
    mov privs.PrivilegeCount,1 
; Открыть маркер доступа (access token), ассоциирующийся с процессом
; устанавливаем привелегию на действие от имени системы      
    lea eax,hToken
    push eax; &hToken
    push TOKEN_QUERY or TOKEN_ADJUST_PRIVILEGES; DesiredAccess
    call _imp__GetCurrentProcess@0
    push eax        ; ProcessHandle
    call _imp__OpenProcessToken@12 
; Assign the given privilege.
    push ebx;0      ; ReturnLength
    push ebx;0      ; PreviousState
    push ebx;0      ; BufferLength
    lea edx,privs
    push edx        ; NewState
    push ebx;0      ; DisableAllPrivileges
    push hToken     ; TokenHandle
    call _imp__AdjustTokenPrivileges@24 
; Enable/disable privileges in the specified access token
; Здесь будет код, требующий повышенных привилегий
; Grant user mode hardware IO access.
    push ebx;0
    push ebx;0
    push ProcessUserModeIOPL
    call _imp__GetCurrentProcess@0
    push eax
    call _imp__ZwSetInformationProcess@16
    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 
@@: push edx   
    push ecx   
    push 40    ; задержка в 40 мСек
    call _imp__Sleep@4
    pop ecx   
    pop edx ;Команда OUTS выводит данные в порт ввода-вывода, 
    outsb   ;номер которого загружен в регистр DX, 
    loop @b ;из ячейки памяти по адресу DS:ESI    
        in al,61h
    and al,11111100b
    out 61h,al          
 
    push ebx;0
    call _imp__ExitProcess@4
start endp
.data
aSetcbprivilege db "SeTcbPrivilege",0
melody  dw 354h,354h,2,2,387h,387h,2,2,3BDh,3BDh,387h,387h
    dw 3BDh,3BDh,3F5h,3F5h,432h,432h,2,2,472h,472h,2,2
    dw 4 dup(4B5h),4 dup(472h),3F5h,3F5h,2,2,432h,432h,2
    dw 2,472h,472h,432h,432h,472h,472h,4B5h,4B5h,4FDh,4FDh
    dw 2,2,549h,549h,2,2,4 dup(599h),4 dup(549h),472h,472h
    dw 2,2 dup(2,5EEh),2,4 dup(649h),4 dup(5EEh),472h,472h
    dw 2,2 dup(2,5EEh),2,4 dup(649h),4 dup(5EEh),70Eh,70Eh
    dw 6A8h,6A8h,649h,649h,5EEh,5EEh,599h,599h,549h,549h
    dw 4FDh,4FDh,4B5h,4B5h,472h,472h,2,2,432h,432h,2,2
    dw 3F5h,3F5h,2,2,387h,387h,2,2,8 dup(354h),2    
size_melody = $ - melody
end start
Программа работает, давайте ее немного улучшим!

Разберем нашу программу по шагам.

Сначала мы передаем функции LookupPrivilegeValue указатель на структуру LUID_AND_ATTRIBUTES и функция LookupPrivilegeValue заполняет эту структуру текущими значениями привилегии SeTcbPrivilege, далее, на основании данных из структуры LUID_AND_ATTRIBUTES заполняем структуру TOKEN_PRIVILEGES и передаем указатель на структуру TOKEN_PRIVILEGES функции AdjustTokenPrivileges. Но структура TOKEN_PRIVILEGES уже содержит внутри себя структуру LUID_AND_ATTRIBUTES!

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
LUID STRUCT
  LowPart   DWORD      ?
  HighPart  DWORD      ?
LUID ENDS
 
LUID_AND_ATTRIBUTES STRUCT
    Luid LUID <>
    Attributes  DWORD ?
LUID_AND_ATTRIBUTES ENDS
 
TOKEN_PRIVILEGES STRUCT
  PrivilegeCount    DWORD ?
  Privileges        LUID_AND_ATTRIBUTES ANYSIZE_ARRAY dup(<>)
TOKEN_PRIVILEGES ENDS
Зачем "переливать из пустого в порожнее" и заполнять на основе одной структуры другую? Сразу передадим функции LookupPrivilegeValue указатель на структуру TOKEN_PRIVILEGES смещенный на 4 байта
Code
1
2
3
4
5
6
TOKEN_PRIVILEGES STRUCT
  PrivilegeCount    DWORD ?
  LowPart       DWORD ?
  HighPart      DWORD ?
  Attributes        DWORD ?
TOKEN_PRIVILEGES ENDS
Заменим функцию OpenProcessToken на вызов прерывания 2Eh
Assembler
1
2
3
    mov al,NtOpenProcessToken;= 7Bh
    mov edx,esp
    int 2Eh
Заменим функцию AdjustPrivilegesToken на вызов прерывания 2Eh
Assembler
1
2
3
    mov al,NtAdjustPrivilegesToken;= 0Bh
    mov edx,esp
    int 2Eh
Заменим функцию ZwSetInformationProcess на вызов прерывания 2Eh
Assembler
1
2
3
    mov al,NtSetInformationProcess;= 0E4h
    mov edx,esp
    int 2Eh
Какой смысл вызывать функцию GetCurrentProcess если она всегда возвращает в eax значение 0FFFFFFFFh? Сразу передаем функциям OpenProcessToken и ZwSetInformationProcess в качестве аргумента число -1
при старте нашего приложения на вершине стека лежит адрес функции kernel32.TerminateProcess, а именно ее вызывает функция ExitProcess, поэтому заменяем вызов ExitProcess на команду retn, которая извлечет из стека адрес функции TerminateProcess и передаст на нее управление.
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
; masm windows gui #
.686P
.model flat
include windows.inc
includelib kernel32.lib
includelib advapi32.lib
includelib ntdll.lib
 
;extern _imp__ExitProcess@4:dword 
extern _imp__LookupPrivilegeValueA@12:dword
extern _imp__Sleep@4:dword
;--------------------------------------
NtOpenProcessToken = 7Bh
NtAdjustPrivilegesToken = 0Bh
NtSetInformationProcess = 0E4h
ProcessUserModeIOPL = 16
.code
 
start proc
    sub esp,10h; место в стеке под структуру TOKEN_PRIVILEGES
        xor ebx,ebx
; Получить текущее значение привилегии
    push esp        ; esp=&atr.Luid
    push offset aSetcbprivilege ; lpName
    push ebx        ; lpSystemName=NULL 
    call _imp__LookupPrivilegeValueA@12 
; Заполнить структуру TOKEN_PRIVILEGES
        mov dword ptr [esp+8],SE_PRIVILEGE_ENABLED;privs.Attributes=SE_PRIVILEGE_ENABLED
; Открыть маркер доступа (access token), ассоциирующийся с процессом       
    lea ecx,[esp+0Ch]   ; TokenHandle
    push ecx        ; &TokenHandle
    push TOKEN_QUERY or TOKEN_ADJUST_PRIVILEGES; DesiredAccess
    push -1         ; CurrentProcessHandle
        mov al,NtOpenProcessToken
    mov edx,esp
    int 2Eh
    add esp,12
    push 1          ; privs.PrivilegeCount=1
    mov edx,esp
    push ebx        ; ReturnLength=0
    push ebx        ; PreviousState=0
    push ebx        ; BufferLength=0
    push edx        ; NewState=&privs
    push ebx        ; DisableAllPrivileges=0
    push dword ptr [esp+24h]; TokenHandle
    mov al,NtAdjustPrivilegesToken
    mov edx,esp; Enable/disable privileges in the specified access token
    int 2Eh
; Здесь будет код, требующий повышенных привилегий, 
    push ebx;0
    push ebx;0
    push ProcessUserModeIOPL
    push -1; CurrentProcessHandle
    mov al,NtSetInformationProcess
    mov edx,esp
    int 2Eh
    add esp,16+24+20; выравниваем стек и удаляем структуру TOKEN_PRIVILEGES
;play melody
    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 
@@: push edx   
    push ecx
    push 40    ; задержка в 40 мСек
    call _imp__Sleep@4
    pop ecx   
    pop edx ;Команда OUTS выводит данные в порт ввода-вывода, 
    outsb   ;номер которого загружен в регистр DX, 
    loop @b ;из ячейки памяти по адресу DS:ESI    
        in al,61h
    and al,11111100b
    out 61h,al
    retn            
start endp
.data
aSetcbprivilege db "SeTcbPrivilege",0
melody  dw 354h,354h,2,2,387h,387h,2,2,3BDh,3BDh,387h,387h
    dw 3BDh,3BDh,3F5h,3F5h,432h,432h,2,2,472h,472h,2,2
    dw 4 dup(4B5h),4 dup(472h),3F5h,3F5h,2,2,432h,432h,2
    dw 2,472h,472h,432h,432h,472h,472h,4B5h,4B5h,4FDh,4FDh
    dw 2,2,549h,549h,2,2,4 dup(599h),4 dup(549h),472h,472h
    dw 2,2 dup(2,5EEh),2,4 dup(649h),4 dup(5EEh),472h,472h
    dw 2,2 dup(2,5EEh),2,4 dup(649h),4 dup(5EEh),70Eh,70Eh
    dw 6A8h,6A8h,649h,649h,5EEh,5EEh,599h,599h,549h,549h
    dw 4FDh,4FDh,4B5h,4B5h,472h,472h,2,2,432h,432h,2,2
    dw 3F5h,3F5h,2,2,387h,387h,2,2,8 dup(354h),2    
size_melody = $ - melody
end start
Доступ к командам In/Out через установку user-mode приложению IOPL=3 работает в Windows XP и не работает в Windows 7
________________________________________ ____
© Mikl___ 2011
Миниатюры
Зачем нужен драйвер и как написать простейший драйвер  
6
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
23.10.2012, 04:28
Доступ к командам In/Out через установку user-mode приложению IOPL=3

Доступ к портам ввода-вывода из user-mode приложения без драйвера

Код выполняется с правами SYSTEM, что можно сделать, если работать как сервис, то есть с привилегией "Действовать как часть операционной системы" ("Act as part of the operating system"), она же SeTcbPrivilege. Далее вызывается функция ZwSetInformationProcess (-1, 16, 0, 0) и устанавливаем IOPL=3. Проверено под WinXP SP3. Идея взята здесь.

Далее исходный текст scp13
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
; masm windows gui #
;по мотивам кода взятого на h ttp://www.masm32.com/board/index.php?topic=13290.0
;-------------------------------------------------
.686P
.model flat
include windows.inc
include accctrl.inc
 
includelib kernel32.lib
includelib user32.lib
includelib advapi32.lib
includelib ntdll.lib
 
extern _imp__OpenProcess@12:dword
extern _imp__OpenProcessToken@12:dword
extern _imp__GetSecurityInfo@32:dword
extern _imp__Process32Next@8:dword
extern _imp__lstrcmpA@8:dword
extern _imp__CharUpperA@4:dword
extern _imp__ConvertStringSidToSidA@8:dword
extern _imp__SetEntriesInAclA@16:dword
extern _imp__LocalFree@4:dword
extern _imp__CloseHandle@4:dword
extern _imp__ImpersonateLoggedOnUser@4:dword
extern _imp__ZwSetInformationProcess@16:dword
extern _imp__ExitProcess@4:dword
extern _imp__Process32First@8:dword
extern _imp__SetSecurityInfo@28:dword
extern _imp__CreateToolhelp32Snapshot@8:dword
extern _imp__Sleep@4:dword
 
ProcessUserModeIOPL    equ 16
; --------------------------------------------
.code
start proc
LOCAL   m_hToken:DWORD
LOCAL   hToken:HANDLE
LOCAL   pAcl:DWORD
LOCAL   pAclMod:DWORD
LOCAL   ea:EXPLICIT_ACCESS
LOCAL   procEntry:PROCESSENTRY32
 
    xor ebx,ebx
;GetWinLogon:
    push ebx;0
    push TH32CS_SNAPPROCESS
    call _imp__CreateToolhelp32Snapshot@8 
    inc eax;.if (eax != INVALID_HANDLE_VALUE)
    jz exit
    dec eax
    xchg edi,eax
    lea esi,procEntry
    assume esi: ptr PROCESSENTRY32
    mov [esi].dwSize, SIZEOF PROCESSENTRY32
    push esi
    push edi
    call _imp__Process32First@8
        test eax,eax;.if (eax != 0)
    jz exit
    push esi
    push edi
    call _imp__Process32Next@8
@@: test eax,eax
    jz exit
    lea eax,[esi].szExeFile
    push eax
    call _imp__CharUpperA@4
    push offset WinLogOn
    lea eax,[esi].szExeFile
    push eax
    call _imp__lstrcmpA@8
    xchg ecx,eax
    jecxz @f;.if (eax != 0)
    push esi
    push edi
    call _imp__Process32Next@8 
    jmp short @b;.while (eax != 0)
@@: mov eax,[esi].th32ProcessID
    assume esi:nothing
    test eax,eax
    jz exit;.if (eax != 0) 
    push eax
    push ebx;FALSE
    push MAXIMUM_ALLOWED
    call _imp__OpenProcess@12
    test eax,eax
    jz exit;.if (eax != 0)
    xchg esi,eax    ;esi := hProcess
    lea edi,hToken
    push edi
    push READ_CONTROL OR WRITE_DAC
    push esi
    call _imp__OpenProcessToken@12
    xchg ecx,eax
    jecxz a0;.if (eax != 0)
    push ebx
    push ebx
    lea eax,pAcl
    push eax
    push ebx
    push ebx
    push DACL_SECURITY_INFORMATION
    push SE_KERNEL_OBJECT
    push dword ptr [edi];push hToken
        call _imp__GetSecurityInfo@32 
        test eax,eax;.if (eax == 0)
    jnz short a1
    mov ecx,SIZEOF(EXPLICIT_ACCESS)/4
    lea edi,ea
    rep stosd;RtlZeroMemory(&ea,sizof(ea)) 
    sub edi,SIZEOF(EXPLICIT_ACCESS)
    assume edi: ptr EXPLICIT_ACCESS
        mov [edi].grfAccessPermissions,TOKEN_QUERY OR TOKEN_DUPLICATE \
        OR TOKEN_ASSIGN_PRIMARY
        mov [edi].grfAccessMode,GRANT_ACCESS
    lea eax,[edi].Trustee.ptstrName
    push eax
    push offset S1
        call _imp__ConvertStringSidToSidA@8
        xchg ecx,eax;.if (eax != 0)
    jecxz a1
    lea eax,pAclMod
    push eax
    push pAcl
    push edi;&ea
    push 1
    call _imp__SetEntriesInAclA@16
        test eax,eax;.if (eax == 0)
    jnz short @f
    push ebx
    push pAclMod
    push ebx
    push ebx
    push DACL_SECURITY_INFORMATION
    push SE_KERNEL_OBJECT
    push hToken
        call _imp__SetSecurityInfo@28
@@: push [edi].Trustee.ptstrName
    assume edi:nothing
        xchg edi,eax
        call _imp__LocalFree@4
a1: push hToken
    call _imp__CloseHandle@4
a0: test edi,edi
    jnz short @f
    lea eax,m_hToken
    push eax
    push MAXIMUM_ALLOWED
    push esi
        call _imp__OpenProcessToken@12
@@: push esi
    call _imp__CloseHandle@4
    mov ecx,m_hToken
    jecxz exit;.if (ecx != 0)
    push ecx
    call _imp__ImpersonateLoggedOnUser@4
        xchg ecx,eax;test eax,eax;.if (eax != 0)
    jecxz exit;jz short exit
    push ebx;0
    push ebx;0
    push ProcessUserModeIOPL
    push -1;CurrentProcessHandle
    call _imp__ZwSetInformationProcess@16
        test eax,eax;.if (eax == 0)
    jnz short exit
;--------------------------------------------------------------
    in al,61h;текущее состояние порта 61h в AL    
    or al,00000011b;установить 0-ой и 1-ый биты   
    out 61h,al  ;теперь динамик включен
    mov al,0B6h
    push 43h
    pop edx
    out dx,al
        mov esi,offset melody; данные 
    mov ecx,size_melody  ; счетчик
    dec edx;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    
        in al,61h
    and al,11111100b;сбросить 0-ой и 1-ый биты
    out 61h,al
;-------------------------------------------------------------- 
exit:   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)
    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
    dw 2,2 dup(387h),2,2,8 dup(354h),2
size_melody = $ - melody
S1  db "S-1-1-0",0
WinLogOn db "WINLOGON.EXE",0
end start
________________________________________ ___
© Mikl___ 2011
5
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
23.10.2012, 06:32
Доступ к командам In/Out через установку user-mode приложению IOPL=3

scp09 при открытии драйвера через CreateFile("\\.\scp09") получаем адрес процесса через IoGetCurrentProcess. Устанавливаем поле KPROCESS.Iopl равным TRUE, в user-mode приложении создаем и запускаем поток, содержащий команды In/Out, для этого нового потока IOPL обновится, следом, после переключения задач, обновится EFLAGS. Полнофункциональный драйвер.

Далее исходный текст драйвера scp09.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
; masm windows native #
.686P
.model flat
;---------------------------------------------------------------------------
include ntddk.inc
include ntstatus.inc
include w2kundoc.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
;extern _imp__IoGetCurrentProcess@0:dword
;---------------------------------------------------------------------------
IOCTL_ENABLE_IOPM_ON_PROCESSID      equ 9C40240Ch
;---------------------------------------------------------------------------
.const
CCOUNTED_UNICODE_STRING "\\Device\\scp09", cusDevice, 4
CCOUNTED_UNICODE_STRING "\\DosDevices\\scp09", cusSymbolicLink, 4
;---------------------------------------------------------------------------
.code
;---------------------------------------------------------------------------
CreateDispatch proc 
lpIrp        equ dword ptr [esp+8];:PIRP
 
    ;call _imp__IoGetCurrentProcess@0
    assume fs:nothing
    mov eax,fs:[124h]
    mov eax,[eax+44h]
    mov (KPROCESS ptr [eax]).Iopl,3                 
    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
    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
    js 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
    js 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
    xor eax,eax;return STATUS_SUCCESS
    jmp short @f
    mov eax,STATUS_INSUFFICIENT_RESOURCES
;return STATUS_INSUFFICIENT_RESOURCES
@@: pop esi
    leave
    retn 8
DriverEntry endp
;---------------------------------------------------------------------------
DriverUnload:
DriverObject    equ dword ptr [esp+4];:PDRIVER_OBJECT
 
    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
;---------------------------------------------------------------------------
end DriverEntry
Первый вариант user-mode приложения, которое запускает драйвер scp09.sys

user-mode приложение, которое запускает scp09.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
; 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__GetLastError@0:dword
extern _imp__DeleteService@4:dword
extern _imp__ControlService@12:dword
extern _imp__QueryServiceStatus@8:dword
extern _imp__CreateThread@24:dword 
extern _imp__TerminateThread@8:dword
 
ascp09 equ  a_scp09+4
 
.code
;--------------------------------------------
start   proc
local   scp09_Handle:HANDLE
local   SchSCManager:SC_HANDLE  
local   schService:SC_HANDLE  ;
local   acDriverPath[MAX_PATH]:byte
local   hThread:HANDLE
local   Status:SERVICE_STATUS
 
    xor ebx,ebx;ebx:=0
;Install scp09 Driver
    push eax
    push esp
    lea edi,acDriverPath
    push edi
    push MAX_PATH
    push offset ascp09
    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 ascp09 ;    "scp09"      name to display and name of service
    mov [ecx+5],ebx; делаю из "\\.\scp09.sys" "\\.\scp09"
    push ecx; lpDisplayName         name to display = scp09
    push ecx; lpServiceName         name of service = scp09
    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 a4
    call edi;_imp__GetLastError@0
    cmp eax,ERROR_SERVICE_EXISTS;431h
    push ebx;0
    push ebx;0
    jnz short @f
    push offset err1 ; "Driver already exists. No action taken"
    jmp short a1
; ---------------------------------------------------------------------------
@@: push offset err2 ; "Unknown error while creating Service"
a1: push ebx;0
    call esi;_imp__MessageBoxA@16
; ---------------------------------------------------------------------------
a4: lea ecx,Status
    push ecx
    push schService
    call _imp__QueryServiceStatus@8
;Start the scp09 Driver. Errors will occur here if scp09.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 a5
    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 @f
    push offset err3; "The driver is already running"
    jmp short a3
;-------------------------------------------------------------------------
@@: 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
a5: 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_scp09 ; "\\\\.\\scp09"; lpFileName
    call _imp__CreateFileA@28
    inc eax;cmp eax,INVALID_HANDLE_VALUE
    jnz @f
a2: push ebx;if(scp09_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
@@: dec eax
    mov scp09_Handle,eax
;----------------------------------------------------------------------------
;драйвер сделал IOPL=3 у процесса, создаем поток, для этого нового потока IOPL 
;обновится, а после переключения задач обновится и поле IOPL в EFLAGS
;Создаем поток
    lea ecx,hThread
    push ecx;указатель на переменную куда помещен дескриптор потока.
        PUSH ebx;флаг определяющий состояние потока. Если флаг равен 0, то 
;выполнение потока начинается немедленно. Если значение флага потока равно 
;CREATE_SUSPENDED, то поток находится в состоянии ожидания и запускается по 
;выполнению функции ResumeThread
        PUSH ebx;Параметр для потоковой функции
        PUSH offset Play_musik ;указатель на потоковую функцию, с вызова которой 
;начинается исполнение потока
        PUSH ebx;размер стека потока. Если параметр равен 0, то берется размер 
;стека по умолчанию, равный размеру стека родительского потока
        PUSH ebx;указатель на структуру атрибутов доступа, обычно 0
        CALL _imp__CreateThread@24 
@@:     cmp flag,0  ; задержка, чтобы отыграла мелодия
    jnz @b
;Удаляем поток
        PUSH ebx;0
        PUSH hThread
        CALL _imp__TerminateThread@8
;-----------------------------------------------------------            
    mov edi,_imp__MessageBoxA@16
        push scp09_Handle   ; hObject
    call _imp__CloseHandle@4; CloseHandle(scp09_Handle)
; ---------------------------------------------------------------------------
    lea ecx,Status
    push ecx            ; 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 @f
; ---------------------------------------------------------------------------
    push ebx
    push ebx
    push offset err6; "Unknown error while stopping driver service"
    push ebx
    call edi;_imp__MessageBoxA@16
@@: push schService;esi
    call _imp__DeleteService@4
    push ebx
    push ebx
    test eax,eax
    jnz short @f
; ---------------------------------------------------------------------------
    push ebx
    push ebx
    push offset err7; "Error removing driver service - driver hasn't been successfully removed"
    push ebx
    call edi;_imp__MessageBoxA@16
@@: 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
;----------------------------------------------------------------
Play_musik:: 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
@@: push edx   
    push ecx   
    push 40    ; задержка в 40 мСек
    call _imp__Sleep@4     
    pop ecx   
    pop edx   ;Команда выводит данные в порт ввода-вывода, 
    outsb     ;номер которого загружен в регистр DX, 
    loop @b  ;из ячейки памяти по адресу DS:ESI
    in al,61h
    and al,11111100b;теперь динамик выключен
    out 61h,al  
    and flag,0;можно удалить поток
    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
;----------------------------------------------------------------
flag    db 1
Status  SERVICE_STATUS <>
a_scp09 db "\\.\scp09.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 приложения, которое запускает драйвер scp09.sys

Предварительно прописываем драйвер scp09.sys в реестре "вручную" (используем функции RegOpenKey, RegCreateKey, RegSetValue) и загружаем драйвер scp08.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
; 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__CreateThread@24:dword 
extern _imp__TerminateThread@8: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
 
ascp09 equ  a_scp09+4
;--------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\scp09>
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]:byte
local   hThread:HANDLE
 
    xor ebx,ebx;ebx:=0
        mov esi,offset DrvFilename+4;&esi='scp08.sys',0
        lea edi,acDriverPath
        mov eax,'\??\'
    stosd;путь к драйверу должен начаться с '\??\'
;Install scp09 Driver
    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; делаю из "\\.\scp09.sys" "\\.\scp09"
        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
        pop eax; выравниваем стек после GetFullPathNameA    
    mov eax,esp
    push 1;dType := 1
        push sizeof(dword)
    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
    sub esi,4;&esi='\\.\scp09',0
    push ebx        ; hTemplateFile
    push FILE_ATTRIBUTE_NORMAL; dwFlagsAndAttributes
    push OPEN_EXISTING  ; dwCreationDisposition
    push ebx        ; lpSecurityAttributes
    push ebx        ; dwShareMode
    push GENERIC_READ   ; dwDesiredAccess
    push esi ; "\\\\.\\scp09"; lpFileName
    call _imp__CreateFileA@28
    inc eax;cmp eax,INVALID_HANDLE_VALUE
    jz short a2;if(scp09_Handle == INVALID_HANDLE_VALUE) goto a2
    dec eax
    push eax;hObject для CloseHandle
;----------------------------------------------------------------------------
;драйвер сделал IOPL=3 у процесса, создаем поток, для этого нового потока IOPL 
;обновится, а после переключения задач обновится и поле IOPL в EFLAGS
;Создаем поток
    lea ecx,hThread
    push ecx;указатель на переменную куда помещен дескриптор потока.
        PUSH ebx;флаг определяющий состояние потока. Если флаг равен 0, то 
;выполнение потока начинается немедленно. Если значение флага потока равно 
;CREATE_SUSPENDED, то поток находится в состоянии ожидания и запускается по 
;выполнению функции ResumeThread
        PUSH ebx;Параметр для потоковой функции
        PUSH offset Play_musik ;указатель на потоковую функцию, с вызова которой 
;начинается исполнение потока
        PUSH ebx;размер стека потока. Если параметр равен 0, то берется размер 
;стека по умолчанию, равный размеру стека родительского потока
        PUSH ebx;указатель на структуру атрибутов доступа, обычно 0
        CALL _imp__CreateThread@24 
@@:     cmp flag,0  ; задержка, чтобы отыграла мелодия
    jnz @b
;Удаляем поток
        PUSH ebx;0
        PUSH hThread
        CALL _imp__TerminateThread@8
;-----------------------------------------------------------            
    call _imp__CloseHandle@4; CloseHandle(scp09_Handle)
; ---------------------------------------------------------------------------
a2: lodsd;add esi,4 из '\\.\scp09' делаем 'scp09'
    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
;----------------------------------------------------------------
Play_musik:: 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
@@: push edx   
    push ecx   
    push 40    ; задержка в 40 мСек
    call _imp__Sleep@4     
    pop ecx   
    pop edx   ;Команда выводит данные в порт ввода-вывода, 
    outsb     ;номер которого загружен в регистр DX, 
    loop @b  ;из ячейки памяти по адресу DS:ESI
    in al,61h
    and al,11111100b;теперь динамик выключен
    out 61h,al  
    and flag,0;можно удалить поток
    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
;----------------------------------------------------------------
flag    db 1
DrvFilename db "\\.\scp09.sys",0
aSystem     db "SYSTEM\CurrentControlSet\Services",0
aType       db "Type",0
aImagePath  db "ImagePath",0
end start
________________________________________ ___
© Mikl___ 2011
6
58 / 57 / 15
Регистрация: 15.09.2012
Сообщений: 557
23.10.2012, 19:21  [ТС]
Где находятся функции используемые при написанни драйвера? Это системные функции ОС запакованые в dll? Какой нитерфейс предоставляет ОС и драйвер для взаимодействия?

Добавлено через 26 минут
Где прочитать все функции используемые в драйверах и описание их? MSDN?
1
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
25.10.2012, 04:25
Цитата Сообщение от ASDFD12 Посмотреть сообщение
Где находятся функции используемые при написанни драйвера?
dll в которых содержатся используемые функции перечисляются в строках
Assembler
1
2
3
includelib kernel32.lib
includelib user32.lib
includelib advapi32.lib
например ExitProcess находится в kernel32.dll, MessageBox в user32.dll и т.д.
набираешь имя функции в строке поиска MSDN и там будет всё об этой функции, правда на английском, но есть Гугл-переводчик...

Добавлено через 6 часов 47 минут
Доступ к командам In/Out через установку user-mode приложению IOPL=3

Драйвер scp10 идентификатор процесса ProcessId получает через DeviceIoControl или из реестра или через WriteFile("\\.\scp10"). В функцию PsLookupProcessByProcessId передаем ProcessId и получаем указатель на KPROCESS. Устанавливаем поле KPROCESS.Iopl равным TRUE, в user-mode приложении создаем и запускаем поток, содержащий команды In/Out.

Далее исходный текст драйвера scp10.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 #
.686P
.model flat
;---------------------------------------------------------------------------
include ntddk.inc
include ntstatus.inc
include w2kundoc.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
extern _imp__PsLookupProcessByProcessId@8:dword
;---------------------------------------------------------------------------
IOCTL_ENABLE_IOPM_ON_PROCESSID      equ 9C40240Ch
;---------------------------------------------------------------------------
.const
CCOUNTED_UNICODE_STRING "\\Device\\scp10", cusDevice, 4
CCOUNTED_UNICODE_STRING "\\DosDevices\\scp10", cusSymbolicLink, 4
;---------------------------------------------------------------------------
.code
;---------------------------------------------------------------------------
CreateDispatch proc 
lpIrp        equ dword ptr [esp+8];:PIRP
                
    mov ecx,lpIrp
    xor edx,edx
    and (_IRP PTR [ecx]).IoStatus.Information,0;Irp->IoStatus.Information = 0;
    and (_IRP PTR [ecx]).IoStatus.Status,STATUS_SUCCESS;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
    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
    js 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
    js 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]).MajorFunction[IRP_MJ_DEVICE_CONTROL*4],offset DeviceControl   
    mov (DRIVER_OBJECT PTR [esi]).DriverUnload,offset DriverUnload
    xor eax,eax;return STATUS_SUCCESS
    jmp short @f
    mov eax,STATUS_INSUFFICIENT_RESOURCES
;return STATUS_INSUFFICIENT_RESOURCES
@@: 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
    assume eax: ptr IO_STACK_LOCATION
    mov ecx,[eax].Parameters.DeviceIoControl.InputBufferLength
;inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength
;switch ( irpSp->Parameters.DeviceIoControl.IoControlCode )
    cmp [eax].Parameters.DeviceIoControl.IoControlCode,IOCTL_ENABLE_IOPM_ON_PROCESSID
    assume eax: nothing
    jnz short @f
    cmp ecx,4 ;if (inBufLength != 4) 
    jnz short @f
    lea eax,Process
    push eax;&Process
    push dword ptr [edi];ProcessID
    call _imp__PsLookupProcessByProcessId@8
    mov eax,Process
    mov (KPROCESS ptr [eax]).Iopl,3
    xor edi,edi;ntStatus = STATUS_SUCCESS
    jmp break
@@: mov edi,STATUS_UNSUCCESSFUL; ntStatus = STATUS_UNSUCCESSFUL;
break:  xor edx,edx; edx = IO_NO_INCREMENT
    mov (_IRP PTR [esi]).IoStatus.Information,edx
;pIrp->IoStatus.Information = 0; /* Output Buffer Size */    
    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
 
    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
;---------------------------------------------------------------------------
end DriverEntry
Первый вариант user-mode приложения, которое запускает драйвер scp10.sys

user-mode приложение, которое запускает scp10.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
249
250
251
252
253
254
255
256
257
258
259
260
; 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
extern _imp__CreateThread@24:dword 
extern _imp__TerminateThread@8:dword
ascp10 equ  a_scp10+4
 
IOCTL_ENABLE_IOPM_ON_PROCESSID      equ 9C40240Ch
 
.code
 
start   proc
local   scp10_Handle:HANDLE
local   SchSCManager:SC_HANDLE  
local   schService:SC_HANDLE  ;
local   acDriverPath[MAX_PATH]:byte
local   hThread:HANDLE
local   Status:SERVICE_STATUS
local   BytesReturned:dword
 
    xor ebx,ebx;ebx:=0
;Install scp10 Driver
    push eax
    push esp
    lea edi,acDriverPath
    push edi
    push MAX_PATH
    push offset ascp10
    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 ascp10 ;    "scp10"      name to display and name of service
    mov [ecx+5],ebx; делаю из "\\.\scp10.sys" "\\.\scp10"
    push ecx; lpDisplayName         name to display = scp10
    push ecx; lpServiceName         name of service = scp10
    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 a4
    call edi;_imp__GetLastError@0
    cmp eax,ERROR_SERVICE_EXISTS;431h
    push ebx;0
    push ebx;0
    jnz short @f
    push offset err1 ; "Driver already exists. No action taken"
    jmp short a1
; ---------------------------------------------------------------------------
@@: push offset err2 ; "Unknown error while creating Service"
a1: push ebx;0
    call esi;_imp__MessageBoxA@16
; ---------------------------------------------------------------------------
a4: lea ecx,Status
    push ecx;&Status
    push schService
    call _imp__QueryServiceStatus@8
;Start the scp10 Driver. Errors will occur here if scp10.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 a5
    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 @f
    push offset err3; "The driver is already running"
    jmp short a3
;-------------------------------------------------------------------------
@@: 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
a5: 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_scp10 ; "\\\\.\\scp10"; lpFileName
    call _imp__CreateFileA@28
    inc eax;cmp eax,INVALID_HANDLE_VALUE
    jnz @f
a2: push ebx;if(scp10_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
@@: dec eax
    mov scp10_Handle,eax
    call _imp__GetCurrentProcessId@0
    mov pi.dwProcessId,eax
    push ebx        ; lpOverlapped
    lea ecx,BytesReturned
    push ecx        ; lpBytesReturned
    push ebx        ; nOutBufferSize
    push ebx        ; lpOutBuffer
    push 4          ; nInBufferSize
    push offset pi.dwProcessId; lpInBuffer
    push IOCTL_ENABLE_IOPM_ON_PROCESSID; dwIoControlCode
    push scp10_Handle   ; hDevice
    call _imp__DeviceIoControl@32
;----------------------------------------------------------------------------
;драйвер сделал IOPL=3 у процесса, создаем поток, для этого нового потока IOPL 
;обновится, а после переключения задач обновится и IOPL в EFLAGS
;Создаем поток
    lea ecx,hThread
    push ecx;указатель на переменную куда помещен дескриптор потока.
        PUSH ebx;флаг определяющий состояние потока. Если флаг равен 0, то 
;выполнение потока начинается немедленно. Если значение флага потока равно 
;CREATE_SUSPENDED, то поток находится в состоянии ожидания и запускается по 
;выполнению функции ResumeThread
        PUSH ebx;Параметр для потоковой функции
        PUSH offset Play_musik ;указатель на потоковую функцию, с вызова которой 
;начинается исполнение потока
        PUSH ebx;размер стека потока. Если параметр равен 0, то берется размер 
;стека по умолчанию, равный размеру стека родительского потока
        PUSH ebx;указатель на структуру атрибутов доступа, обычно 0
        CALL _imp__CreateThread@24 
@@:     cmp flag,0  ; задержка, чтобы отыграла мелодия
    jnz @b
;Удаляем поток
        PUSH ebx;0
        PUSH hThread
        CALL _imp__TerminateThread@8
;-----------------------------------------------------------            
    mov edi,_imp__MessageBoxA@16
        push scp10_Handle   ; hObject
    call _imp__CloseHandle@4; CloseHandle(scp10_Handle)
; ---------------------------------------------------------------------------
    lea ecx,Status
    push ecx        ; 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 @f
; ---------------------------------------------------------------------------
    push ebx
    push ebx
    push offset err6; "Unknown error while stopping driver service"
    push ebx
    call edi;_imp__MessageBoxA@16
@@: push schService;esi
    call _imp__DeleteService@4
    push ebx
    push ebx
    test eax,eax
    jnz short @f
; ---------------------------------------------------------------------------
    push ebx
    push ebx
    push offset err7; "Error removing driver service - driver hasn't been successfully removed"
    push ebx
    call edi;_imp__MessageBoxA@16
@@: 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
;----------------------------------------------------------------
Play_musik:: 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 _imp__Sleep@4     
    pop ecx   
    pop edx   ;Команда выводит данные в порт ввода-вывода, 
    outsb     ;номер которого загружен в регистр DX, 
    loop @b  ;из ячейки памяти по адресу DS:ESI
    in al,61h
    and al,11111100b;теперь динамик выключен
    out 61h,al  
    and flag,0;можно удалить поток
    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
;----------------------------------------------------------------
flag    db 1
pi PROCESS_INFORMATION <>;   /* Process Info Structure - Contains Process ID Information
a_scp10 db "\\.\scp10.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 приложения, которое запускает драйвер scp10.sys

Предварительно прописываем драйвер scp10.sys в реестре "вручную" (используем функции RegOpenKey, RegCreateKey, RegSetValue) и загружаем драйвер scp10.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
201
202
203
204
205
206
; 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__CreateThread@24:dword 
extern _imp__TerminateThread@8: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_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\scp10>
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]:byte
local   hThread:HANDLE
 
    xor ebx,ebx;ebx:=0
        mov esi,offset DrvFilename+4;&esi='scp10.sys',0
        lea edi,acDriverPath
        mov eax,'\??\'
    stosd;путь к драйверу должен начаться с '\??\'
;Install scp10 Driver
    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; делаю из "\\.\scp10.sys" "\\.\scp10"
; ---------------------------------------------------------------------------
        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
    mov dword ptr [eax],1;dType := 1
        push sizeof(dword)
    push eax;&dType
    push REG_DWORD
    push ebx;0
    push offset aType
    push Key2
    call _imp__RegSetValueExA@24
    push Key2
    call _imp__RegCloseKey@4
    push offset cusDevice
    call _imp__ZwLoadDriver@4
    sub esi,4;&esi='\\.\scp10',0
    push ebx        ; hTemplateFile
    push FILE_ATTRIBUTE_NORMAL; dwFlagsAndAttributes
    push OPEN_EXISTING  ; dwCreationDisposition
    push ebx        ; lpSecurityAttributes
    push ebx        ; dwShareMode
    push GENERIC_READ   ; dwDesiredAccess
    push esi ; "\\\\.\\scp10"; lpFileName
    call _imp__CreateFileA@28
    inc eax;cmp eax,INVALID_HANDLE_VALUE
    jz short a0
    dec eax
    mov ecx,esp;&BytesReturned
    push eax; hObject для CloseHandle
    push ebx        ; lpOverlapped
    push ecx        ; lpBytesReturned
    push ebx        ; nOutBufferSize
    push ebx        ; lpOutBuffer
    push 4          ; nInBufferSize
    push offset pi.dwProcessId; lpInBuffer
    push IOCTL_ENABLE_IOPM_ON_PROCESSID; dwIoControlCode
    push eax    ; hDevice
    call _imp__GetCurrentProcessId@0
    mov pi.dwProcessId,eax
    call _imp__DeviceIoControl@32
;----------------------------------------------------------------------------
;драйвер сделал IOPL=3 у процесса, создаем поток, для этого нового потока IOPL 
;обновится, а после переключения задач обновится и IOPL в EFLAGS
;Создаем поток
    lea ecx,hThread
    push ecx;указатель на переменную куда помещен дескриптор потока.
        PUSH ebx;флаг определяющий состояние потока. Если флаг равен 0, то 
;выполнение потока начинается немедленно. Если значение флага потока равно 
;CREATE_SUSPENDED, то поток находится в состоянии ожидания и запускается по 
;выполнению функции ResumeThread
        PUSH ebx;Параметр для потоковой функции
        PUSH offset Play_musik ;указатель на потоковую функцию, с вызова которой 
;начинается исполнение потока
        PUSH ebx;размер стека потока. Если параметр равен 0, то берется размер 
;стека по умолчанию, равный размеру стека родительского потока
        PUSH ebx;указатель на структуру атрибутов доступа, обычно 0
        CALL _imp__CreateThread@24 
@@:     cmp flag,0  ; задержка, чтобы отыграла мелодия
    jnz @b
;Удаляем поток
        PUSH ebx;0
        PUSH hThread
        CALL _imp__TerminateThread@8
;-----------------------------------------------------------            
    call _imp__CloseHandle@4; CloseHandle(scp10_Handle)
; ---------------------------------------------------------------------------
a0:     lodsd;add esi,4 из '\\.\scp10' делаем 'scp10'
    mov [esp],offset cusDevice          
    call _imp__ZwUnloadDriver@4; выравниваем стек после GetFullPathNameA    
    push esi
    push Key
    call _imp__SHDeleteKeyA@8;удаляем непустой ключ из реестра 
    push Key
    call _imp__RegCloseKey@4
; ---------------------------------------------------------------------------
    push ebx
    call _imp__ExitProcess@4
start endp
;----------------------------------------------------------------
Play_musik:: 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 _imp__Sleep@4     
    pop ecx   
    pop edx   ;Команда выводит данные в порт ввода-вывода, 
    outsb     ;номер которого загружен в регистр DX, 
    loop @b  ;из ячейки памяти по адресу DS:ESI
    in al,61h
    and al,11111100b;теперь динамик выключен
    out 61h,al  
    and flag,0;можно удалить поток
    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
;----------------------------------------------------------------
flag    db 1
pi PROCESS_INFORMATION <>;   /* Process Info Structure - Contains Process ID Information
DrvFilename db "\\.\scp10.sys",0
aSystem     db "SYSTEM\CurrentControlSet\Services",0
aType       db "Type",0
aImagePath  db "ImagePath",0
end start
________________________________________
© Mikl___ 2011
5
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
26.10.2012, 03:49
Доступ к командам In/Out через установку user-mode приложению IOPL=3

В драйвере scp11.sys получаем текущий поток и процесс, функция PsGetContextThread извлекает из стека ядра KTRAP_FRAME и преобразует его в структуру CONTEXT. В поле CONTEXT.RegEFlags устанавливаем флаги IOPL=3 и функция PsSetContextThread копирует переданный CONTEXT в KTRAP_FRAME. В user-mode приложении создаем и запускаем поток, содержащий команды In/Out. Полнофункциональный драйвер.

Далее исходный текст драйвера scp11.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
; masm windows native #
.686P
.model flat
;---------------------------------------------------------------------------
include ntddk.inc
include ntstatus.inc
include w2kundoc.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
extern _imp__PsGetContextThread:dword
extern _imp__PsSetContextThread:dword
;-----------------------------------
EFLAGS_IOPL_MASK    equ 3000h
;---------------------------------------------------------------------------
.const
CCOUNTED_UNICODE_STRING "\\Device\\scp11", cusDevice, 4
CCOUNTED_UNICODE_STRING "\\DosDevices\\scp11", cusSymbolicLink, 4
;---------------------------------------------------------------------------
.code
;---------------------------------------------------------------------------
CreateDispatch proc DriverObject,lpIrp
;get current thread and Process, set flag for IOPL in both of them
    sub esp,sizeof(CONTEXT);local Context:CONTEXT
    assume fs:nothing
    mov eax,fs:[124h];GetCurrentThread
    assume eax:ptr KTHREAD
        mov ecx,[eax].ApcState.Process;Process = Thread->ApcState.Process
    assume ecx:ptr KPROCESS   
    mov [ecx].Iopl,TRUE;Process->Iopl = TRUE
        mov [eax].Iopl,TRUE;Thread->Iopl = TRUE
;Force IOPL to be on for current thread
    assume ecx:nothing
    mov ecx,esp;lea ecx,Context
;PsGetContextThread (Thread, &Context, KernelMode) доставляет потоку 
;специальную APC режима ядра, которая извлекает из стека ядра структуру 
;KTRAP_FRAME и преобразует ее в структуру CONTEXT.
    push UserMode
    push ecx;&Context
    push eax;Thread
;--------------------------------------------------------
    push KernelMode
    push ecx;&Context
    push eax;Thread
    call _imp__PsGetContextThread;PsGetContextThread(Thread,&Context,KernelMode)
;учтем, что в стеке находятся параметры для PsSetContextThread
;or Context.ContextFlags,EFLAGS_IOPL_MASK;IOPL = 3
        or dword ptr [esp+12].CONTEXT.ContextFlags,EFLAGS_IOPL_MASK
;установка контекста потока функцией PsSetContextThread, функция копирует 
;переданный CONTEXT в KTRAP_FRAME. 
    call _imp__PsSetContextThread;PsGetContextThread(Thread,&Context,UserMode)              
    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;IoCompleteRequest(Irp, IO_NO_INCREMENT)
    xor eax,eax;return STATUS_SUCCESS
    leave
    retn 8
CreateDispatch endp
;---------------------------------------------------------------------------
DriverEntry proc DriverObject:PDRIVER_OBJECT, RegistryPath:PUNICODE_STRING
local deviceObject:PDEVICE_OBJECT
 
    push esi
    lea ecx,deviceObject
    push ecx;&deviceObject
    push 0;FALSE
    push 0
    push FILE_DEVICE_UNKNOWN
    push offset cusDevice
    push 0                  ;for IoCreateDevice
    mov esi,DriverObject
    push esi;DriverObject
    call _imp__IoCreateDevice;status = IoCreateDevice(DriverObject, 
; 0, &uniNameString, FILE_DEVICE_UNKNOWN, 0, FALSE, &deviceObject)
    test eax,eax
    js short @f;if(!NT_SUCCESS(status)) return status
    push offset cusDevice
    push offset cusSymbolicLink
    call _imp__IoCreateSymbolicLink;status = IoCreateSymbolicLink (&uniDOSString, &uniNameString)
    test eax,eax
    js 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
    xor eax,eax;return STATUS_SUCCESS
    jmp short @f
    mov eax,STATUS_INSUFFICIENT_RESOURCES
;return STATUS_INSUFFICIENT_RESOURCES
@@: pop esi
    leave
    retn 8
DriverEntry endp
;---------------------------------------------------------------------------
DriverUnload:
DriverObject    equ dword ptr [esp+4];:PDRIVER_OBJECT
 
    push offset cusSymbolicLink;eax;&uniDOSString
    call _imp__IoDeleteSymbolicLink;IoDeleteSymbolicLink (&uniDOSString)
    mov eax,DriverObject
    push dword ptr (DRIVER_OBJECT ptr [eax]).DeviceObject
    call _imp__IoDeleteDevice;IoDeleteDevice(DriverObject->DeviceObject)
    retn 4
;---------------------------------------------------------------------------
end DriverEntry
Первый вариант user-mode приложения, которое запускает драйвер scp11.sys

user-mode приложение, которое запускает scp11.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
; 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__GetLastError@0:dword
extern _imp__DeleteService@4:dword
extern _imp__ControlService@12:dword
extern _imp__QueryServiceStatus@8:dword
extern _imp__CreateThread@24:dword 
extern _imp__TerminateThread@8:dword
ascp11 equ  a_scp11+4
 
IOCTL_ENABLE_IOPM_ON_PROCESSID      equ 9C40240Ch
 
.code
 
start   proc
local   scp11_Handle:HANDLE
local   SchSCManager:SC_HANDLE  
local   schService:SC_HANDLE  ;
local   acDriverPath[MAX_PATH]:byte
local   hThread:HANDLE
local   Status:SERVICE_STATUS
local   BytesReturned:dword
 
    xor ebx,ebx;ebx:=0
;Install scp11 Driver
    push eax
    push esp
    lea edi,acDriverPath
    push edi
    push MAX_PATH
    push offset ascp11
    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 ascp11 ;    "scp11"      name to display and name of service
    mov [ecx+5],ebx; делаю из "\\.\scp11.sys" "\\.\scp11"
    push ecx; lpDisplayName         name to display = scp11
    push ecx; lpServiceName         name of service = scp11
    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 a4
    call edi;_imp__GetLastError@0
    cmp eax,ERROR_SERVICE_EXISTS;431h
    push ebx;0
    push ebx;0
    jnz short @f
    push offset err1 ; "Driver already exists. No action taken"
    jmp short a1
; ---------------------------------------------------------------------------
@@: push offset err2 ; "Unknown error while creating Service"
a1: push ebx;0
    call esi;_imp__MessageBoxA@16
; ---------------------------------------------------------------------------
a4: lea ecx,Status
    push ecx;&Status
    push schService
    call _imp__QueryServiceStatus@8
;Start the scp11 Driver. Errors will occur here if scp11.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 a5
    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 @f
    push offset err3; "The driver is already running"
    jmp short a3
;-------------------------------------------------------------------------
@@: 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
a5: 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_scp11 ; "\\\\.\\scp11"; lpFileName
    call _imp__CreateFileA@28
    inc eax;cmp eax,INVALID_HANDLE_VALUE
    jnz @f
a2: push ebx;if(scp11_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
@@: dec eax
    mov scp11_Handle,eax
;----------------------------------------------------------------------------
;драйвер сделал IOPL=3 у процесса, создаем поток, для этого нового потока IOPL 
;обновится, а после переключения задач обновится и IOPL в EFLAGS
;Создаем поток
    lea ecx,hThread
    push ecx;указатель на переменную куда помещен дескриптор потока.
        PUSH ebx;флаг определяющий состояние потока. Если флаг равен 0, то 
;выполнение потока начинается немедленно. Если значение флага потока равно 
;CREATE_SUSPENDED, то поток находится в состоянии ожидания и запускается по 
;выполнению функции ResumeThread
        PUSH ebx;Параметр для потоковой функции
        PUSH offset Play_musik ;указатель на потоковую функцию, с вызова которой 
;начинается исполнение потока
        PUSH ebx;размер стека потока. Если параметр равен 0, то берется размер 
;стека по умолчанию, равный размеру стека родительского потока
        PUSH ebx;указатель на структуру атрибутов доступа, обычно 0
        CALL _imp__CreateThread@24 
@@:     cmp flag,0  ; задержка, чтобы отыграла мелодия
    jnz @b
;Удаляем поток
        PUSH ebx;0
        PUSH hThread
        CALL _imp__TerminateThread@8
;-----------------------------------------------------------            
    mov edi,_imp__MessageBoxA@16
        push scp11_Handle   ; hObject
    call _imp__CloseHandle@4; CloseHandle(scp11_Handle)
; ---------------------------------------------------------------------------
    lea ecx,Status
    push ecx        ; 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 @f
; ---------------------------------------------------------------------------
    push ebx
    push ebx
    push offset err6; "Unknown error while stopping driver service"
    push ebx
    call edi;_imp__MessageBoxA@16
@@: push schService;esi
    call _imp__DeleteService@4
    push ebx
    push ebx
    test eax,eax
    jnz short @f
; ---------------------------------------------------------------------------
    push ebx
    push ebx
    push offset err7; "Error removing driver service - driver hasn't been successfully removed"
    push ebx
    call edi;_imp__MessageBoxA@16
@@: 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
;----------------------------------------------------------------
Play_musik:: 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 _imp__Sleep@4     
    pop ecx   
    pop edx   ;Команда выводит данные в порт ввода-вывода, 
    outsb     ;номер которого загружен в регистр DX, 
    loop @b  ;из ячейки памяти по адресу DS:ESI
    in al,61h
    and al,11111100b;теперь динамик выключен
    out 61h,al  
    and flag,0;можно удалить поток
    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
;----------------------------------------------------------------
flag    db 1
a_scp11 db "\\.\scp11.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 приложения, которое запускает драйвер scp11.sys

Предварительно прописываем драйвер scp11.sys в реестре "вручную" (используем функции RegOpenKey, RegCreateKey, RegSetValue) и загружаем драйвер scp11.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
; masm windows gui #
.686P
.model flat
include windows.inc
 
includelib kernel32.lib
includelib ntdll.lib
includelib advapi32.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__CreateThread@24:dword 
extern _imp__TerminateThread@8: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\scp11>
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]:byte
local   hThread:HANDLE
 
    xor ebx,ebx;ebx:=0
        mov esi,offset DrvFilename+4;&esi='scp11.sys',0
        lea edi,acDriverPath
        mov eax,'\??\'
    stosd;путь к драйверу должен начаться с '\??\'
;Install scp11 Driver
    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; из "\\.\scp11.sys" делаю "\\.\scp11"
        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;указатель на пустое место в стеке
    mov dword ptr [eax],1;dType := 1
        push sizeof(dword)
    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;выравниваем стек после GetFullPathNameA  
    call _imp__ZwLoadDriver@4
    sub esi,4;&esi='\\.\scp11',0
    push ebx        ; hTemplateFile
    push FILE_ATTRIBUTE_NORMAL; dwFlagsAndAttributes
    push OPEN_EXISTING  ; dwCreationDisposition
    push ebx        ; lpSecurityAttributes
    push ebx        ; dwShareMode
    push GENERIC_READ   ; dwDesiredAccess
    push esi ; "\\.\scp11"; lpFileName
    call _imp__CreateFileA@28
    inc eax;cmp eax,INVALID_HANDLE_VALUE
    jz short a0
    dec eax
    push eax
;----------------------------------------------------------------------------
;драйвер сделал IOPL=3 у процесса, создаем поток, для этого нового потока IOPL 
;обновится, а после переключения задач обновится и IOPL в EFLAGS
;Создаем поток
    lea ecx,hThread
    push ecx;указатель на переменную куда помещен дескриптор потока.
        PUSH ebx;флаг определяющий состояние потока. Если флаг равен 0, то 
;выполнение потока начинается немедленно. Если значение флага потока равно 
;CREATE_SUSPENDED, то поток находится в состоянии ожидания и запускается по 
;выполнению функции ResumeThread
        PUSH ebx;Параметр для потоковой функции
        PUSH offset Play_musik ;указатель на потоковую функцию, с вызова которой 
;начинается исполнение потока
        PUSH ebx;размер стека потока. Если параметр равен 0, то берется размер 
;стека по умолчанию, равный размеру стека родительского потока
        PUSH ebx;указатель на структуру атрибутов доступа, обычно 0
        CALL _imp__CreateThread@24 
@@:     cmp flag,0  ; задержка, чтобы отыграла мелодия
    jnz @b
;Удаляем поток
        PUSH ebx;0
        PUSH hThread
        CALL _imp__TerminateThread@8
;-----------------------------------------------------------            
    call _imp__CloseHandle@4; CloseHandle(scp11_Handle)
; ---------------------------------------------------------------------------
a0: lodsd;add esi,4 из '\\.\scp11' делаем 'scp11'
    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
;----------------------------------------------------------------
Play_musik:: 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
@@: push edx   
    push ecx   
    push 40    ; задержка в 40 мСек
    call _imp__Sleep@4     
    pop ecx   
    pop edx   ;Команда выводит данные в порт ввода-вывода, 
    outsb     ;номер которого загружен в регистр DX, 
    loop @b  ;из ячейки памяти по адресу DS:ESI
    in al,61h
    and al,11111100b;теперь динамик выключен
    out 61h,al  
    and flag,0;можно удалить поток
    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
;----------------------------------------------------------------
flag        db 1
DrvFilename db "\\.\scp11.sys",0
aSystem     db "SYSTEM\CurrentControlSet\Services",0
aType       db "Type",0
aImagePath  db "ImagePath",0
end start
________________________________________ _____
© Mikl___ 2011
5
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
26.10.2012, 04:31
Доступ к командам In/Out через установку user-mode приложению IOPL=3

Далее исходный текст драйвера scp12.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
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
249
250
251
252
; masm windows native #
.686P
.model flat
;---------------------------------------------------------------------------
include ntddk.inc
include ntstatus.inc
include w2kundoc.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
extern _imp__KeGetCurrentThread:dword
extern _imp__PsGetContextThread:dword
extern _imp__PsSetContextThread:dword
;-----------------------------------
KTRAP_FRAME_LENGTH  equ 8Ch
NPX_FRAME_LENGTH    equ 210h
EFLAGS_IOPL_MASK    equ 3000h
CONTEXT_i386        equ 10000h
CONTEXT_CONTROL     equ CONTEXT_i386 + 00000001h
 
KTRAP_FRAME struct
;Following 4 values are only used and defined for DBG systems,
;but are always allocated to make switching from DBG to non-DBG
;and back quicker.  They are not DEVL because they have a non-0
;performance impact.
DbgEbp      ULONG ?;Copy of User EBP set up so KB will work.
DbgEip      ULONG ?;EIP of caller to system call, again, for KB.
DbgArgMark  ULONG ?;Marker to show no args here.
DbgArgPointer   ULONG ?;Pointer to the actual args
;Temporary values used when frames are edited.
;  NOTE:   Any code that want's ESP must materialize it, since it
;          is not stored in the frame for kernel mode callers.
;
;          And code that sets ESP in a KERNEL mode frame, must put
;          the new value in TempEsp, make sure that TempSegCs holds
;          the real SegCs value, and put a special marker value into SegCs.
TempSegCs   ULONG ?
TempEsp     ULONG ?
;Debug registers.
rDr0        ULONG ?
rDr1        ULONG ?
rDr2        ULONG ?
rDr3        ULONG ?
rDr6        ULONG ?
rDr7        ULONG ?
;Segment registers
SegGs       ULONG ?
SegEs       ULONG ?
SegDs       ULONG ?
;Volatile registers
rEdx        ULONG ?
rEcx        ULONG ?
rEax        ULONG ?
;Nesting state, not part of context record
PreviousPreviousMode    ULONG ?
;Trash if caller was user mode. Saved exception list if caller
;was kernel mode or we're in an interrupt.
ExceptionList   PVOID ?
 
SegFs       ULONG ?
;Non-volatile registers
rEdi        ULONG ?
rEsi        ULONG ?
rEbx        ULONG ?
rEbp        ULONG ?
 
; IRET-frame.
ErrCode     ULONG ?
rEip        ULONG ?
rSegCs      ULONG ?
rEFlags     ULONG ?
 
HardwareEsp ULONG ?;WARNING - segSS:esp are only here for stacks
HardwareSegSs   ULONG ?;that involve a ring transition.
 
V86Es       ULONG ?;these will be present for all transitions from
V86Ds       ULONG ?;V86 mode
V86Fs       ULONG ?
V86Gs       ULONG ?
KTRAP_FRAME ends
PKTRAP_FRAME typedef ptr KTRAP_FRAME
 
;CONTEXT STRUCT         ; sizeof = 02CCh
 
    ; The flags values within this flag control the contents of
    ; a CONTEXT record.
    ;
    ; If the context record is used as an input parameter, then
    ; for each portion of the context record controlled by a flag
    ; whose value is set, it is assumed that that portion of the
    ; context record contains valid context. If the context record
    ; is being used to modify a threads context, then only that
    ; portion of the threads context will be modified.
    ;
    ; If the context record is used as an IN OUT parameter to capture
    ; the context of a thread, then only those portions of the thread's
    ; context corresponding to set flags will be returned.
    ;
    ; The context record is never used as an OUT only parameter.
 
;   ContextFlags        DWORD       ?   ; 0000h
 
    ; This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
    ; set in ContextFlags.  Note that CONTEXT_DEBUG_REGISTERS is NOT
    ; included in CONTEXT_FULL.
 
;   regDr0              DWORD       ?   ; 0004h
;   regDr1              DWORD       ?   ; 0008h
;   regDr2              DWORD       ?   ; 000Ch
;   regDr3              DWORD       ?   ; 0010h
;   regDr6              DWORD       ?   ; 0014h
;   regDr7              DWORD       ?   ; 0018h
 
    ; This section is specified/returned if the
    ; ContextFlags word contians the flag CONTEXT_FLOATING_POINT.
 
;   FloatSave           FLOATING_SAVE_AREA <>   ; 001Ch
 
    ; This section is specified/returned if the
    ; ContextFlags word contians the flag CONTEXT_SEGMENTS.
 
;   regSegGs            DWORD       ?   ; 008Ch
;   regSegFs            DWORD       ?   ; 0090h
;   regSegEs            DWORD       ?   ; 0094h
;   regSegDs            DWORD       ?   ; 0098h
 
    ; This section is specified/returned if the
    ; ContextFlags word contians the flag CONTEXT_INTEGER.
 
;   regEdi              DWORD       ?   ; 009Ch
;   regEsi              DWORD       ?   ; 00A0h
;   regEbx              DWORD       ?   ; 00A4h
;   regEdx              DWORD       ?   ; 00A8h
;   regEcx              DWORD       ?   ; 00ACh
;   regEax              DWORD       ?   ; 00B0h
 
    ; This section is specified/returned if the
    ; ContextFlags word contians the flag CONTEXT_CONTROL.
 
;   regEbp              DWORD       ?   ; 00B4h
;   regEip              DWORD       ?   ; 00B8h
;   regSegCs            DWORD       ?   ; 00BCh  MUST BE SANITIZED
;   regEFlags           DWORD       ?   ; 00C0h  MUST BE SANITIZED
;   regEsp              DWORD       ?   ; 00C4h
;   regSegSs            DWORD       ?   ; 00C8h
 
 
    ; This section is specified/returned if the ContextFlags word
    ; contains the flag CONTEXT_EXTENDED_REGISTERS.
    ; The format and contexts are processor specific
 
;   ExtendedRegisters   BYTE        MAXIMUM_SUPPORTED_EXTENSION dup(?)  ; 00CCh
 
;CONTEXT ENDS
;---------------------------------------------------------------------------
.const
CCOUNTED_UNICODE_STRING "\\Device\\scp12", cusDevice, 4
CCOUNTED_UNICODE_STRING "\\DosDevices\\scp12", cusSymbolicLink, 4
;---------------------------------------------------------------------------
.code
;---------------------------------------------------------------------------
CreateDispatch proc DriverObject,lpIrp
;local Thread:PKTHREAD
local Context:CONTEXT
;get current thread and Process, set flag for IOPL in both of them
    assume fs:nothing
    ;mov eax,fs:[124h];
    call _imp__KeGetCurrentThread
;   mov Thread,eax;Thread = KeGetCurrentThread()
    assume eax:ptr KTHREAD
        mov ecx,[eax].ApcState.Process;Process = Thread->ApcState.Process
    assume ecx:ptr KPROCESS   
    mov [ecx].Iopl,TRUE;Process->Iopl = TRUE
;Force IOPL to be on for current thread
    assume ecx:nothing
    mov ecx,esp;lea ecx,Context
;PsGetContextThread (Thread, &Context, KernelMode) доставляет потоку специальную 
;APC режима ядра(PspGetSetContextSpecialApc),которая извлекает из стека ядра 
;KTRAP_FRAME и преобразовывает его в структуру CONTEXT.
    push UserMode
    push ecx;&Context
    push eax;Thread
;---------------------------------------------------------
    push KernelMode
    push ecx;&Context
    push eax;Thread
    call _imp__PsGetContextThread
;Context.ContextFlags = CONTEXT_CONTROL
;Аналогично, установка контекста потока функцией PsSetContextThread  (Thread, 
;&Context, UserMode) копирует переданный CONTEXT в KTRAP_FRAME. 
    call _imp__PsSetContextThread
    mov ecx,lpIrp
    xor edx,edx;edx=IO_NO_INCREMENT
;Irp->IoStatus.Information = 0
    mov (_IRP PTR [ecx]).IoStatus.Information,edx
;Irp->IoStatus.Status = STATUS_SUCCESS
    mov (_IRP PTR [ecx]).IoStatus.Status,edx
    call _imp__IofCompleteRequest;IoCompleteRequest(Irp, IO_NO_INCREMENT)
    xor eax,eax;return STATUS_SUCCESS
    leave
    retn 8
CreateDispatch endp
;---------------------------------------------------------------------------
DriverEntry proc DriverObject:PDRIVER_OBJECT, RegistryPath:PUNICODE_STRING
local deviceObject:PDEVICE_OBJECT
 
    push esi
    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;status = IoCreateDevice(DriverObject, 
; 0, &uniNameString, FILE_DEVICE_UNKNOWN, 0, FALSE, &deviceObject)
    test eax,eax
    js short @f;if(!NT_SUCCESS(status)) return status
    push offset cusDevice
    push offset cusSymbolicLink
    call _imp__IoCreateSymbolicLink;status = IoCreateSymbolicLink (&uniDOSString, &uniNameString)
    test eax,eax
    js 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
    xor eax,eax;return STATUS_SUCCESS
    jmp short @f
    mov eax,STATUS_INSUFFICIENT_RESOURCES
;return STATUS_INSUFFICIENT_RESOURCES
@@: pop esi
    leave
    retn 8
DriverEntry endp
;---------------------------------------------------------------------------
DriverUnload:
DriverObject    equ dword ptr [esp+4];:PDRIVER_OBJECT
 
    push offset cusSymbolicLink;eax;&uniDOSString
    call _imp__IoDeleteSymbolicLink;IoDeleteSymbolicLink (&uniDOSString)
    mov eax,DriverObject
    push dword ptr (DRIVER_OBJECT ptr [eax]).DeviceObject
    call _imp__IoDeleteDevice;IoDeleteDevice(DriverObject->DeviceObject)
    retn 4
;---------------------------------------------------------------------------
end DriverEntry
Первый вариант user-mode приложения, которое запускает драйвер scp12.sys

user-mode приложение, которое запускает scp12.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
; 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__GetLastError@0:dword
extern _imp__DeleteService@4:dword
extern _imp__ControlService@12:dword
extern _imp__QueryServiceStatus@8:dword
extern _imp__CreateThread@24:dword 
extern _imp__TerminateThread@8:dword
ascp12 equ  a_scp12+4
 
.code
 
start   proc
local   scp12_Handle:HANDLE
local   SchSCManager:SC_HANDLE  
local   schService:SC_HANDLE  ;
local   acDriverPath[MAX_PATH]:byte
local   hThread:HANDLE
local   Status:SERVICE_STATUS
local   BytesReturned:dword
 
    xor ebx,ebx;ebx:=0
;Install scp12 Driver
    push eax
    push esp
    lea edi,acDriverPath
    push edi
    push MAX_PATH
    push offset ascp12
    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 ascp12 ;    "scp12"      name to display and name of service
    mov [ecx+5],ebx; делаю из "\\.\scp12.sys" "\\.\scp12"
    push ecx; lpDisplayName         name to display = scp12
    push ecx; lpServiceName         name of service = scp12
    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 a4
    call edi;_imp__GetLastError@0
    cmp eax,ERROR_SERVICE_EXISTS;431h
    push ebx;0
    push ebx;0
    jnz short @f
    push offset err1 ; "Driver already exists. No action taken"
    jmp short a1
; ---------------------------------------------------------------------------
@@: push offset err2 ; "Unknown error while creating Service"
a1: push ebx;0
    call esi;_imp__MessageBoxA@16
; ---------------------------------------------------------------------------
a4: lea ecx,Status
    push ecx;&Status
    push schService
    call _imp__QueryServiceStatus@8
;Start the scp12 Driver. Errors will occur here if scp12.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 a5
    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 @f
    push offset err3; "The driver is already running"
    jmp short a3
;-------------------------------------------------------------------------
@@: 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
a5: 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_scp12 ; "\\\\.\\scp12"; lpFileName
    call _imp__CreateFileA@28
    inc eax;cmp eax,INVALID_HANDLE_VALUE
    jnz @f
a2: push ebx;if(scp12_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
@@: dec eax
    mov scp12_Handle,eax
;----------------------------------------------------------------------------
;драйвер сделал IOPL=3 у процесса, создаем поток, для этого нового потока IOPL 
;обновится, а после переключения задач обновится и IOPL в EFLAGS
;Создаем поток
    lea ecx,hThread
    push ecx;указатель на переменную куда помещен дескриптор потока.
        PUSH ebx;флаг определяющий состояние потока. Если флаг равен 0, то 
;выполнение потока начинается немедленно. Если значение флага потока равно 
;CREATE_SUSPENDED, то поток находится в состоянии ожидания и запускается по 
;выполнению функции ResumeThread
        PUSH ebx;Параметр для потоковой функции
        PUSH offset Play_musik ;указатель на потоковую функцию, с вызова которой 
;начинается исполнение потока
        PUSH ebx;размер стека потока. Если параметр равен 0, то берется размер 
;стека по умолчанию, равный размеру стека родительского потока
        PUSH ebx;указатель на структуру атрибутов доступа, обычно 0
        CALL _imp__CreateThread@24 
@@:     cmp flag,0  ; задержка, чтобы отыграла мелодия
    jnz @b
;Удаляем поток
        PUSH ebx;0
        PUSH hThread
        CALL _imp__TerminateThread@8
;-----------------------------------------------------------            
    mov edi,_imp__MessageBoxA@16
        push scp12_Handle   ; hObject
    call _imp__CloseHandle@4; CloseHandle(scp12_Handle)
; ---------------------------------------------------------------------------
    lea ecx,Status
    push ecx        ; 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 @f
; ---------------------------------------------------------------------------
    push ebx
    push ebx
    push offset err6; "Unknown error while stopping driver service"
    push ebx
    call edi;_imp__MessageBoxA@16
@@: push schService;esi
    call _imp__DeleteService@4
    push ebx
    push ebx
    test eax,eax
    jnz short @f
; ---------------------------------------------------------------------------
    push ebx
    push ebx
    push offset err7; "Error removing driver service - driver hasn't been successfully removed"
    push ebx
    call edi;_imp__MessageBoxA@16
@@: 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
;-------------------------------------------------------------------------
Play_musik: 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 
@@: push edx   
    push ecx   
    push 40    ; задержка в 40 мСек
    call _imp__Sleep@4     
    pop ecx   
    pop edx   ;Команда выводит данные в порт ввода-вывода, 
    outsb     ;номер которого загружен в регистр DX, 
    loop @b  ;из ячейки памяти по адресу DS:ESI
    in al,61h
    and al,11111100b;теперь динамик выключен
    out 61h,al  
    and flag,0
    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
;----------------------------------------------------------------
flag    db 1
a_scp12 db "\\.\scp12.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 приложения, которое запускает драйвер scp12.sys

Предварительно прописываем драйвер scp12.sys в реестре "вручную" (используем функции RegOpenKey, RegCreateKey, RegSetValue) и загружаем драйвер scp12.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
; masm windows gui #
.686P
.model flat
include windows.inc
 
includelib kernel32.lib
includelib ntdll.lib
includelib advapi32.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__CreateThread@24:dword 
extern _imp__TerminateThread@8: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\scp12>
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]:byte
local   hThread:HANDLE
 
    xor ebx,ebx;ebx:=0
    mov esi,offset DrvFilename+4;&esi='scp12.sys',0
        lea edi,acDriverPath
        mov eax,'\??\'
    stosd;путь к драйверу должен начаться с '\??\'
;Install scp12 Driver
    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; из "\\.\scp12.sys" делаю "\\.\scp12"
        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;указатель на пустое место в стеке
    mov dword ptr [eax],1;dType := 1
        push sizeof(dword)
    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;выравниваем стек после GetFullPathNameA  
    call _imp__ZwLoadDriver@4
    sub esi,4;esi='\\.\scp12',0
; ---------------------------------------------------------------------------
    push ebx        ; hTemplateFile
    push FILE_ATTRIBUTE_NORMAL; dwFlagsAndAttributes
    push OPEN_EXISTING  ; dwCreationDisposition
    push ebx        ; lpSecurityAttributes
    push ebx        ; dwShareMode
    push GENERIC_READ   ; dwDesiredAccess
    push esi ; "\\.\scp12"; lpFileName
    call _imp__CreateFileA@28
    inc eax;cmp eax,INVALID_HANDLE_VALUE
    jz short a0
    dec eax;eax=hObject
    push eax ; hObject для CloseHandle
;----------------------------------------------------------------------------
;драйвер сделал IOPL=3 у процесса, создаем поток, для этого нового потока IOPL 
;обновится, а после переключения задач обновится и IOPL в EFLAGS
;Создаем поток
    lea ecx,hThread
    push ecx;указатель на переменную, куда помещен дескриптор потока.
        PUSH ebx;флаг определяющий состояние потока. Если флаг равен 0, то 
;выполнение потока начинается немедленно. Если значение флага потока равно 
;CREATE_SUSPENDED, то поток находится в состоянии ожидания и запускается по 
;выполнению функции ResumeThread
        PUSH ebx;Параметр для потоковой функции
        PUSH offset Play_musik ;указатель на потоковую функцию, с вызова которой 
;начинается исполнение потока
        PUSH ebx;размер стека потока. Если параметр равен 0, то берется размер 
;стека по умолчанию, равный размеру стека родительского потока
        PUSH ebx;указатель на структуру атрибутов доступа, обычно 0
        CALL _imp__CreateThread@24 
@@:     cmp flag,0  ; задержка, чтобы отыграла мелодия
    jnz @b
;Удаляем поток
        PUSH ebx;0
        PUSH hThread
        CALL _imp__TerminateThread@8
;-----------------------------------------------------------            
    call _imp__CloseHandle@4; CloseHandle(hObject)
; ---------------------------------------------------------------------------
a0:     lodsd;add esi,4 из '\\.\scp12' делаем 'scp12'
    push offset cusDevice           
    call _imp__ZwUnloadDriver@4
    push esi;'scp12'
    push Key
    call _imp__SHDeleteKeyA@8;удаляем непустой ключ
    push Key
    call _imp__RegCloseKey@4
; ---------------------------------------------------------------------------
    push ebx
    call _imp__ExitProcess@4
start endp
;-------------------------------------------------------------------------
Play_musik: in al,61h;текущее состояние порта 61h в AL
    or al,00000011b;установить 0-ой и 1-ый биты  
    out 61h,al ;теперь динамик включен
    mov al,0B6h
    push 43h
    pop edx;dx=43h
    out dx,al;out 43h,al    
    mov esi,offset melody;адрес начала данных 
    mov ecx,size_melody  ; счетчик
    dec edx;dx=42h
@@: push edx;API-функции "портят" значения в регистрах DX, CX   
    push ecx;поэтому сохраним их в стеке
    push 40; задержка в 40 мСек
    call _imp__Sleep@4     
    pop ecx;а теперь восстановим значения в регистрах DX, CX
    pop edx
    outsb;Команда OUTS выводит данные в порт ввода-вывода, номер которого 
    loop @b;загружен в регистр DX, из ячейки памяти по адресу DS:ESI
    in al,61h;текущее состояние порта 61h в AL
    and al,11111100b;сбросить 0-ой и 1-ый биты  
    out 61h,al;теперь динамик выключен
    and flag,0
    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
;----------------------------------------------------------------
flag        db 1
DrvFilename db "\\.\scp12.sys",0
aSystem     db "SYSTEM\CurrentControlSet\Services",0
aType       db "Type",0
aImagePath  db "ImagePath",0
end start
________________________________________ __
© Mikl___ 2011
6
58 / 57 / 15
Регистрация: 15.09.2012
Сообщений: 557
28.10.2012, 22:26  [ТС]
Думаю для человека знающего на среднем уровне С++, C# идеальным вариантом для начала изучения драйверов будет => Новая модель драйвера книга "Windows Driver Foundation. ... Автор: Пенни Орвик, Гай Смит. Почитал содержание этой книги и обрадовался. Очень бы хотелось ее достать. В электронном варианте пока не нашел ( на русском языке). Если в кого есть дайте (111000110010@mail.ru)
1
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
29.10.2012, 06:49
Доступ к командам In/Out через CallGate

scp14-00 для доступа к портам создает CallGate. К сожалению, не на всех машинах с WinXP SP3 псевдоустройство \Device\PhysicalMemory можно открыть с атрибутом SECTION_MAP_WRITE даже с правами Администратора (версия 5.1 сборка 2600.xpsp_sp3_qfe.080423-1303 service pack 3 позволяет, а версия 5.1 сборка 2600.xpsp.080413-2111 service pack 3 ― нет), но там, где открывается ― код работает. Идея калгейта взята у Ms-Rem из статьи «Перехват API функций в Windows NT (часть 3). Нулевое кольцо».

Еще один способ, который позволяет перейти в нулевое кольцо и работать в нем не используя драйвер вообще. Способ этот основывается на открытии секции \Device\PhysicalMemory и модификации глобальной таблицы дескрипторов (GDT). В GDT добавляется дескриптор шлюза вызова CallGate, который указывает на наш код выполняющийся в нулевом кольце. После чего производится вызов шлюза командой дальнего вызова CALL FAR, которая изменяет привилегии кода и передает управление нашему коду

Assembler
1
2
3
4
5
6
GateDescriptor struc
    OffsetLo    Word    ?;нижние 2 байта адреса
    Selector    Word    ?;кодовый селектор (определяет привилегии)
    Attributes  Word    ?;атрибуты шлюза
    OffsetHi    Word    ?;верхние 2 байта адреса
GateDescriptor ends
Нужно определить адрес GDT в памяти (с помощью команды SGDT), перевести полученный виртуальный адрес в физический, отобразить данный участок памяти в свое адресное пространство, после чего найти ближайший свободный селектор в GDT и записать туда свой шлюз.
Следует обратить внимание на то, что нужную нам секцию нельзя сразу открыть на запись, так как полный доступ к ней имеет только система, нужно сначала изменить атрибуты безопасности секции разрешив текущему пользователю открывать её на запись, после чего секцию можно открыть и установить старые атрибуты безопасности обратно (для большей незаметности). Естественно все эти действия можно проделать только имея права администратора.
В этом коде Ring0CallProc - адрес кода который может быть вызван через установленный шлюз и будет выполнен в нулевом кольце защиты. Селектор установленного шлюза будет равен DWORD(CurrentGate) - DWORD(ptrGDT) - offset, смещение неважно. Теперь для вызова нашего кода достаточно выполнить дальний вызов FAR CALL на установленный шлюз.
Когда необходимость в шлюзе отпадет, его необходимо убрать.

Далее исходный текст scp14

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
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
; masm windows gui #
.686P
.model flat
include ntddk.inc
 
includelib kernel32.lib
includelib user32.lib
includelib advapi32.lib
includelib ntdll.lib
 
extern _imp__ExitProcess@4:dword
extern _imp__MessageBoxA@16:dword 
extern _imp__Sleep@4:dword
extern _imp__UnmapViewOfFile@4:dword
extern _imp__MapViewOfFile@20:dword
extern _imp__SetSecurityInfo@28:dword
extern _imp__GetSecurityInfo@32:dword
extern _imp__NtOpenSection@12:dword
extern _imp__SetEntriesInAclA@16:dword
extern _imp__FlushViewOfFile@8:dword
extern _imp__wsprintfA:dword
extern _imp__NtClose@4:dword
extern _imp__GetSystemInfo@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
;-----------------------------------
buffer_size     equ 100
SE_KERNEL_OBJECT    equ 6
GRANT_ACCESS            equ 1
NO_INHERITANCE          equ 0
NO_MULTIPLE_TRUSTEE equ 0
TRUSTEE_IS_NAME         equ 1
TRUSTEE_IS_USER         equ 1
FILE_MAP_WRITE      equ SECTION_MAP_WRITE
FILE_MAP_READ           equ SECTION_MAP_READ
KGDT_R0_CODE        equ 8
KGDT_R0_PCR     equ 30h
KGDT_R3_DATA        equ 20h
RPL_MASK        equ 3
 
TRUSTEE_A STRUCT
    pMultipleTrustee        DWORD   ?   ; PTR TRUSTEE_A
    MultipleTrusteeOperation    DWORD   ?   ; MULTIPLE_TRUSTEE_OPERATION
    TrusteeForm         DWORD   ?   ; TRUSTEE_FORM
    TrusteeType         DWORD   ?   ; TRUSTEE_TYPE
    union
        ptstrName       DWORD   ?   ; LPSTR
        pSid            DWORD   ?   ; PTR SID
    ends
TRUSTEE_A ENDS
 
EXPLICIT_ACCESS_A STRUCT
    grfAccessPermissions    DWORD   ?
    grfAccessMode       DWORD   ?   ; ACCESS_MODE
    grfInheritance      DWORD   ?
    Trustee         TRUSTEE_A <>
EXPLICIT_ACCESS_A ENDS
 
SYSTEM_INFO STRUCT
  wProcessorArchitecture        WORD       ?
  wReserved                     WORD       ?
  dwPageSize                    DWORD      ?
  lpMinimumApplicationAddress   DWORD      ?
  lpMaximumApplicationAddress   DWORD      ?
  dwActiveProcessorMask         DWORD      ?
  dwNumberOfProcessors          DWORD      ?
  dwProcessorType               DWORD      ?
  dwAllocationGranularity       DWORD      ?
  wProcessorLevel               WORD       ?
  wProcessorRevision            WORD       ?
SYSTEM_INFO ENDS
;OBJ_CASE_INSENSITIVE   equ 40h
;OBJ_KERNEL_HANDLE  equ 200h
 
GDTREG STRUC
    LimitLow    word ?
    BaseLow     word ?
    BaseHigh    word ?
    mix     word ?
GDTREG ENDS
 
GateDescriptor struc
    OffsetLo    Word    ?;нижние 2 байта адреса
    Selector    Word    ?;кодовый селектор (определяет привилегии)
    Attributes  Word    ?;атрибуты шлюза
    OffsetHi    Word    ?;верхние 2 байта адреса
GateDescriptor ends
 
.code
 
start proc
local   SecDesc:dword
local   OldAcl:dword;PACL
local   NewAcl:dword
local   gGdt:GDTREG
local   Offset_:dword
local   OldGate:GDTREG
local   hSection:dword
 
    xor ebx,ebx;ebx:=0
        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
;открытие памяти и установка калгейта
 
;Для последующего вызова функции NtOpenSection нам потребуется указатель на 
;заполненную структуру OBJECT_ATTRIBUTES 
    push ebx;oa->SecurityQualityOfService = 0
    push ebx;oa->SecurityDescriptor = 0
    push OBJ_CASE_INSENSITIVE or OBJ_KERNEL_HANDLE;oa->Attributes
    push offset PhMem;oa->ObjectName = pusRegistryPath
    push ebx;oa->RootDirectory = 0
    push sizeof(OBJECT_ATTRIBUTES);oa->Length=sizeof(OBJECT_ATTRIBUTES); 18h
 
    push esp;&oa
    push MEM_MAPPED or MEM_PRIVATE;(READ_CONTROL or WRITE_DAC)
    lea eax,hSection
    push eax;&hSection
    call _imp__NtOpenSection@12
    xchg ecx,eax;test eax,eax
    jecxz @f;jz short @f
    push offset e_opens1
    call ErrorTest; return STATUS_SUCCESS ?
 
@@:     lea eax,SecDesc
    push eax;&SD
    push ebx
        lea eax,OldAcl
    push eax
    push ebx
    push ebx
    push DACL_SECURITY_INFORMATION;4
    push SE_KERNEL_OBJECT;6
    push hSection
    call _imp__GetSecurityInfo@32
    xchg ecx,eax;cmp eax,0
    jecxz @f;jz short @f
    push offset e_getsec
    call ErrorTest
 
@@: push offset aCurentUser;Access->Trustee.ptstrName=offset aCurentUser;"CURRENT_USER";
    push TRUSTEE_IS_USER;Access->Trustee.TrusteeType=TRUSTEE_IS_USER
    push TRUSTEE_IS_NAME;Access->Trustee.TrusteeForm=TRUSTEE_IS_NAME
    push ebx;Access->Trustee.MultipleTrusteeOperation=NO_MULTIPLE_TRUSTEE
    push ebx;Access->Trustee.pMultipleTrustee=NULL
    push ebx;Access->grfInheritance=NO_INHERITANCE
    push GRANT_ACCESS;Access->grfAccessMode=GRANT_ACCESS
    push SECTION_MAP_WRITE;Access->grfAccessPermissions=SECTION_MAP_WRITE
    mov ecx,esp;ecx=&Access
; create new acl
    lea edx,NewAcl
    push edx
    push OldAcl
    push ecx;&Access
    push 1
    call _imp__SetEntriesInAclA@16
    xchg ecx,eax;test eax,eax
    jecxz @f;jz short @f
    push offset e_setacl
    call ErrorTest
 
@@:     add esp,sizeof (EXPLICIT_ACCESS_A)
    push ebx;0
    push NewAcl
    push ebx;0
    push ebx;0
    push DACL_SECURITY_INFORMATION;4
    push SE_KERNEL_OBJECT;6
    push hSection
    call _imp__SetSecurityInfo@28
    xchg ecx,eax;test eax,eax
    jecxz @f;jz short @f
        push offset e_setsec
    call ErrorTest
 
@@:     push hSection
    call _imp__NtClose@4
 
        push esp;&oa
    push SECTION_MAP_READ or SECTION_MAP_WRITE
    lea eax,hSection
    push eax
    call _imp__NtOpenSection@12
    xchg ecx,eax;test eax,eax
    jecxz @f;jz short @f
;STATUS_SUCCESS        = 0
;STATUS_ACCESS_DENIED  = 0C0000022h
;STATUS_INVALID_HANDLE = 0C0000008h
    push offset e_opens2
    call ErrorTest; return STATUS_SUCCESS ?
 
@@:     add esp,sizeof( OBJECT_ATTRIBUTES )
;установка калгейта 
    sgdt gGdt;определить адрес GDT в памяти с помощью команды SGDT 
        mov edx,dword ptr gGdt.BaseLow
    push edx
    and edx,0FFFh
    mov Offset_,edx
    pop edx
        test edx,edx;cmp eax, 80000000h
        jns @f;jb short @f
    cmp edx,0A0000000h
    jb short a0
@@: and edx,0FFFF000h
a0: and edx,1FFFF000h
    jnz short @f
        push offset e_gdterr
    call ErrorTest
;перевести полученный виртуальный адрес в физический, отобразить данный участок 
;памяти в свое адресное пространство, после чего найти ближайший свободный 
;селектор в GDT и записать туда свой шлюз.
@@: movzx eax,gGdt.LimitLow
    add eax,Offset_ ; gdt.limit + offset
        push eax;dwNumberOfBytesToMap задает количество байтов, котоpое нужно 
;пpомэппиpовать в память
    push edx;base_address;dwFileOffsetHigh и dwFileOffsetLow задают стаpтовый 
;файловое смещение файловой поpции, котоpую вы хотите загpузить в память.
    push ebx;так как мы хотим читать весь файл, поэтому начинаем мэппинг 
;со смещение ноль. 
    push FILE_MAP_READ or FILE_MAP_WRITE;dwDesiredAccess опpеделяет, какую 
;опеpацию мы хотим совеpшить над файлом
    push hSection
    call _imp__MapViewOfFile@20
;После вызова MapViewOfFile, желаемое количество байт загpужается в память.
;Получаем указатель на блок памяти
        test eax,eax; if ptrGDT = nil then Exit
    jne short @f
    push offset e_maps
    call ErrorTest
 
@@: mov edi,eax;ptrGDT,eax
        add eax,Offset_
        movzx ecx,gGdt.LimitLow
    sub ecx,eax
    assume eax: ptr GateDescriptor
@@: test [eax].Attributes,0FF00h;if (CurrentGate.Attributes and $FF00) = 0 then
    jz short @f
    cmp eax,ecx
    ja short a1
    add eax,sizeof GDTREG;8
    jmp short @b
@@: push dword ptr [eax]
    pop dword ptr OldGate
    push dword ptr [eax+4]
    pop dword ptr OldGate+4
    assume eax: ptr GateDescriptor
    mov esi,eax;esi:=CurrentGate
    mov [eax].Selector,KGDT_R0_CODE;ring0 code selector
    mov ecx,offset Play_music
        mov [eax].OffsetLo,cx
    shr ecx,16
        mov [eax].OffsetHi,cx
        mov [eax].Attributes,1110110000000000b; 5 последних бит = количество параметров
        sub eax,edi
        sub eax,Offset_
    mov FarCall_Selector,ax;CurrentGate - ptrGDT - Offset_
    assume eax:nothing
    push sizeof GDTREG;8
    push esi;CurrentGate
    call _imp__FlushViewOfFile@8
    dw 1DFFh
    dd FarCall_Offset; call far [FarCall]
    push dword ptr OldGate
    pop dword ptr [esi];CurrentGate
    push dword ptr OldGate+4
    pop dword ptr [esi+4];CurrentGate+4
a1: push hSection
    call _imp__NtClose@4
    push edi;ptrGDT
    call _imp__UnmapViewOfFile@4
    push ebx
    call _imp__ExitProcess@4    
start endp
;----------------------------------------------
ErrorTest proc  
    sub esp,buffer_size;буфер под строку описание ошибки
    mov esi,esp
    push eax
    push dword ptr [esp+buffer_size+8];описание ошибки
    push offset f_err
    push esi
    call _imp__wsprintfA
    push ebx
    push ebx
    push esi
    push ebx
    call _imp__MessageBoxA@16
    add esp,buffer_size+16;выправляем стек после wsprintfA и удаляем буфер
    push ebx
    call _imp__ExitProcess@4
ErrorTest endp
;-------------------------------------------------
Play_music proc;перезагрузка регистра FS и DS и вызов Ring0 кода
    cli 
    push fs
    push ds
    pusha
    pushf
    mov cx,KGDT_R0_PCR;30h
    mov di,KGDT_R3_DATA or RPL_MASK;23h
    mov ds,di
    mov fs,cx
    in al,61h;текущее состояние порта 61h в AL
    or al,00000011b;установить 0-ой и 1-ый биты 
    out 61h,al ;теперь динамик включен
    mov al,0B6h
    out 43h,al
    mov esi,offset melody; данные 
    mov ecx,size_melody  ; счетчик
    mov dx,42h 
    push edi
a2: push edx   
    push ecx   
    rdtsc      
    mov ecx,eax
    mov edi,edx
    add ecx,TimerLo
    adc edi,TimerHi
@@: rdtsc; крутимся до тех пор пока не получится
    sub eax,ecx; задержка в 55 мСек
    sbb edx,edi
    jnz @b
    pop ecx   
    pop edx   ;Команда выводит данные в порт ввода-вывода, 
    outsb     ;номер которого загружен в регистр DX, 
    loop a2  ;из ячейки памяти по адресу DS:ESI
    pop edi
    in al,61h
    and al,11111100b;сбросить 0-ой и 1-ый биты 
    out 61h,al  ;теперь динамик выключен
    popf
    popa
    pop ds
    pop fs
    sti
    retf
Play_music 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
;----------------------------------------------------------------
TimerLo     dd 0
TimerHi     dd 0
f_err       db "Error: %s, code: 0x%X",0
e_opens1    db 'NtOpenSection for DACL access failed',0
e_opens2    db "NtOpenSection for r/w failed",0
e_getsec    db "GetSecurityInfo failed",0
e_setacl    db "SetEntriesInAclA failed",0
e_setsec    db "SetSecurityInfo failed",0
e_maps      db "NtMapViewOfSection failed",0
e_unmaps    db "NtUnmapViewOfSection failed",0
e_query     db "NtQuerySystemInformation failed",0
e_gdterr    db "gdt failed!",0
aCurentUser db "CURRENT_USER",0
align 4
FarCall_Offset  dd 0
FarCall_Selector dw ?
aDevice: du <\Device\PhysicalMemory>
a:
align 4
PhMem       dw a-aDevice
        dw a-aDevice+2
        dd aDevice
end start
_________________________________
© Mikl___ 2011
Миниатюры
Зачем нужен драйвер и как написать простейший драйвер  
4
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
29.10.2012, 07:16
Доступ к командам In/Out. Ответ ajak от Indy/Clerk'а
Вопрос ― Как модифицировать IOPM?
Ответ ― Логически подумать никак не получается?

Если смещение карты IOPM находится за пределами сегмента TSS, то карта IOPM не используется, а доступ к портам определятся содержимым 12 и 13 битов в регистре флагов (поле IOPL). Если карта IOPM находится в пределах сегмента, то доступ к порту определяется соответствующим битом в ней.
Так как VDM процессов может быть несколько, а карта IOPM для них только и используется (то есть для user-mode VDM процессов), значит смещение карты IOPM в TSS для этих процессов изменяется. Изменяться смещение может только шедулером, следовательно, где-то в информации связанной с процессом это смещение должно храниться. Известно, что описатель процесса (непосредственно объект) ― это структура EPROCESS. Взглянув на нее, сразу находим нужное поле:
C
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
typedef struct _KPROCESS {
 
    //
    // The dispatch header and profile listhead are fairly infrequently
    // referenced.
    //
 
    DISPATCHER_HEADER Header;
    LIST_ENTRY ProfileListHead;
 
    //
    // The following fields are referenced during context switches.
    //
 
    ULONG_PTR DirectoryTableBase[2];
 
#if defined(_X86_)
 
    KGDTENTRY LdtDescriptor;
    KIDTENTRY Int21Descriptor;
    USHORT IopmOffset;
    UCHAR Iopl;
    BOOLEAN Unused;
 
#endif
Смещение поля равно 0x30. Открываем код шедулера и обнаруживаем то, что и предполагалось:
Assembler
1
2
3
4
5
6
7
8
9
; Set the IOPM map offset value.
;
; N.B. This may be a redundant load of this value if the process did not
;      change during the context switch. However, always reloading this
;      value saves several instructions under the context swap lock.
;
 
        mov     ax, [ebp]+PrIopmOffset  ; set IOPM offset
        mov     [ecx]+TssIoMapBase, ax  ;
Далее, так как у каждого процессора свой TSS, то карта IOPM должна быть настроена в каждом TSS. Иначе на первом процессоре будет одна карта IOPM, на другом ― другая. Так как одновременно потоки одного процесса могут исполняться на разных процессорах, то также как и карта IOPM, должно быть загружено смещение её в TSS. Загрузка достигается с помощью IPI или DPC.
Для подтверждения можно загрузить IOPM в TSS и установить смещение её в KPROCESS, после чего подождать, пока не произойдет свопинг посредством функции NtYieldExecution. После этого окажется что порт доступен, так как смещение будет загружено в TSS (разумеется на текущем процессоре). Ведь так просто
________________________________________ ______
© Mikl___ 2011
4
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
06.11.2012, 09:42
Доступ к портам ввода/вывода через прерывание
Теория ― мать склероза
Вызовем код, содержащий команды in/out через какое-нибудь прерывание. При этом оно (и это вполне естественно) не должно использоваться системой. Пусть его номер будет, допустим, 99h. Содержимое дескрипторной таблицы прерываний (Interrupt Descriptor Table ― IDT) можно посмотреть утилитой IdtDump, написанной Four-F и входящей в KmdKit.
Адрес расположения таблицы IDT не является фиксированным и, чтобы его получить, мы должны использовать, например, команду SIDT (Store Interrupt Descriptor Table). Эта команда вернет нам следующую структуру
Assembler
1
2
3
4
IDT struct
    Limit WORD ?
    Base DWORD ?
IDT ends
выгружаем текущий дескриптор и из него получаем начальный адрес таблицы IDT. Но это всё, что мы можем сделать для изменения прерывания в режиме User Mode, читать или писать в таблицу мы могли только под Windows 95/98/Me под Windows NT/XP/Seven мы можем работать с таблицей IDT только через Kernel Mode драйвер. Поэтому, на скорую руку, переделываем драйвер scp02
Далее индексируемся на описатель 99h прерывания в таблице IDT и меняем его так, чтобы управление передалось на нашу подпрограмму

Дескрипторная таблица прерываний (Interrupt Descriptor Table, IDT), состоит из 8-ми байтных дескрипторов для каждого прерывания, которые могут содержать шлюзы задачи, прерывания и ловушки. Формат IDT напоминает дескриптор из GDT/LDT.
Первое и последнее слова дескриптора шлюза прерывания содержат 32-х разрядный адрес обработчика прерывания (зеленое поле "смещение" на картинке). Второе слово содержит селектор сегмента кода, где находится код обработчика.
# бита название назначение
15P (Present) ― бит присутствия Если =1 ― прерывание обрабатывается, если =0 ― генерируется исключение общей защиты.
14-13DPL (Descriptor Privilege Level) ― уровень привилегийЕсли текущий уровень привилегий отличается от уровня привилегий обработчика, происходит переключение стека и в стеке обработчика сохраняется указатель на стек прерванной задачи (SS и ESP). В стек помещаются регистры EFLAGS, CS, EIP. Для некоторых исключений последним в стек помещается еще и код ошибки, который, кстати, должен вытолкнуть обработчик исключения после обработки. Очищается бит TF, для программного прерывания или исключения сбрасываются биты VM, RF и NT. При вызове обработчика через шлюз прерывания очищается бит IF, блокируя дальнейшие маскируемые аппаратные прерывания.
12=0
11 D (digits) ― бит разрядностиЕсли =1 ― 32 разряда, если =0 ― 16 разрядов
10-8type of gates=111 trap gate
  =110 interrupt gate
  =101 task gate
7-5=0
4-0reserved 
Практика ― сестра шизофрении
Assembler
1
    mov eax,(DriverQuery ptr [eax]).wparam
Через структуру R0DriverQuery передаем драйверу адрес обработчика прерывания
Assembler
1
2
    cli
    sub esp,8
запрещаем прерывания на время работы с таблицей прерываний и выделяем в стэке место под 6-ти байтовую структуру
Assembler
1
        sidt qword ptr [esp+2]
заполняем базой и лимитом таблицы IDT
Assembler
1
    mov ecx,[esp+4]
нас интересует только база IDT, передаем ее в ECX
Assembler
1
    add esp,8
возвращаем стэк в исходное положение
Assembler
1
    add ecx,99h*8
нас интересует 99h прерывание, смещение до этой 8-ми байтной ячейки 99h*8 или 4С8h или 1224 байт
Assembler
1
    mov [ecx],eax
помещаем в первое поле адрес обработчика
Assembler
1
    mov [ecx+2],cs
"лишние" 16 бит адреса будут стерты значением селектора сегмента кода
Assembler
1
    mov [ecx+4],eax
помещаем в третье и четвертое поле адрес обработчика
Assembler
1
    mov word ptr [ecx+4],0EE00h
и опять "лишние" 16 разрядов адрес обработчика будут стерты значением помещенных в структуру битом присутствия, уровня привилегий и разрядности
Assembler
1
    sti
разрешаем немаскированные прерывания
Далее исходный текст драйвера scp16.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
; masm windows native #
.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
 
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\\scp16", cusDevice, 4
CCOUNTED_UNICODE_STRING "\\DosDevices\\scp16", 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
; приложению получить доступ к нашему драйверу, используя "\\.\scp16" нотацию
    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
    mov eax,(DriverQuery ptr [eax]).wparam
    cli
    sub esp,8
        sidt qword ptr [esp+2]
    mov ecx,[esp+4]; в ECX база IDT
    add esp,8
    add ecx,99h*8
    mov [ecx],eax
    mov [ecx+4],eax
    mov [ecx+2],cs
    mov word ptr [ecx+4],0EE00h
    sti
    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
Текст программы, которая загружает и работает с драйвером scp16.sys
  1. Управление на нашу подпрограмму будет передано из драйвера и подпрограмма будет выполнятся как бы на уровне Kernel Mode поэтому мы не можем сделать задержку User Mode функцией Sleep поэтому в самом начале программы замеряем сколько тиков CPU соответствуют 40 мсек
  2. Для инициирования драйвера вызовем функцию GetFullPathName и формируем строку с полным путем к файлу драйвера, состоящую из текущего каталога и имени файла драйвера, которую позже передадим функции CreateService.
  3. Помещаем драйвер в сервисную базу. База должна быть предварительно открыта функцией OpenSCManager
  4. Получив доступ к базе SCM, мы регистрируем в ней свой драйвер, с помощью функции CreateService
  5. CreateService регистрирует в базе данных SCM новый драйвер, и заполняет соответствующий подраздел реестра.
  6. После запуска сервиса, пример использует структуру SERVICE_STATUS, возвращаемую функцией QueryServiceStatus, чтобы получить состояние сервиса. Член dwControlsAccepted
    структуры SERVICE_STATUS, возвращенный этой функцией указывает, может ли драйвер быть остановлен, приостановлен или возобновлена его работа.
  7. Запуск драйвера осуществляется функцией StartService
  8. Открываем устройство "\\.\scp16" функцией CreateFile
  9. Передаем устройству "\\.\scp16" при помощи функции WriteFile адрес обработчика прерывания 99h
  10. Вызовом int 99h проигрываем музыку
  11. Закрываем устройство "\\.\scp16" функцией CloseHandle. При этом драйвер удаляет из Interrupt Descriptor Table обработчик нашего самопального прерывания.
  12. Останавливаем сервис при помощи функции ControlService отправив запрос
    SERVICE_CONTROL_STOP
  13. Приводим систему в исходное состояние. Вызовом функции DeleteService мы удаляем сведения о драйвере из базы данных SCM и из реестра.
  14. Вызовом функции CloseServiceHandle мы закрываем описатель hService. Поскольку больше открытых описателей службы нет, то именно в этот момент система приводит базу данных SCM в исходное состояние. Второй вызов CloseServiceHandle закрывает описатель hSCManager самого SCM.
  15. Завершаем программу функцией ExitProcess
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
; 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
    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='scp16.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='scp16',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='\\.\scp16',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
        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
    int 99h; играем "марш клоунов"
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
;обработчик 99h прерывания
musik:  pushad
        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 
    push edi
a15:    push edx   
    push ecx   
    rdtsc      
    mov ecx,eax
    mov edi,edx
    add ecx,TimerLo
    adc edi,TimerHi
@@: rdtsc; крутимся до тех пор пока не получится
    sub eax,ecx; задержка в 55 мСек
    sbb edx,edi
    jnz @b
    pop ecx   
    pop edx   ;Команда выводит данные в порт ввода-вывода, 
    outsb     ;номер которого загружен в регистр DX, 
    loop a15  ;из ячейки памяти по адресу DS:ESI
    pop edi
    in al,61h
    and al,11111100b;4Dh 
    out 61h,al          
    popad
    iretd; возврат из прерывания   
;__________________________________________________________________
.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 '\\.\scp16.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
______________________________
© Mikl___ 2012
Миниатюры
Зачем нужен драйвер и как написать простейший драйвер   Зачем нужен драйвер и как написать простейший драйвер  
6
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
30.01.2014, 11:53
системный динамик играет не «Марш клоунов» Нино Ротта, а "Марш гладиаторов" (Opus 68 march (Vjezd gladiátorů)) чешского композитора Julius Fučík (1872-1916), написан марш в 1897 году
Вложения
Тип файла: pdf fucik-julius-entree-des-gladiateurs-tonnerre-et-blazes-pour-piano-44557.pdf (179.6 Кб, 30 просмотров)
0
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
30.01.2014, 12:47
А вот это "Марш клоунов" Нино Ротта
Вложения
Тип файла: zip Nino_Rota_Marsh_klounov.zip (7.77 Мб, 29 просмотров)
1
110 / 41 / 0
Регистрация: 30.09.2013
Сообщений: 575
19.03.2014, 18:47
Цитата Сообщение от ASDFD12 Посмотреть сообщение
Рускоязычные книги тоже не совсем понятно написаны.
А есть хорошие книги про написания драйверов? Если кто знает подскажите. Заранее спасибо.
0
58 / 57 / 15
Регистрация: 15.09.2012
Сообщений: 557
19.03.2014, 18:53  [ТС]
Уолтер Они Windows Driver Model 2-е издание
1
45 / 44 / 1
Регистрация: 11.07.2012
Сообщений: 1,024
30.06.2017, 08:16
Цитата Сообщение от Mikl___ Посмотреть сообщение
эта ссылка нерабочая, куда она/он переехала/переехал?
0
Модератор
Эксперт по электронике
 Аватар для ФедосеевПавел
8655 / 4490 / 1669
Регистрация: 01.02.2015
Сообщений: 13,898
Записей в блоге: 12
30.06.2017, 18:08
Как и многое другое из мира прошлого - в webarchive http://web.archive.org/web/201... hp?list=21
2
45 / 44 / 1
Регистрация: 11.07.2012
Сообщений: 1,024
04.07.2017, 14:22
Цитата Сообщение от taras atavin Посмотреть сообщение
Но ведь всё элементарно до безобразия: драйвером называется системная программа, обеспечивающая работоспособность конкретного перифирийного устройства, или меняющая её характеристики.
Мне кажется автор не это спрашивает, он хочет/хотел понять что такое драйвер, а именно как он делается/пишется. Грубо говоря блок схему разработки драйвера, что бы потом его настроить. Ведь на этом форуме жесткие условия, надо начать что то писать и при этом понимать что пишешь, иначе могут не помочь. Так вот в моем понимании драйвер это (я уже три дня читаю литературу по разработке драйвера). И так по моему драйвер это код ядра, который пишется на ассемблере , либо на си с использованием готовых низкоуровневых функций для ядра, НО не для коннкретного внешнего устройства, а для его подключения через какой либо сейрийный порт компютера. Так как внешнее устройство подключается к компьютеру через какой либо порт, по другому его никак не подключить, а все портв стандартные и работают по протоколу передачи данных, поэтому для каждого порта уже есть готовые низкоуровневые функции ядра в защищенном режиме, которые можно использовать. НО бывают такие случаи, которые нестандартные, ну например не нужно мне данные через сом порт принимать, а нужны только 2 управляющих сигнала из всего сом порта на прием и передачу, поэтому я могу не брать стандартные функции, а использовать свой ассемблерный код. А вот когда я данные полученные от моего внешнего устройства через параметры передам в пользовательский незащищенный режим, я уже могу их там обрабатывать на с++ как мне захочется. Вот я что понимаю под драйвером, в том разрезе, что хотел услышать автор темы. Мною уважаемый Микл все подробно разжевал и объяснил, но не подал полную картинку в целом, что зачем и для чего. А автор в ассемблере не разбирается или не хочет разбираться, он хочет сразу драйвер, и я его автора могу понять , сам 3 дня уже читаю, и только только что то начинает понемногу прорисовываться, с ходу мне кажется драйвер не взять, надо постепенно...

Добавлено через 29 минут
Цитата Сообщение от ita2907 Посмотреть сообщение
Почему такое неуважение к "великому и могучему" русскому языку?
Какое отношение имеет русский язык к программированию? Все ПО на английском, ну разве может быть 1с...

Добавлено через 8 минут
Цитата Сообщение от Mikl___ Посмотреть сообщение
Все драйвера, которые будут приводится в этом топике, будут открывать порты 42h, 43h, 61h, чтобы сыграть системным динамиком «Марш клоунов» Нино Ротта.
Вот эти прерывания, они одинаковые что в ms-dos что в Windows? Если одинаковые, то почему именно эти ? У меня есть распечатка из книги (не помню уже из какой) со всеми прерываниями и про эти прерывания написано 42h,43h зарезервированы , 61h свободно может использоваться в прикладных программах, мноюуважаемый Микл использует все прерывания для прикладной программы, так можно?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
04.07.2017, 14:22
Помогаю со студенческими работами здесь

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

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
39
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Работа со звуком через SDL3_mixer
8Observer8 08.02.2026
Содержание блога Пошагово создадим проект для загрузки звукового файла и воспроизведения звука с помощью библиотеки SDL3_mixer. Звук будет воспроизводиться по клику мышки по холсту на Desktop и по. . .
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru