当您创建使用驱动程序的线程时,驱动程序在线程退出之前必须不被卸载。要做到这一点,需要在创建线程之前调用ObfReferenceObject
以引用您的驱动程序对象。如果创建线程失败,则需要调用ObfDereferenceObject
。当线程退出时,需要调用ObfDereferenceObject
。但是这里有一个问题——如何/从哪里调用?从线程例程的末尾调用ObfDereferenceObject
没有意义——驱动程序可能会在ObfDereferenceObject
内部卸载,并且我们会从调用返回到不存在的内存位置。理想情况下,外部代码(Windows本身)会在线程返回后立即调用此函数。
寻找{{link1:IoAllocateWorkItem
}}以获取良好的示例。工作项类似于线程,驱动程序必须在WorkerRoutine
返回之前不被卸载。系统会关心这一点-因此我们将DeviceObject
传递给IoAllocateWorkItem
:指向调用者的驱动程序对象或调用者设备对象之一的指针。 -当我们调用IoQueueWorkItem
时,系统会引用此对象(设备或驱动程序),并保证在WorkerRoutine
执行期间不会卸载驱动程序。当它返回时- Windows为传递的设备或驱动程序对象调用ObfDereferenceObject
。在此之后,我们返回到系统内核代码(而不是驱动程序)。但不幸的是,PsCreateSystemThread
不接受驱动程序对象的指针,并且没有实现这样的功能。
另一个很好的例子{{link1:FreeLibraryAndExitThread
}} - 事实上,驱动程序是内核模式dll,可以加载和卸载。 {{link1:FreeLibraryAndExitThread
}} 正好实现了我们需要的功能,但仅适用于用户模式dll。 再次强调,在内核模式中没有这样的api。
但无论如何,解决方案是可能的。 可以自己跳转(而不是调用)到线程执行结束时的ObfDereferenceObject
,但需要使用汇编代码。 不可能在c / c ++中进行此技巧。
首先,让我们在全局变量中声明指向驱动程序对象的指针 - 我们在驱动程序入口点中将其初始化为有效值。
extern "C" PVOID g_DriverObject;
除了一些用于获取混淆的c++名称的宏之外,这需要在asm文件中使用:
在中,我们为线程声明了2个函数:
VOID _AThread(IN PVOID Context)_ASM_FUNCTION;
VOID __fastcall AThread(IN PVOID Context)
{
CPP_FUNCTION;
}
(不要忘记在AThread
上使用__fastcall
-对于x86来说这是必需的)
现在我们使用以下代码创建线程:
ObfReferenceObject(g_DriverObject);
HANDLE hThread;
if (0 > PsCreateSystemThread(&hThread, 0, 0, 0, 0, _AThread, ctx))
else
所以你将线程入口点设置为_AThread
,该入口点将在asm文件中实现。在开始时,你调用ObfReferenceObject(g_DriverObject);
。_AThread
将调用你的实际线程实现AThread
(使用c++编写)。最后它返回到_AThread
(因此你不能调用PsTerminateSystemThread
)。无论如何,调用这个API是可选的 - 当线程例程将控制权返回给系统时,它将自动调用此函数。最后,_AThread
取消引用g_DriverObject
并返回给系统。
所以主要的技巧在于asm文件。这里有两个x86和x64的asm文件:
x86:
.686p
extern _g_DriverObject:DWORD
extern __imp_@ObfDereferenceObject@4:DWORD
extern ?AThread@@YIXPAX@Z : PROC
_TEXT segment
?_AThread@@YGXPAX@Z proc
pop ecx
xchg ecx,[esp]
call ?AThread@@YIXPAX@Z
mov ecx,_g_DriverObject
jmp __imp_@ObfDereferenceObject@4
?_AThread@@YGXPAX@Z endp
_TEXT ends
END
x64:
extern g_DriverObject:QWORD
extern __imp_ObfDereferenceObject:QWORD
extern ?AThread@@YAXPEAX@Z : PROC
_TEXT segment 'CODE'
?_AThread@@YAXPEAX@Z proc
sub rsp,28h
call ?AThread@@YAXPEAX@Z
add rsp,28h
mov rcx,g_DriverObject
jmp __imp_ObfDereferenceObject
?_AThread@@YAXPEAX@Z endp
_TEXT ENDS
END