从 LoadImageNotifyRoutine 注入 DLL,在 ZwMapViewOfSection 上挂起
Injecting a DLL from LoadImageNotifyRoutine, hangs on ZwMapViewOfSection
所以我正在制作一个 crackme,其中一部分是挂钩某个函数并等待某个参数组合发生,然后挑战就完成了。
为此,我正在创建一个驱动程序以将 DLL 注入具有特定 DLL 的进程并挂接特定功能。
我正在做
- 获取要注入的 DLL 的句柄
ZwCreateFile(
&DeviceExtension->HookDllHandle,
GENERIC_ALL,
&Attributes,
&StatusBlock,
NULL,
0,
0,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
)
- 然后,在主驱动中注册一个LoadImageNotifyRoutine
PsSetLoadImageNotifyRoutine(ImageCBK);
应该发生什么:
- 我检查是否加载了所需的 DLL(将导出我的函数)。
- 通过在调用回调的进程上下文中,我使用
ZwCreateSection
创建了一个部分,然后将 dll 映射到该部分并通过创建新线程调用 DLL 的入口点。
- 之后hook应该没问题了
尽管 ZwCreateSection
和 ZwMapViewOfSection
的 IRQL 允许在通知例程中使用它们,但每次我尝试使用它时 ZwMapViewOfSection
仍然挂起。
我一直在使用 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);
遗憾的是,它从未显示带有 DllBaseAddress
的最后一个 DbgPrint
简单阅读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
和
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.
你忽略这个并调用 map 的例程 ZwMapViewOfSection
。并陷入僵局
解决方案简单而优雅 - 将普通内核模式 APC 插入 ImageCBK
内的当前线程。因为此 APC 在这里被禁用 - 它已经在你从 ImageCBK
return 之后执行 - 只是系统从关键区域退出并启用 APC。此时你的 apc KernelRoutine/NormalRoutine 将被调用。并且恰好在 NormalRoutine
内,您必须映射
所以我正在制作一个 crackme,其中一部分是挂钩某个函数并等待某个参数组合发生,然后挑战就完成了。
为此,我正在创建一个驱动程序以将 DLL 注入具有特定 DLL 的进程并挂接特定功能。
我正在做
- 获取要注入的 DLL 的句柄
ZwCreateFile(
&DeviceExtension->HookDllHandle,
GENERIC_ALL,
&Attributes,
&StatusBlock,
NULL,
0,
0,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
)
- 然后,在主驱动中注册一个LoadImageNotifyRoutine
PsSetLoadImageNotifyRoutine(ImageCBK);
应该发生什么:
- 我检查是否加载了所需的 DLL(将导出我的函数)。
- 通过在调用回调的进程上下文中,我使用
ZwCreateSection
创建了一个部分,然后将 dll 映射到该部分并通过创建新线程调用 DLL 的入口点。 - 之后hook应该没问题了
尽管 ZwCreateSection
和 ZwMapViewOfSection
的 IRQL 允许在通知例程中使用它们,但每次我尝试使用它时 ZwMapViewOfSection
仍然挂起。
我一直在使用 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);
遗憾的是,它从未显示带有 DllBaseAddress
简单阅读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
和
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.
你忽略这个并调用 map 的例程 ZwMapViewOfSection
。并陷入僵局
解决方案简单而优雅 - 将普通内核模式 APC 插入 ImageCBK
内的当前线程。因为此 APC 在这里被禁用 - 它已经在你从 ImageCBK
return 之后执行 - 只是系统从关键区域退出并启用 APC。此时你的 apc KernelRoutine/NormalRoutine 将被调用。并且恰好在 NormalRoutine
内,您必须映射