简体   繁体   English

Windows内核驱动程序:ZwAllocateVirtualMemory导致线程终止

[英]Windows Kernel Driver: ZwAllocateVirtualMemory causing thread to terminate

I'm trying to write an APC dll injection driver, I've found this example and thought to modify it to my needs. 我正在尝试编写一个APC dll注入驱动程序,我找到了这个示例,并想根据自己的需要对其进行修改。

I use PcreateProcessNotifyRoutineEx to obtain the ProcessId for specific applications I targeting, in this case, "iexplore.exe" and then use PloadImageNotifyRoutine to check if ntdll.dll is already loaded and initialized (from this recommendation ), and if ntdll.dll is loaded, I call "my" InjectDLL function. 我使用PcreateProcessNotifyRoutineEx来获取我定位的特定应用程序的ProcessId,在这种情况下为“ iexplore.exe”,然后使用PloadImageNotifyRoutine检查是否已加载和初始化ntdll.dll(根据此建议 ),以及是否已加载ntdll.dll。 ,我称之为“我的” InjectDLL函数。

This is the PloadImageNotifyRoutine function that is calling InjectDll: 这是调用InjectDll的PloadImageNotifyRoutine函数:

VOID PloadImageNotifyRoutine(
    _In_ PUNICODE_STRING FullImageName,
    _In_ HANDLE ProcessId,
    _In_ PIMAGE_INFO ImageInfo
)
{
    PEPROCESS Process = NULL;
    PETHREAD Thread = NULL;
    PCHAR pTeb = nullptr;
    DWORD ArbitraryUserPointer = 0;
    PCHAR pszProcessNameA = nullptr;

    pTeb = (PCHAR)__readfsdword(0x18);
    ArbitraryUserPointer = *(DWORD*)(pTeb + 0x014);

    // If ArbitraryUserPointer points to kernel32.dll it means ntdll.dll is done loading.
    if (FALSE == IsStringEndWith((wchar_t*)ArbitraryUserPointer, L"\\kernel32.dll"))
    {
        return;
    }

    if (!NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, &Process)))
    {
        return;
    }

    pszProcessNameA = (PCHAR)PsGetProcessImageFileName(Process);
    if (FALSE == StringNCompare(pszProcessNameA, "iexplore.exe", GetStringLength("iexplore.exe")))
    {
        return;
    }

    Thread = KeGetCurrentThread();
    InjectDll(MODULE_PATH, Process, Thread);
    ObDereferenceObject(Process);
}

And this is the InjectDll function: 这是InjectDll函数:

BOOLEAN InjectDll(PWCHAR pModulePath, PEPROCESS Process, PETHREAD Thread)
{
    PKINJECT mem;
    ULONG size;

    mem = NULL;
    size = 4096;

    if (!NT_SUCCESS(ZwAllocateVirtualMemory(NtCurrentProcess(), (PVOID*)&mem, 0, &size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)))
    {
        return FALSE;
    }

    //more code ...
}

I removed here some checks so it would be more clear. 我在这里删除了一些检查,这样会更清楚。

I tried to debug it a little, but it seems like ZwAllocateVirtualMemory is trying to allocate memory, failing at some point and terminate the thread. 我尝试对其进行一些调试,但是ZwAllocateVirtualMemory似乎正在尝试分配内存,有时会失败并终止线程。

After it calls ExAllocatePoolWithTag it starting to free memory, unmapping sections and terminate the thread (<= calls I saw at the stack while debugging - didn't really trace each call, but looked at it in general view). 在调用ExAllocatePoolWithTag之后,它开始释放内存,取消映射节并终止线程(<=我在调试时在堆栈中看到的调用-并未真正跟踪每个调用,而是在一般视图中进行了查看)。

The stack before the thread get terminated: 线程终止之前的堆栈:

nt!ExAllocatePoolWithTag+0x195
nt!NtAllocateVirtualMemory+0x1066
nt!KiSystemServicePostCall
nt!ZwAllocateVirtualMemory+0x11
kernel_apc_dll_injector!InjectDll+0x54
kernel_apc_dll_injector!PloadImageNotifyRoutine+0x2b0
nt!PsCallImageNotifyRoutines+0x62

The process is still visible from task manager, but its Memory is 92k and has no CPU usage, probably because it didn't "cleaned up" properly. 从任务管理器中仍然可以看到该进程,但是该进程的内存为92k,没有CPU使用率,可能是因为未正确“清理”该进程。

I don't know if my analysis is right, and maybe it even unnecessary for this problem. 我不知道我的分析是否正确,也许对于这个问题甚至是不必要的。

at first side note - not call PsLookupProcessByProcessId from image notify routine. 首先注意-不要从图像通知例程调用PsLookupProcessByProcessId this is simply not need. 根本不需要。 check that ProcessId == PsGetCurrentProcessId() . 检查ProcessId == PsGetCurrentProcessId() and if yes - use current process pointer (as you and use in call ZwAllocateVirtualMemory - NtCurrentProcess() ) otherwise just exist. 如果是,请使用当前进程指针(如您所用,并在调用ZwAllocateVirtualMemory - NtCurrentProcess() ),否则将仅存在。

now about main - "ZwAllocateVirtualMemory causing thread to terminate" - of course no. 现在有关主-“ ZwAllocateVirtualMemory导致线程终止”-当然没有。 thread not terminate . 线程未终止 it hung . 挂了 at first if thread is terminate - because this is single thread in process at this stage - all process is terminate. 首先,如果线程终止,则-由于此线程在此阶段处于进程中-所有进程均终止。 but you yourself say that The process is still visible from task manager . 但是您自己说, 该过程仍然可以从任务管理器中看到 also how you view call stack of terminated thread ? 还如何查看终止线程的调用堆栈? this also say that thread not terminated but wait inside ExAllocatePoolWithTag 这也表示线程没有终止,而是在ExAllocatePoolWithTag内部ExAllocatePoolWithTag

problem that callback is execute in some critical region and The actions that you can perform in this routine are restricted (The operating system calls the driver's process-notify routine at PASSIVE_LEVEL inside a critical region with normal kernel APCs disabled). 问题是在某些关键区域执行回调,并且您在此例程中可以执行的操作受到限制 (操作系统在禁用了常规内核APC的关键区域内的PASSIVE_LEVEL内调用驱动程序的进程通知例程)。 one of the restrictions - is call ZwAllocateVirtualMemory - it hung in callback, which you and can see. 限制之一-称为ZwAllocateVirtualMemory它挂在回调中,您可以看到。

so you can not call ZwAllocateVirtualMemory and do injection direct from callback. 因此您不能调用ZwAllocateVirtualMemory并直接从回调中进行注入。 but solution exist. 但存在解决方案。 insert normal kernel apc to current thread. 将普通内核apc插入当前线程。 it will be not executed in-place because - normal kernel APCs disabled in callback. 它不会就地执行,因为-回调中禁用了常规内核APC。 but just after you exit from callback and apc will be enabled - your apc executed. 但在您退出回调并启用apc之后,您的apc已执行。 and here (in normal routine) you already can call ZwAllocateVirtualMemory and do dll injection 在这里(按常规),您已经可以调用ZwAllocateVirtualMemory并进行dll注入

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM