So I'm making a crackme and one of the parts is to hook a certain function and wait for a certain combination a params to happen, then the challenge is done.
For that, I'm creating a driver to inject a DLL into processes that have a specific DLL and hook a certain function.
I'm doing it by
ZwCreateFile(
&DeviceExtension->HookDllHandle,
GENERIC_ALL,
&Attributes,
&StatusBlock,
NULL,
0,
0,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
)
PsSetLoadImageNotifyRoutine(ImageCBK);
What's supposed to happen:
ZwCreateSection
, then map the dll into that section and call the DLL's entry point by creating a new thread.Even though the IRQL for ZwCreateSection
and ZwMapViewOfSection
allows their use inside a notify routine, still ZwMapViewOfSection
hangs every time I try to use it.
I've been using some code from Beholder
status = ObOpenObjectByPointer(PsGetCurrentProcess(), OBJ_KERNEL_HANDLE, NULL, STANDARD_RIGHTS_ALL, NULL, KernelMode, &ProcessHandle);
if (!NT_SUCCESS(status))
{
DbgPrint("Unable to get process handle\n");
return STATUS_SEVERITY_ERROR;
}
// Create a new section for DLL mapping
InitializeObjectAttributes(&Attributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwCreateSection(&DllSectionHandle, SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_QUERY, &Attributes, NULL, PAGE_EXECUTE_READ, SEC_IMAGE, DeviceExtension->HookDllHandle);
if (!NT_SUCCESS(status))
{
ZwClose(ProcessHandle);
DbgPrint("Section creation failed %08X\n", status);
return status;
}
DbgPrint("Section created %08X\n", DllSectionHandle);
// Map DLL on the section
status = ZwMapViewOfSection(DllSectionHandle, ProcessHandle, &DllBaseAddress, 0, 0, NULL, &DllViewSize, ViewUnmap, 0, PAGE_EXECUTE_READ);
if (!NT_SUCCESS(status))
{
ZwClose(ProcessHandle);
ZwClose(DllSectionHandle);
DbgPrint("Unable to map section %08X\n", status);
return status;
}
DbgPrint("Mapped DLL: %08X\n", DllBaseAddress);
Sadly, it never shows the last DbgPrint with the DllBaseAddress
simply read documentation
The operating system calls the driver's load-image notify routine at
PASSIVE_LEVEL
inside a critical region with normal kernel APCs always disabled
and
To avoid deadlocks, load-image notify routines must not call system routines that map, allocate, query, free, or perform other operations on user-space virtual memory.
you ignore this and call routine ZwMapViewOfSection
that map. and got deadlock
solution is simply and elegant - insert normal kernel mode APC to current thread inside ImageCBK
. because this APC is disabled here - it executed already after you return from ImageCBK
-just system exit from critical region and enable APC. at this point your apc KernelRoutine/NormalRoutine will be called. and exactly inside NormalRoutine
you must map