1. Wait函数
用户模式下的WaitForSingleObject和WaitForMultipleObject都是依赖内核模式下的KeWaitForSingleObject和KeWaitForMultipleObjects函数实现的,其声明如下:NTSTATUS
KeWaitForMultipleObjects(
IN ULONG Count,//
IN PVOID Object[],
IN WAIT_TYPE WaitType,
IN KWAIT_REASON WaitReason,
IN KPROCESSOR_MODE WaitMode,
IN BOOLEAN Alertable,//
IN PLARGE_INTEGER Timeout OPTIONAL,
IN PKWAIT_BLOCK WaitBlockArray OPTIONAL
);
Alertable是一个布尔类型的值。它不同于WaitReason,这个参数以另一种方式影响系统行为,它决定等待是否可以提前终止以提交一个APC。如果等待发生在用户模式中,那么内存管理器就可以把线程的内核模式堆栈换出。如果驱动程序以自动变量(在堆栈中)形式创建事件对象,并且某个线程又在提升的IRQL级上调用了KeSetEvent,而此时该事件对象刚好又被换出内存,结果将产生一个bug check。所以我们应该总把alertable参数指定为FALSE,即在内核模式中等待。
Timeout是一个64位超时值的地址,单位为100纳秒。正数的超时表示一个从1601年1月1日起的绝对时间。调用KeQuerySystemTime函数可以获得当前系统时间。负数代表相对于当前时间的时间间隔。如果你指定了绝对超时,那么系统时钟的改变也将影响到你的超时时间。如果系统时间越过你指定的绝对时间,那么永远都不会超时。相反,如果你指定相对超时,那么你经过的超时时间将不受系统时钟改变的影响,指定为NULL表示永久等待
2.创建线程
内核下创建新线程使用PsCreateSystemThreadNTSTATUS
PsCreateSystemThread(
OUT PHANDLE ThreadHandle,//得到新创建的线程句柄
IN ULONG DesiredAccess,//创建的权限
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,//一般设为NULL
IN HANDLE ProcessHandle OPTIONAL,//如果是进程句柄,则线程属于指定的进程,如果NULL,则为系统进程
OUT PCLIENT_ID ClientId OPTIONAL,//驱动创建时,设为NULL
IN PKSTART_ROUTINE StartRoutine,//新线程的运行地址
IN PVOID StartContext//新线程接收的参数
);
系统进程指ID为4的System进程,创建的线程并须自己用PsTerminateSystemThread强制结束线程,否则线程是无法自动退出的,这个调用必须在IRQL=PASSIVE_LEVEL下进行
随手示例创建用户线程和系统线程:
#define IOCTL_TEST2
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS¦FILE_WRITE_ACCESS)
#pragma code_seg("PAGE")
VOID SystemThread(PVOID pContext)
{
KdPrint(("Entry SystemThreadn"));
PEPROCESS pEProcess = IoGetCurrentProcess();
PTSTR ProcessName = (PTSTR)((ULONG)pEProcess + 0x174);
KdPrint(("This Thread run in %s processn", ProcessName));
PsTerminateSystemThread(STATUS_SUCCESS);
KdPrint(("Leave SystemThreadn"));
}
#pragma code_seg("PAGE")
VOID MyThread(PVOID pContext)
{
KdPrint(("Entry MyThread:%sn", (CHAR*)pContext));
PEPROCESS pEProcess = IoGetCurrentProcess();
PTSTR ProcessName = (PTSTR)((ULONG)pEProcess + 0x174);
KdPrint(("This Thread run in %s processn", ProcessName));
PsTerminateSystemThread(STATUS_SUCCESS);
KdPrint(("Leave MyThreadn"));
}
#pragma code_seg("PAGE")
VOID CreateThreadTest()
{
HANDLE hSysThread = NULL;
HANDLE hMyThread = NULL;
CHAR *p = "parameter";
NTSTATUS status = PsCreateSystemThread
(&hSysThread, 0, NULL, NULL, NULL, SystemThread, NULL);
status = PsCreateSystemThread
(&hMyThread, 0, NULL, NtCurrentProcess(), NULL, MyThread, (PVOID)p);
}
调用方式:使用demo发个IO控制码过去,调用CreateThreadTest即可