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

时间:2018-05-30 17:50:07

标签: c windows driver low-level windows-kernel

我试图编写一个APC dll注入驱动程序,我找到了this示例,并考虑根据我的需要对其进行修改。

我使用PcreateProcessNotifyRoutineEx获取我定位的特定应用程序的ProcessId,在本例中为" iexplore.exe"然后使用PloadImageNotifyRoutine检查ntdll.dll是否已加载并初始化(来自this recommendation),如果加载了ntdll.dll,我会调用" my"注入DLL函数。

这是调用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);
}

这是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 ...
}

我在这里删除了一些检查,以便更清楚。

我尝试稍微调试一下,但似乎ZwAllocateVirtualMemory试图分配内存,在某些时候失败并终止线程。

在调用ExAllocatePoolWithTag后,它开始释放内存,取消映射部分并终止线程(< =我在调试时在堆栈中看到的调用 - 没有真正跟踪每个调用,但在一般视图中查看它)

线程终止前的堆栈:

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

该过程仍可从任务管理器看到,但其内存为92k并且没有CPU使用率,可能是因为它没有清理"正常。

我不知道我的分析是否正确,甚至可能不需要这个问题。

1 个答案:

答案 0 :(得分:2)

在第一边注意 - 不要从图像通知例程调用PsLookupProcessByProcessId。这根本不需要。检查ProcessId == PsGetCurrentProcessId()。如果是 - 请使用当前流程指针(正如您所使用并在调用中使用ZwAllocateVirtualMemory - NtCurrentProcess())否则就会存在。

现在关于main - “ZwAllocateVirtualMemory导致线程终止” - 当然没有。线程不终止。它。首先,如果线程终止 - 因为这是在这个阶段正在处理的单线程 - 所有进程都终止。但是你自己说这个过程仍然可以从任务管理器中看到。你如何查看终止线程的调用堆栈?这也说明线程没有终止,而是在ExAllocatePoolWithTag

内等待

回调在某个关键区域中执行的问题您可以在此例程中执行的操作受到限制(操作系统在正常关键区域内的PASSIVE_LEVEL处调用驱动程序的进程通知例程内核APC禁用)。其中一个限制 - 叫ZwAllocateVirtualMemory - 它挂在回调中,你可以看到。

因此您无法调用ZwAllocateVirtualMemory并直接从回调中进行注射。但解决方案存在。将普通内核apc插入当前线程。它将不会就地执行,因为 - 在回调中禁用了正常的内核APC。但是在你退出回调之后,apc将被启用 - 你的apc被执行了。在这里(在正常的例程中)你已经可以调用ZwAllocateVirtualMemory并执行dll注入