Драйвер ядра Windows: ZwAllocateVirtualMemory вызывает прерывание потока - PullRequest
0 голосов
/ 30 мая 2018

Я пытаюсь написать драйвер APC для инъекций DLL, нашел этот пример и подумал изменить его под свои нужды.

Я использую PcreateProcessNotifyRoutineEx чтобы получить ProcessId для конкретных приложений, для которых я настроен, в данном случае «iexplore.exe», а затем с помощью PloadImageNotifyRoutine проверить, загружен ли и инициализирован ли файл ntdll.dll (из этой рекомендации ), и если ntdll.dll загружен, я вызываю «мою» функцию InjectDLL.

Это функция PloadImageNotifyRoutine, которая вызывает InjectDll:

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, он начинает освобождать память, размечать разделы и завершать поток (<= calls я видел в стеке во время отладки - на самом деле не отслеживал каждый вызов, но смотрел на него в общем виде). ​​</p>

стек до завершения потока:

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

процесс все еще виден из диспетчера задач, но его память составляет 92 КБ и не использует ЦП, возможно, из-за того, что он «не очищен» должным образом.

Я не знаю, прав ли мой анализ, и, возможно,это даже не нужно для этой проблемы.

1 Ответ

0 голосов
/ 30 мая 2018

на первой стороне примечания - не вызывайте PsLookupProcessByProcessId из процедуры уведомления изображения.это просто не нужно.проверьте, что ProcessId == PsGetCurrentProcessId().и если да - используйте текущий указатель процесса (как вы и используете в вызове ZwAllocateVirtualMemory - NtCurrentProcess()), в противном случае просто существует.

теперь о главном - "ZwAllocateVirtualMemory, вызывающий прерывание потока" - конечно, нет.поток не завершается .это повешено .сначала, если поток завершается - потому что на данном этапе это единственный поток в процессе - весь процесс завершается.но вы сами говорите, что Процесс все еще виден из диспетчера задач .также, как вы просматриваете стек вызовов завершенного потока?это также говорит о том, что поток не завершен, но ожидает внутри ExAllocatePoolWithTag

проблемы, что обратный вызов выполняется в некоторой критической области и Действия, которые вы можете выполнять в этой подпрограмме, ограничены (Операционная системавызывает процедуру драйвера-процесса уведомления в PASSIVE_LEVEL внутри критической области с отключенными обычными APC ядра).одно из ограничений - это вызов ZwAllocateVirtualMemory - он зависает в обратном вызове, который вы и видите.

, поэтому вы не можете позвонить ZwAllocateVirtualMemory и делать инъекцию прямо из обратного вызова.но решение существует.вставить нормальное ядро ​​apc в текущий поток.это не будет выполнено на месте, потому что - нормальные APC ядра отключены в обратном вызове.но сразу после выхода из callback и apc будет включен - ваш apc выполнен.и здесь (в обычном порядке) вы уже можете позвонить ZwAllocateVirtualMemory и сделать инъекцию dll

...