代码之家  ›  专栏  ›  技术社区  ›  Oriel Cochavi

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

  •  1
  • Oriel Cochavi  · 技术社区  · 7 年前

    我正在尝试编写一个apc dll注入驱动程序,我发现 this 举例说明并考虑根据我的需要修改它。

    我用 PcreateProcessNotifyRoutineEx 要获取针对特定应用程序的processid,在本例中为“iexplore.exe”,然后使用 PloadImageNotifyRoutine 检查ntdll.dll是否已加载和初始化(从 this recommendation ,如果加载了ntdll.dll,则调用“my”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);
    }
    

    这是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 回复  |  直到 7 年前
        1
  •  2
  •   RbMm    7 年前

    在第一边注-不打电话 PsLookupProcessByProcessId 从图像通知例程。这根本不是必要的。检查一下 ProcessId == PsGetCurrentProcessId() . 如果是-使用当前进程指针(如您在调用中使用的 ZwAllocateVirtualMemory - NtCurrentProcess() )否则就是存在。

    现在关于main-“zwallocatevirtualmemory导致线程终止”-当然不是线程 不终止 . 它 . 首先,如果线程被终止-因为这是这个阶段进程中的单线程-所有进程都被终止。但你自己也这么说 从任务管理器中仍然可以看到该进程 . 另外,如何查看终止线程的调用堆栈?也就是说线程没有终止而是在内部等待 ExAllocatePoolWithTag

    在某个关键区域执行回调的问题 在此例程中可以执行的操作受到限制 (操作系统在禁用正常内核APC的关键区域内以被动级别调用驱动程序的进程通知例程)。其中一个限制是通话 zwallocatevirtualmemory公司 -它挂在回调上,你和你都能看到。

    所以你不能打电话 zwallocatevirtualmemory公司 并直接从回调进行注入。但解决办法是存在的。将普通内核apc插入当前线程。由于在回调中禁用了-normal kernel apcs,因此它将不会在适当的位置执行。但就在您退出回调和APC将被启用-您的APC执行。在这里(按正常程序),你已经可以打电话给 zwallocatevirtualmemory公司 并执行dll注入