Наткнулся на статью "Процедура DriverEntry и предварительные объявления–часть 14" с сайта compkniga.com. В ней есть пример простого драйвера "в стиле NT". Чтобы было интересней читать, решил сразу перевести сишный код на асм. Вот процедура DriverEntry: Код (Text): DriverEntry proc pDriverObject:DWORD, pusRegistryPath:DWORD local pFDO:DWORD mov eax, pDriverObject assume eax:ptr DRIVER_OBJECT mov [eax].MajorFunction[IRP_MJ_CREATE*4], offset Create_File_IRPprocessing mov [eax].MajorFunction[IRP_MJ_CLOSE*4], offset CloseHandle_IRPprocessing mov [eax].MajorFunction[IRP_MJ_READ*4], offset ReadWrite_IRPhandler mov [eax].MajorFunction[IRP_MJ_WRITE*4], offset ReadWrite_IRPhandler mov [eax].MajorFunction[IRP_MJ_DEVICE_CONTROL*4], offset DeviceControlRoutine mov [eax].DriverUnload, offset UnloadRoutine invoke RtlInitUnicodeString, addr usDeviceName, addr uszDeviceName invoke RtlInitUnicodeString, addr usSymbolicLinkName, addr uszSymbolicLinkName invoke IoCreateDevice, pDriverObject, sizeof EXAMPLE_DEVICE_EXTENSION, addr usDeviceName, \ FILE_DEVICE_UNKNOWN, 0, FALSE, addr pFDO .if eax != STATUS_SUCCESS ret .endif lea eax, DevExt assume eax:ptr EXAMPLE_DEVICE_EXTENSION push pFDO pop [eax].pFDO lea eax, pFDO invoke DbgPrint, addr exdbg3, eax ;lea eax, DevExt invoke DbgPrint, addr exdbg33, eax invoke IoCreateSymbolicLink, addr usSymbolicLinkName, addr usDeviceName .if eax != STATUS_SUCCESS push eax invoke IoDeleteDevice, pFDO pop eax ret .endif mov eax, STATUS_SUCCESS ret DriverEntry endp В этой процедуре закомментирована строчка lea ebx, DevExt Если ее разкомментировать, то драйвер вылетает в BSOD с ошибкой 00000050 Извиняюсь, не 00000050, а 0000007е (типа необрабатываемое исключение, или что-то подобное) Не могу понять, почему...Немного выше указанной строк стоит такая же lea.
Во-первых, там закомментирована lea eax, DevExt. Во-вторых, а что вообще такое DevExt, где оно объявлено? В-третьих, выложи анализ дампа падения, !analyze -v в WinDbg.
1. Да, все верно, lea eax, DevExt. 2. DevExt это структура для хранения указателя на FDO и символьной ссылки: EXAMPLE_DEVICE_EXTENSION STRUCT pFDO DWORD ? usSymLinkName UNICODE_STRING <> EXAMPLE_DEVICE_EXTENSION ENDS объявленна в сегменте данных .data 3. Анализ дампа в прикрепленном файле.
Ничего не понимаю: запускал сейчас тот же пример, чтобы получить аварийный дамп, и драйвер работал нормально. Никаких вылетов. Даже не знаю, что это могло быть. Прошу прощение за напрасное беспокойство.
DevExt это структура для хранения указателя на FDO и символьной ссылки: EXAMPLE_DEVICE_EXTENSION STRUCT pFDO DWORD ? usSymLinkName UNICODE_STRING <> EXAMPLE_DEVICE_EXTENSION ENDS объявленна в сегменте данных .data так: DevExt EXAMPLE_DEVICE_EXTENSION <> Присвоение значения: lea eax, DevExt assume eax:ptr EXAMPLE_DEVICE_EXTENSION push pFDO pop [eax].pFDO
Я конкретно ступил с DevExt, разместив ее в .data секции. Ведь это должна была быть структура DEVICE_EXTENSION, место под которую отводится при вызове IoCreateDevice. FDO -> DeviceExtension и содержит нужный указатель. Его и надо было использовать. Да... каюсь.
Тту появился новый гемор: Код (Text): Create_File_IRPprocessing proc pDeviceObject:DWORD, pIrp:DWORD local pStack:DWORD mov eax, pIrp assume eax:ptr _IRP mov eax, [eax].Tail.Overlay.CurrentStackLocation mov pStack, eax assume eax:ptr IO_STACK_LOCATION mov eax, dword ptr [eax].FileObject assume eax:ptr FILE_OBJECT ;movzx ebx, [eax].FileName._Length invoke DbgPrint, addr exdbg66, eax invoke CompleteIrp, pIrp, STATUS_SUCCESS, 0 ret Create_File_IRPprocessing endp В этой процедуре, которая должна обрабатывать IRP_MJ_CREATE, закомментированная строка вызывает BSOD с такими данными: STOP: 0x0000008e (0xc0000005, ...) Это исключение GP?
VirtualBox Windows Virtual PC VMware Workstation Parallels Desktop/Workstation И т.д. Я к тому спросил, что некоторые виртуалки весьма глючные сами по себе (например, Parallels Desktop), они могут ронять виртуалку на ровном месте примерно с такими же кодами, как у тебя (0x50, 0x7e, ...). А у тебя здесь да, проблема с device extension, его нужно брать по адресу pDevObj -> DeviceExtension после успешного вызова IoCreateDevice().
Никаких WM у меня не запущено. Ошибку с DeviceExtension я исправил, все работает, но, как я уже писал, образовалась новая проблемка (см. мой предыдущий пост). Не мог бы ты и сней помочь? Насчет дампов WinDbg: дамп ядра на моей машине весит 104 МБ. Точно нужно его выкладывать, или можно просто скопировать вывод WinDbg?
Может, стоит всё таки взять C для начала? И примеры на C смотреть тоже. Часть ошибок удастся избежать автоматически. Асм нужно брать тогда, когда пишешь какие-то аппаратно-зависимые вещи или что-то, что следует сильно оптимизировать по скорости, ну например, загрузчик операционной системы, алгоритмы шифрования и т.д. Однако, на реальной машине, что ли, запускаешь? Угробишь же систему. На первый взгляд в коде всё правильно. Сначала вывод давай, если будет не достаточно, тебе скажут об этом.
Вот - выкладываю вывод WinDbg: Код (Text): Microsoft (R) Windows Debugger Version 6.11.0001.404 X86 Copyright (c) Microsoft Corporation. All rights reserved. Loading Dump File [C:\WINDOWS\MEMORY.DMP] Kernel Summary Dump File: Only kernel address space is available Symbol search path is: C:\WINDOWS\symbols;srv*c:\Symbols*http://msdl.microsoft.com/download/symbols Executable search path is: Windows XP Kernel Version 2600 (Service Pack 3) MP (2 procs) Free x86 compatible Product: WinNt, suite: TerminalServer SingleUserTS Built by: 2600.xpsp_sp3_qfe.080423-1303 Machine Name: Kernel base = 0x804d7000 PsLoadedModuleList = 0x805634c0 Debug session time: Thu Feb 23 18:54:48.562 2012 (GMT+3) System Uptime: 0 days 0:00:58.234 Loading Kernel Symbols ............................................................... ............................................................. Loading User Symbols PEB is paged out (Peb.Ldr = 7ffdb00c). Type ".hh dbgerr001" for details Loading unloaded module list ............ ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* Use !analyze -v to get detailed debugging information. BugCheck 8E, {c0000005, 8057bc2a, b337ba00, 0} PEB is paged out (Peb.Ldr = 7ffdb00c). Type ".hh dbgerr001" for details PEB is paged out (Peb.Ldr = 7ffdb00c). Type ".hh dbgerr001" for details Probably caused by : ntkrnlmp.exe ( nt!IopParseDevice+a69 ) Followup: MachineOwner --------- 0: kd> !analyze -v ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* KERNEL_MODE_EXCEPTION_NOT_HANDLED (8e) This is a very common bugcheck. Usually the exception address pinpoints the driver/function that caused the problem. Always note this address as well as the link date of the driver/image that contains this address. Some common problems are exception code 0x80000003. This means a hard coded breakpoint or assertion was hit, but this system was booted /NODEBUG. This is not supposed to happen as developers should never have hardcoded breakpoints in retail code, but ... If this happens, make sure a debugger gets connected, and the system is booted /DEBUG. This will let us see why this breakpoint is happening. Arguments: Arg1: c0000005, The exception code that was not handled Arg2: 8057bc2a, The address that the exception occurred at Arg3: b337ba00, Trap Frame Arg4: 00000000 Debugging Details: ------------------ PEB is paged out (Peb.Ldr = 7ffdb00c). Type ".hh dbgerr001" for details PEB is paged out (Peb.Ldr = 7ffdb00c). Type ".hh dbgerr001" for details EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - <Unable to get error code text> FAULTING_IP: nt!IopParseDevice+a69 8057bc2a c7436001000000 mov dword ptr [ebx+60h],1 TRAP_FRAME: b337ba00 -- (.trap 0xffffffffb337ba00) ErrCode = 00000002 eax=00000000 ebx=00000000 ecx=00000000 edx=00000001 esi=88953490 edi=889534a0 eip=8057bc2a esp=b337ba74 ebp=b337bb4c iopl=0 nv up ei pl zr ac pe nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010256 nt!IopParseDevice+0xa69: 8057bc2a c7436001000000 mov dword ptr [ebx+60h],1 ds:0023:00000060=???????? Resetting default scope DEFAULT_BUCKET_ID: DRIVER_FAULT BUGCHECK_STR: 0x8E PROCESS_NAME: example.exe LAST_CONTROL_TRANSFER: from 805221f9 to 8053767a STACK_TEXT: b337b5c8 805221f9 0000008e c0000005 8057bc2a nt!KeBugCheckEx+0x1b b337b990 804de403 b337b9ac 00000000 b337ba00 nt!KiDispatchException+0x3b1 b337b9f8 804de3b4 b337bb4c 8057bc2a badb0d00 nt!CommonDispatchException+0x4d b337ba14 8056d5b4 b337bb3c 889534a0 88ab7240 nt!KiExceptionExit+0x18a b337bb4c 8056d03b 88f17f08 00000000 8895ce58 nt!ObCreateObject+0x12a b337bbc4 80570402 00000000 b337bc04 00000040 nt!ObpLookupObjectName+0x53c b337bc18 8057c24e 00000000 00000000 37bc8401 nt!ObOpenObjectByName+0xea b337bc94 8057c31d 0012ff70 c0100080 0012ff10 nt!IopCreateFile+0x407 b337bcf0 8057c360 0012ff70 c0100080 0012ff10 nt!IoCreateFile+0x8e b337bd30 804dd99f 0012ff70 c0100080 0012ff10 nt!NtCreateFile+0x30 b337bd30 7c90e4f4 0012ff70 c0100080 0012ff10 nt!KiFastCallEntry+0xfc WARNING: Frame IP not in any known module. Following frames may be wrong. 0012ff68 00000000 00000000 00000000 00000000 0x7c90e4f4 STACK_COMMAND: kb FOLLOWUP_IP: nt!IopParseDevice+a69 8057bc2a c7436001000000 mov dword ptr [ebx+60h],1 SYMBOL_STACK_INDEX: 0 SYMBOL_NAME: nt!IopParseDevice+a69 FOLLOWUP_NAME: MachineOwner MODULE_NAME: nt IMAGE_NAME: ntkrnlmp.exe DEBUG_FLR_IMAGE_TIMESTAMP: 480f21b7 FAILURE_BUCKET_ID: 0x8E_nt!IopParseDevice+a69 BUCKET_ID: 0x8E_nt!IopParseDevice+a69 Followup: MachineOwner ---------
Однозначного ответа этот вывод, к сожалению, не даёт. Ясно пока только одно: падение произошло уже после того, как твой драйвер завершил Create-запрос. Покажи код своей функции CompleteIrp(). Что за драйвер-то вообще? Он что-нибудь делает полезного? Например, аттачится ли он в стек какого-нибудь девайса или ещё что-нибудь в этом роде? Строчка movzx ebx, [eax].FileName._Length (тут только _Length меня смущает, зачем подчёркивание?) сама по себе не может приводить к сбою, т.к. eax инициализирован правильно, а поле FileObject в структуре IO_STACK_LOCATION не может быть NULL в случае Create-запроса.
Функция CompleteIrp: Код (Text): CompleteIrp proc pIRP:DWORD, ntStatus:DWORD, Info:DWORD mov eax, pIRP assume eax:ptr _IRP push ntStatus pop [eax].IoStatus.Status push Info pop [eax].IoStatus.Information mov ecx, pIRP mov edx, IO_NO_INCREMENT call IofCompleteRequest mov eax, ntStatus ret CompleteIrp endp Драйвер не делает ничего, написан в учебных целях, только запускается и выводит отладочные сообщения из зарегистрированных процедур. Это пример из одной статьи про драйвера в стиле NT, просто там он на C, а я решил его в асм перевести, и вот... На всякий случай прикрепляю код драйвера. Подчеркивание в _Length - это я использую inc файлы из kmd от Four-F (есть на wasm.ru его статья про драйвера режима ядра).
код драйвера. Что-то файл не прикрепляется, или я чего-то не того... вто он Код (Text): ;goto make .586 .model flat, stdcall option casemap:none IOCTL_9 equ 22E000h include c:\masm32\include\w2k\ntstatus.inc include c:\masm32\include\w2k\ntoskrnl.inc include c:\masm32\include\w2k\ntddk.inc include c:\masm32\include\w2k\hal.inc include c:\masm32\include\w2k\native.inc includelib c:\masm32\lib\w2k\hal.lib includelib c:\masm32\lib\w2k\ntoskrnl.lib EXAMPLE_DEVICE_EXTENSION STRUCT pFDO DWORD ? usSymLinkName UNICODE_STRING <> EXAMPLE_DEVICE_EXTENSION ENDS .data MySpinLock KSPIN_LOCK ? dbg1 db "Module ex1.sys : DriverEntry", 0 dbg2 db "Module ex1.sys : CreateClose", 0 dbg3 db "Module ex1.sys : DriverUnload", 0 dbg4 db "Module ex1.sys : DispatchIoControl", 0 dbg6 db "Module ex1.sys : AddDevice", 0 exdbg1 db "=Example= In DriverEntry.", 0 exdbg2 db "=Example= RegistryPath = %ws", 0 exdbg3 db "=Example= FDO %08X", 0 exdbg33 db "DevExt = %08X.", 0 exdbg4 db "=Example= DriverEntry successfully completed.", 0 exdbg5 db "-Example- in ReadWrite_IRPhandler.", 0 exdbg6 db "-Example- Create File is %ws", 0 exdbg66 db "-Example- File Object Pointer %08X", 0 exdbg7 db "-Example- In Close handler.", 0 uszDeviceName dw "\", "D", "e", "v", "i", "c", "e", "\", "e", "x", "1", 0 uszSymbolicLinkName dw "\", "G", "L", "O", "B", "A", "L", "?", "?", "\", "e", "x", "1", 0 usDeviceName UNICODE_STRING <> usSymbolicLinkName UNICODE_STRING <> szTargetModuleName db "user32.dll", 0 szTargetProcName db "MessageBoxA", 0 .code CompleteIrp proc pIRP:DWORD, ntStatus:DWORD, Info:DWORD mov eax, pIRP assume eax:ptr _IRP push ntStatus pop [eax].IoStatus.Status push Info pop [eax].IoStatus.Information mov ecx, pIRP mov edx, IO_NO_INCREMENT call IofCompleteRequest mov eax, ntStatus ret CompleteIrp endp UnloadRoutine proc pDriverObject:DWORD invoke IoDeleteSymbolicLink, offset usSymbolicLinkName mov eax, pDriverObject invoke IoDeleteDevice, (DRIVER_OBJECT PTR [eax]).DeviceObject ret UnloadRoutine endp DeviceControlRoutine proc pDeviceObject:DWORD, pIrp:DWORD local status:NTSTATUS local Bytes:DWORD local irql:DWORD local CurrentIrql:DWORD mov esi, pIrp assume esi:ptr _IRP mov edi, [esi].Tail.Overlay.CurrentStackLocation assume edi:ptr IO_STACK_LOCATION .if [edi].Parameters.DeviceIoControl.IoControlCode .endif invoke CompleteIrp, pIrp, STATUS_SUCCESS, 0 ret DeviceControlRoutine endp CloseHandle_IRPprocessing proc pDeviceObject:DWORD, pIrp:DWORD ;invoke DbgPrint, addr exdbg7 invoke CompleteIrp, pIrp, STATUS_SUCCESS, 0 ret CloseHandle_IRPprocessing endp Create_File_IRPprocessing proc pDeviceObject:DWORD, pIrp:DWORD local pStack:DWORD mov eax, pIrp assume eax:ptr _IRP mov eax, [eax].Tail.Overlay.CurrentStackLocation mov pStack, eax assume eax:ptr IO_STACK_LOCATION mov eax, dword ptr [eax].FileObject assume eax:ptr FILE_OBJECT movzx ebx, [eax].FileName._Length ;assume ebx:ptr UNICODE_STRING ;mov eax, [ebx].Buffer invoke DbgPrint, addr exdbg66, eax invoke CompleteIrp, pIrp, STATUS_SUCCESS, 0 ret Create_File_IRPprocessing endp ReadWrite_IRPhandler proc pDeviceObject:DWORD, pIRP:DWORD local status:NTSTATUS local Bytes:DWORD mov status, STATUS_SUCCESS invoke DbgPrint, addr exdbg5 invoke CompleteIrp, pIRP, status, Bytes ret ReadWrite_IRPhandler endp .code INIT DriverEntry proc pDriverObject:DWORD, pusRegistryPath:DWORD local pFDO:DWORD local devex:DWORD invoke DbgPrint, addr exdbg1 mov eax, pusRegistryPath assume eax:ptr UNICODE_STRING invoke DbgPrint, addr exdbg2, [eax].Buffer mov eax, pDriverObject assume eax:ptr DRIVER_OBJECT mov [eax].MajorFunction[IRP_MJ_CREATE*4], offset Create_File_IRPprocessing mov [eax].MajorFunction[IRP_MJ_CLOSE*4], offset CloseHandle_IRPprocessing mov [eax].MajorFunction[IRP_MJ_READ*4], offset ReadWrite_IRPhandler mov [eax].MajorFunction[IRP_MJ_WRITE*4], offset ReadWrite_IRPhandler mov [eax].MajorFunction[IRP_MJ_DEVICE_CONTROL*4], offset DeviceControlRoutine mov [eax].DriverUnload, offset UnloadRoutine invoke RtlInitUnicodeString, addr usDeviceName, addr uszDeviceName invoke RtlInitUnicodeString, addr usSymbolicLinkName, addr uszSymbolicLinkName invoke IoCreateDevice, pDriverObject, sizeof EXAMPLE_DEVICE_EXTENSION, addr usDeviceName, \ FILE_DEVICE_UNKNOWN, 0, FALSE, addr pFDO .if eax != STATUS_SUCCESS ret .endif mov eax, pFDO assume eax:ptr DEVICE_OBJECT push [eax].DeviceExtension pop devex lea eax, devex assume eax:ptr EXAMPLE_DEVICE_EXTENSION push pFDO pop [eax].pFDO lea eax, devex invoke DbgPrint, addr exdbg3, eax lea eax, pFDO invoke DbgPrint, addr exdbg33, eax invoke IoCreateSymbolicLink, addr usSymbolicLinkName, addr usDeviceName .if eax != STATUS_SUCCESS push eax invoke IoDeleteDevice, pFDO pop eax ret .endif mov eax, STATUS_SUCCESS ret DriverEntry endp end DriverEntry :make set drv=ex1 c:\masm32\bin\ml /c /coff /nologo %drv%.bat c:\masm32\bin\link /nologo /driver /align:32 /base:0x10000 /subsystem:native /ignore:4078 /out:%drv%.sys %drv%.obj del %drv%.obj pause
Подозреваю, что ф-ия обработки IRP_MJ_CREATE портит ebx, что сильно не нравится вызывающей ее ф-ии. Если попробовать использовать 'movzx ecx, [eax].FileName._Length', BSoD остается? Ну и ebx вообще не трогать, либо сохранять его значение перед использованием и восстанавливать перед выходом из ф-ии? P.S. Писать драйвера на ассемблере без использования VM или второго компьютера для отладки, скажем мягко -- усложнение и без того непростой задачи.
Foo А почему аргументы для IofCompleteRequest() передаются через регистры у тебя? Соглашение fastcall только на x86-64 используется. Почему не через invoke, как обычно, вызываешь? И почему в полном исходнике этот вызов уже переделан на invoke? Что-то ты химией какой-то дерзновенной занимаешься. Регистры, которые используешь в функции, необходимо сохранять перед использованием и восстанавливать при выходе, о чём выше тебе написали. Может, лучше C всё таки, а?