閱讀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