阅读928 返回首页    go 阿里云 go 技术社区[云栖]


[原创]W2k Driving 学习笔记(一)内核线程及同步

[大体流程]

Win32与Kernel交互,从User层向内核发送2个请求:

0 IOCTL_Start_Thread : 从内核新建一个线程,最多建立MAX_THREAD_NUM个线程;

1 IOCTL_Stop_Thread : 关闭刚才建立的所有线程;

每个线程做同样的事,每次将变量Count增加1,使用一个FAST_MUTEX来同步加1操作。

线程过程如下,没什么特别说明的,其中为了照顾偶的眼球眨动频率,特地做了1s的延时。

DDKAPI VOID CountThreadMain(IN PVOID pContext) { PDEVICE_EX pDevEx = (PDEVICE_EX)pContext; LARGE_INTEGER dt = RtlConvertLongToLargeInteger(/ -10 * 1000 * 1000); ULONG tid = (ULONG)PsGetCurrentThreadId(); PRINT("[%s]entry new thread[id:%d]",/ __func__,tid); while(!pDevEx->bEXIT_THREADS) { ExAcquireFastMutex(&pDevEx->FastMtx); ++pDevEx->Count; ExReleaseFastMutex(&pDevEx->FastMtx); PRINT("[%s][tid:%d]Now Count is %d/n",/ __func__,tid,pDevEx->Count); if(!NT_SUCCESS(KeDelayExecutionThread(KernelMode,/ false,&dt))) { PRINT("[%s]err : Delay Failed!/n",__func__); break; } } PRINT("[%s]exit thread[id:%d]/n",/ __func__,tid); (VOID)PsTerminateSystemThread(STATUS_SUCCESS); }

 

在退时要注意,在未退出所有线程之前,绝不能Unload Driver,否则线程所在的内存

区将会被Unmap,系统将会发生缺页0x0E异常。我做了一个等待处理:

DDKAPI VOID WaitKillThreads(PDEVICE_OBJECT pDeviceObject) { PDEVICE_EX pDevEx = (PDEVICE_EX)pDeviceObject->DeviceExtension; PRINT("[%s]sizeof WAIT_BLOCK is %d/n",__func__,sizeof(KWAIT_BLOCK)); if(pDevEx->CURRENT_THREAD_NUM == 0) return; pDevEx->bEXIT_THREADS = TRUE; PKWAIT_BLOCK pKB = (PKWAIT_BLOCK)ExAllocatePool(/ NonPagedPool,/ sizeof(KWAIT_BLOCK)*pDevEx->CURRENT_THREAD_NUM); if(pKB == NULL) { PRINT("[%s]Alloc Mem Failed!/n",__func__); return; } if(!NT_SUCCESS(KeWaitForMultipleObjects(/ pDevEx->CURRENT_THREAD_NUM,/ pDevEx->pThreadObjs,WaitAll,/ Executive,KernelMode,TRUE,/ NULL,pKB))) { PRINT("[%s]KeWaitForMultipleObjects Failed!/n",/ __func__); } ExFreePool((PVOID)pKB); }

 

原先的WaitKillThreads老是导致系统蓝屏,调试发现只有当建立的线程数超过3个时

才会蓝屏,进一步分析,蓝屏的原因是WaitKillThreads将DrvDispatchControl的

第2个参数pIrp写成了垃圾数据。为什么只有当Thread数大于3时才这样呢?观察

WaitKillThreads中可能会擦写内核栈的只有KeWaitForMultipleObjects的回写操作

(pKB),查阅DDK Helps 之后发现,如果等待的对象> THREAD_WAIT_OBJECTS则,

必须分配 sizeof(KWAIT_BLOCK) * Count 字节的非分页内存让其写入。一查

THREAD_WAIT_OBJECTS大小正好等于3,答案揭晓:

WaitKillThreads在最高优化中是内联编入派遣过程,这意味着它们共用一个函数栈桢,

KWAIT_BLOCK大小为24,则如果线程数大于3则正好溢出覆盖掉pIrp内容,My God!

 

另外,在编译代码是发现找不到WaitAll或WaitAny的声明,我用的是MinGW(gcc)5.1.4

版本,在winddk.h中发现其将WAIT_TYPE定义成ULONG,将其改为:

typedef enum _WAIT_TYPE { WaitAll, WaitAny }WAIT_TYPE;

 

后建立成功。

最后更新:2017-04-02 00:06:41

  上一篇:go 顺序栈(C#)
  下一篇:go ASP.Net RssToolkit Version 2.0