The Old New Thing: ----------------- Why you shouldn't allocate usermode memory from PsSetLoadImageNotifyRoutine routine callbacks. I'm describing this little story here because back in the days i have experienced this problem and i couldn't find a solution and reasonable explanation online. I guess for some of my readers this is quite obvious however maybe it will help some less experienced people. The PsSetLoadImageNotifyRoutine routine registers a driver-supplied callback that is subsequently notified whenever an image is loaded (or mapped into memory). When the callback is registered the system calls the load-image notify routine whenever an executable image is mapped into virtual memory, whether in system space or user space, before the execution of the image begins. Additionally, the system calls this routine when a DLL image is mapped into user-space virtual memory. [1] Appending to MSDN [1](?) the callbacks routines operate at the PASSIVE_LEVEL IRQL. So what if you want to allocate some r3 memory (for various purposes) when the new image is being loaded? Assuming that the ZwAllocateVirtualMemory also runs at PASSIVE_LEVEL everything should be just fine. However it's not. It appears that for every test i did when the original process PE file is loaded (some .exe file) and ntdll.dll the callback routine operates at the PASSIVE_LEVEL. However for every further loaded image the IRQL is raised to APC_LEVEL. And now when you will try to execute ZwAllocateVirtualMemory or something "similiar" you will experience a deadlock. Why the deadlock occurs? Some disassembly: When loading kernel32.dll and further modules following code from ntdll.dll is executed: (usermode - ring3): --------------------------------------------------------------------------------- .text:7C91B739 push 4 .text:7C91B73B push ebx .text:7C91B73C push 1 .text:7C91B73E lea eax, [ebp+var_28] .text:7C91B741 push eax .text:7C91B742 push ebx .text:7C91B743 push ebx .text:7C91B744 push ebx .text:7C91B745 lea eax, [ebp+base] .text:7C91B748 push eax .text:7C91B749 push 0FFFFFFFFh .text:7C91B74B push [ebp+var_20] .text:7C91B74E call _ZwMapViewOfSection@40 ; ZwMapViewOfSection(x,x,x,x,x,x,x,x,x,x) --------------------------------------------------------------------------------- this goes to nt!MmMapViewOfSection, and following piece of code is executed: --------------------------------------------------------------------------------- PAGE:000D0380 push eax ; int PAGE:000D0381 push edi ; BugCheckParameter1 PAGE:000D0382 call _KeStackAttachProcess@8 ; KeStackAttachProcess(x,x) PAGE:000D0387 mov [ebp+var_4], 1 PAGE:000D038E PAGE:000D038E loc_D038E: ; CODE XREF: MmMapViewOfSection(x,x,x,x,x,x,x,x,x,x)+A3j PAGE:000D038E lea ecx, [edi+0F0h] ; mutex PAGE:000D0394 mov [ebp+BugCheckParameter1], ecx PAGE:000D0397 call ds:__imp_@ExAcquireFastMutex@4 ; ExAcquireFastMutex(x) --------------------------------------------------------------------------------- As you can see mutex (EPROCESS->AddressCreationLock) is acquired. This mutex will be released at function epilogue. However before this will happen MiMapViewOfImageSection function will be executed. And MiMapViewOfImageSection executes PsCallImageNotifyRoutines (so all the callbacks registered in system) - they are all executed when the mutex is NOT AVAILABLE! This mutex is required by those functions so if it is not available they will wait for it. Since it will never be freed the deadlock occurs. So if you are tying to use ZwAllocateVirtualMemory/MmMapLockedPagesSpecifyCache (for example) from the image notify routine it is very likely it would fail because of the busy AddressCreationLock mutex. Ok that's all! Happy coding :-) [1] - http://msdn.microsoft.com/en-us/library/ff559957.aspx