News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

KeLowerIrql - Error

Started by Astro, February 06, 2010, 12:08:35 AM

Previous topic - Next topic

Astro

Hi,

I can't figure out how I can call KeLowerIrql - it doesn't seem to know what I'm on about, and MSDN doesn't offer a hint as to where I may find it, less how to use it.

How can I change the IRQL in the driver?

I've also got the problem that it sometimes BSODs with IRQL_NOT_LESS_OR_EQUAL but I can't figure out quite why. If I can force the IRQL down I think it will solve the problem.

Complete driver code follows. I'm installing it as KERNEL_DRIVER_SERVICE. I've been using http://four-f.webs.com/ for guidance.

It currently does nothing but create virtual device and a symbolic link, process one custom IRP, and unload. It is unstable though. :( 
I figure it is the IRP processing that is going awry.

.386
.model flat, stdcall
option casemap:none

include \masm32\include\w2k\ntstatus.inc
include \masm32\include\w2k\ntddk.inc
include \masm32\include\w2k\ntoskrnl.inc
include \masm32\include\w2k\w2kundoc.inc

includelib \masm32\lib\w2k\ntoskrnl.lib

include \masm32\Macros\Strings.mac

.data?
CurrIRQL DWORD ?

.data
;DRVR DWORD 0000000000100010-11-100000000001-11 / 0x22-0x3-0x801-0x3 / FILE_DEVICE_UNKNOWN...READ/WRITE...FUNC CODE...BUFFER NEITHER
DRVR DWORD 00000000001000101110000000000111b

CCOUNTED_UNICODE_STRING "\\Device\\devTestDriver", DeviceName, 4 ; Driver name
CCOUNTED_UNICODE_STRING "\\??\\TestDriver", SymLink, 4 ; Symbolic link used by apps. Use \\DosDevice\ for older build

.code

DispatchControl proc pDeviceObject:PDEVICE_OBJECT, pIrp:PIRP
    LOCAL status:NTSTATUS
    LOCAL dwBytesReturned:DWORD

    and dwBytesReturned, 0

    mov esi, pIrp
    ASSUME esi:PTR _IRP
    IoGetCurrentIrpStackLocation esi
    mov edi, eax

    ASSUME edi:PTR IO_STACK_LOCATION
    mov eax,[edi].Parameters.DeviceIoControl.IoControlCode
    cmp eax,DRVR ; IOCTL request
    jne NO_PROCESSING
;---------------------------------------

    mov dwBytesReturned,0
    mov status,STATUS_SUCCESS
    jmp CONT

NO_PROCESSING:
    mov dwBytesReturned,0
    mov status,STATUS_PENDING

    ASSUME esi:PTR _IRP
    ASSUME edi:NOTHING

    push status
    pop [esi].IoStatus.Status

    push dwBytesReturned
    pop [esi].IoStatus.Information

    IoMarkIrpPending esi

    assume esi:nothing

    mov eax,status
    ret 8
;===========================================================

CONT:
    ASSUME esi:PTR _IRP
    ASSUME edi:NOTHING

    push status
    pop [esi].IoStatus.Status

    push dwBytesReturned
    pop [esi].IoStatus.Information

    assume esi:nothing

    push IO_NO_INCREMENT
    push pIrp
    call IoCompleteRequest
   
    mov eax, status
    ret 8

DispatchControl endp




DispatchCreateClose proc pDeviceObject:PDEVICE_OBJECT, pIrp:PIRP

    mov eax, pIrp
    assume eax:ptr _IRP
    mov [eax].IoStatus.Status, STATUS_SUCCESS
    and [eax].IoStatus.Information, 0
    assume eax:nothing

    ;---------------------------------------------
    ; FASTCALL! first two params - L->R ecx and
    ; edx, then the rest, R->L on the stack
   
    mov edx,IO_NO_INCREMENT
    mov ecx,pIrp
    call IofCompleteRequest
    ;fastcall IofCompleteRequest, pIrp, IO_NO_INCREMENT

    mov eax, STATUS_SUCCESS
    ret 8

DispatchCreateClose endp




DriverUnload proc pDriverObject:PDRIVER_OBJECT

    ;---------------------------------------------
    ; Delete the SymLink
   
    push offset SymLink
    call IoDeleteSymbolicLink

    ;---------------------------------------------
    ; Delete the device so we can unload
       
    mov eax, pDriverObject
    push (DRIVER_OBJECT PTR [eax]).DeviceObject
    call IoDeleteDevice
   
    ret 4

DriverUnload endp




DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING
    LOCAL status:NTSTATUS
    LOCAL pDeviceObject:DWORD

    ;---------------------------------------------
    ; Assume we're going to fail. Will result in
    ; driver unload and auto service start failure
   
    mov status,STATUS_DEVICE_CONFIGURATION_ERROR

    ;---------------------------------------------
    ; Create the driver object
   
    push pDeviceObject
    push FALSE
    push 0
    push FILE_DEVICE_UNKNOWN
    push offset DeviceName
    push 0
    push pDriverObject
    call IoCreateDevice

    cmp eax,STATUS_SUCCESS ; =0
    jnz FAIL

    ;---------------------------------------------
    ; Create the symbolic link our user mode app
    ; will call

    push offset SymLink
    push offset DeviceName
    call IoCreateSymbolicLink

    cmp eax,STATUS_SUCCESS ; =0
    jnz FAIL

    ;---------------------------------------------
    ; Declare the functions we're using
   
    mov eax,pDriverObject
    assume eax:PTR DRIVER_OBJECT
    mov [eax].MajorFunction[IRP_MJ_CREATE*4], offset DispatchCreateClose
    mov [eax].MajorFunction[IRP_MJ_CLOSE*4], offset DispatchCreateClose
    mov [eax].MajorFunction[IRP_MJ_DEVICE_CONTROL*4], offset DispatchControl
    mov [eax].DriverUnload, offset DriverUnload
    assume eax:nothing

    mov eax,STATUS_SUCCESS ; =0
    ret 8
;===========================================================

FAIL:

    ;---------------------------------------------
    ; We had an error - delete the device and exit

    push pDeviceObject
    call IoDeleteDevice

    mov eax,status
    ret 8

DriverEntry endp

end DriverEntry


Best regards,
Robin.

redskull

It doesn't really work like that... you are probably trying to access memory that has been paged out, and (generally speaking) the the system can't bring in pages when drivers are executing.  For experimentation purposes, just stick with the non-paged pool for everything.

-r
Strange women, lying in ponds, distributing swords, is no basis for a system of government

Astro

Hi,

I appreciate the cause (I'm possibly not explaining myself well - late here), but it is 'why'??

The functions are passed pointers to memory. If the source I'm reading is correct, DriverEntry could be called at any IRQL. I have nothing to say it isn't correct.

Apparently DispatchControl is called in the context of the calling process. If it is a user-mode app, it is called in the context of that app (PASSIVE_LEVEL), and has access to everything.

For some reason it would appear Windows is calling DriverEntry or DispatchControl at a level that prevents access to paged memory. I can't see how I can prevent the crash though because as far as I can see, I can't minimize the function any more than it already is.

It has to access the structure passed, and that structure is somewhere in memory (I'm guessing in non-paged memory).

The only thing that I see might be an issue are the LOCALs. IIRC these are created on the stack, in paged memory. Instant crash. I'll put these into the .data section and see what happens then.

I suspect the other crash is somehow related to the LOCALs too.

Shooting very much in the dark,
Robin. :(

QuoteThe doer alone learneth.   - Friedrich Nietzsche
Very apt.

redskull

As to the 'why', recall that a page fault is an exception, which is treated just like any other interrupt.  The IRQL is how Windows "ranks" these interrupts by order of importance; for example, the clock interrupt (which allows scheduling and preemption) is nearly at the top, and applications run way down at the bottom.  Page faults, as far as the system is concerned, are only slightly more important thatn applications, in that they run at the Dispatch Level APC Level.  Since drivers are assumed to be servicing actual hardware, and not just 'privileged applications', they are given priority.  As you've found, when a page fault is incurred while you execute a driver, the system says "I need to access memory that is paged out, but I can't stop what I'm doing to page it in".  It can't stop, but it can't continue, and you end up with a BSOD.

As to the 'why' of why your *particular* code is doing it, there's nothing I notice during a cursory once-over that screams out to me, however i'm not any sort of Ring0 expert.  Without the stack trace from the crash, it's just a lot of shots in the dark.  Try the WinDBG ".analyze" command.  Remember though, if any other functions try to use that data when it's paged out the same thing will happen, so don't necessarily assume it's once place when it could be another.  Step 1: Do the crash dump.   Step2: get the stack trace.

-r
Strange women, lying in ponds, distributing swords, is no basis for a system of government

Astro

Hi,

There is some difference between:

DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING
    local status:NTSTATUS
    local pDeviceObject:PVOID

    mov status,STATUS_DEVICE_CONFIGURATION_ERROR

    push offset pDeviceObject
    push FALSE
    push 0
    push FILE_DEVICE_UNKNOWN
    push offset DeviceName
    push 0
    push pDriverObject
    call IoCreateDevice


and

DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING
local status:NTSTATUS
local pDeviceObject:PVOID
mov status, STATUS_DEVICE_CONFIGURATION_ERROR

invoke IoCreateDevice, pDriverObject, 0, addr DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, addr pDeviceObject


The invoke uses addr pDeviceObject, whilst the version that crashes on the second start uses push pDeviceObject.

What is the difference???

By replacing this block with the invoke version prevents the crash.

Best regards,
Robin.

redskull

DriverEntry supplies you with a pointer to the object; when you PUSH OFFSET, you are pushing a 'pointer to a pointer', which causes the illegal memory access (NT attempts to use the pointer itself as the object),  When you INVOKE with just the name, you are pushing the *actual* value stored in pDriverObject, which is correct.

-r
Strange women, lying in ponds, distributing swords, is no basis for a system of government

Astro

I tried to build push offset pDeviceObject - doesn't work, it throws an error.

push pDeviceObject

builds, but crashes on the second run of the driver.

Best regards,
Robin.

dedndave

        mov     eax,offset pDeviceObject
        push    eax

drizz

Writing drivers in masm and not knowing that "addr localvar" is "lea eax,localvar; push eax" ?!

Furthermore: 

http://msdn.microsoft.com/en-us/library/aa490468.aspx


OUT PDEVICE_OBJECT  *DeviceObject


DeviceObject
Pointer to a variable that receives a pointer
The truth cannot be learned ... it can only be recognized.

Astro

Hi drizz,

I don't use it very often and I forgot that. I did try to find it to see how it worked.

Thanks for the link - I'd already looked at that.

@dedndave: thanks.

Best regards,
Robin.