Windows内核驱动:ZwAllocateVirtualMemory引发线程终止问题
Let's break down your problem and walk through targeted fixes to get your injection working reliably:
First, Context on the Crash
Your stack trace points to a failure originating in nt!ExAllocatePoolWithTag during the ZwAllocateVirtualMemory call in your InjectDll function. The target iexplore.exe ends up in a zombie state (92KB memory, no CPU activity) because the thread handling the image load crashed without proper cleanup. Let's dig into the most likely causes:
Likely Root Causes & Fixes
1. You're Operating in the Wrong Process Context
PsLoadImageNotifyRoutine doesn't always run in the context of the target process. If you're using NtCurrentProcess() assuming it points to iexplore.exe, you're probably modifying the wrong process (or running in a system thread context, which will trigger access violations).
Fix:
- Verify you're in the target process context by comparing
PsGetCurrentProcessId()to theProcessIdpassed to the notify routine. - If not, explicitly attach to the target process before any memory operations:
PEPROCESS targetProcess; NTSTATUS status = PsLookupProcessByProcessId(targetPid, &targetProcess); if (!NT_SUCCESS(status)) { /* handle error and exit */ } KAPC_STATE apcState; KeStackAttachProcess(targetProcess, &apcState); // Your ZwAllocateVirtualMemory and injection logic here KeUnstackDetachProcess(&apcState); ObDereferenceObject(targetProcess);
2. Invalid Parameters to ZwAllocateVirtualMemory
Bad flags, insufficient process permissions, or invalid handles are common culprits here.
Checklist:
- Open the target process with explicit privileges: Use
ZwOpenProcesswithPROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_CREATE_THREADaccess rights—don't rely on implicit context. - Validate your allocation parameters:
AllocationType: UseMEM_COMMIT | MEM_RESERVEto properly reserve and commit memory.Protect: Start withPAGE_READWRITE(you can change it toPAGE_EXECUTE_READWRITElater if needed for APC execution).Size: Allocate at leastMAX_PATHbytes to fit your DLL path (plus a null terminator).
- Always check the
NTSTATUSreturn value ofZwAllocateVirtualMemory—don't proceed if allocation fails.
3. Misuse of ExAllocatePoolWithTag
If your InjectDll function calls ExAllocatePoolWithTag directly (e.g., for buffer allocation), invalid parameters here can cause pool corruption or allocation failures.
Fix:
- Use modern, safe pool types like
NonPagedPoolNx(avoid deprecated types likeNonPagedPool). - Validate the requested size—ensure it's not 0 or excessively large.
- Check if the allocation returns
NULLand handle that case gracefully (don't dereference a null pointer). - Always free pool memory with
ExFreePoolWithTagwhen done to avoid leaks.
4. Premature Injection Timing
Even if ArbitraryUserPointer points to kernel32.dll, the process might not be fully initialized. ntdll.dll loads early, but kernel32's initialization routines may still be running, making the process unstable for memory operations.
Fix:
- Delay injection until the process reaches a stable state:
- Check the process's PEB to confirm
LdrInitializeThunkhas completed (verifyPEB->Ldr->InInitializationOrderModuleListincludes critical modules). - Use a kernel timer (
KeSetTimer) to wait a short interval (e.g., 500ms) after detecting the image load before triggering injection. - Alternatively, track process creation via
PsSetCreateProcessNotifyRoutineExand wait for the main thread to start executing user-mode code.
- Check the process's PEB to confirm
5. Unhandled Errors Leading to Crashes
Skipping error checks for kernel API calls (like PsLookupProcessByProcessId or ZwOpenProcess) can lead to invalid memory accesses or pool corruption.
Fix:
- Add robust error handling to every kernel call. For example:
NTSTATUS status = ZwAllocateVirtualMemory(processHandle, &baseAddress, 0, &size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (!NT_SUCCESS(status)) { DbgPrint("ZwAllocateVirtualMemory failed: 0x%X\n", status); // Clean up resources and return early return status; }
Debugging Tips
- Set a breakpoint on
ExAllocatePoolWithTagand inspect the parameters (pool type, size) when the crash occurs—this will reveal if you're requesting an invalid allocation. - Use
!process <targetPid> 2in WinDbg to check the process's state—look for signs of pending termination or invalid thread states. - Enable pool tagging (
!pooltagin WinDbg) to detect if your allocations are causing pool corruption.
内容的提问来源于stack exchange,提问作者Oriel Cochavi

