Win64 驱动内核编程-13.回调监控模块加载
回調(diào)監(jiān)控模塊加載
????模塊加載包括用戶層模塊(.DLL)和內(nèi)核模塊(.SYS)的加載。傳統(tǒng)方法要監(jiān)控這兩者加在必須?HOOK?好幾個函數(shù),比如?NtCreateSection?和?NtLoadDriver
等,而且這些方法還不能監(jiān)控未知的驅(qū)動加載方法。其實為了監(jiān)控模塊加載而HOOK?API?是非常傻的,因為微軟已經(jīng)提供了一對標(biāo)準(zhǔn)的?API?實現(xiàn)此功能。它們
分別是?PsSetLoadImageNotifyRoutine?和?PsRemoveLoadImageNotifyRoutine,可以設(shè)置/取消一個“映像加載通告例程”,當(dāng)有驅(qū)動或者?DLL?被加載時,回調(diào)函
數(shù)就會被調(diào)用。有人可能認(rèn)為這個標(biāo)準(zhǔn)方法的監(jiān)控非常表層,其實恰恰相反,這個方法非常底層,大部分隱秘的加載驅(qū)動的方法都可以繞過?NtLoadDriver,但
是無法繞過“映像加載通告例程”。所以用此方法監(jiān)控驅(qū)動加載是最合適的了。
????之前說過,這個通告例程不僅僅管加載驅(qū)動,連進(jìn)程加載?DLL?也管,那我們怎么判斷到底是加載驅(qū)動還是加載?DLL?呢?如果說根據(jù)后綴名判斷則很明顯是一個挫方法。我的方
法是,?根據(jù)回調(diào)函數(shù)?e?LoadImageNotifyRoutine??的第二個參數(shù)判斷,如果?D?PID??是0?0?,則表示加載驅(qū)動,如果?D?PID??位非零,則?表示加載??DLL?。原因很簡單,我之前說過這個函數(shù)很底層,到了一定的深度之后就無法判斷到底是誰主動引發(fā)的行為了,一切都是系統(tǒng)的行為。當(dāng)然,你也可以認(rèn)為這是通過回調(diào)來監(jiān)控驅(qū)動加載的缺點(diǎn)。判斷了是驅(qū)動后,就通過?ImageInfo->ImageBase?來獲取驅(qū)動的映像基址。過?如果不想讓這個驅(qū)動加載,就通過?e?ImageBase?得?來獲得?y?DriverEntry??的地址(ImageBase?就是?DOS?頭,根據(jù)?DOS?頭找到?NT?頭,然后在?NT?頭的?OptionalHeader里就能找到入口點(diǎn)了。入口點(diǎn)的數(shù)據(jù)就是?DriverEntry?的地址)?,?并?寫入?“拒絕訪問?”?的機(jī)器碼?即可。
//添加: PsSetLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)LoadImageNotifyRoutine); //刪除: PsRemoveLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)LoadImageNotifyRoutine);其中 NotifyRoutine 是一個函數(shù)指針,此回調(diào)函數(shù)的原型是: VOID (*PLOAD_IMAGE_NOTIFY_ROUTINE) ( __in_opt PUNICODE_STRING FullImageName, __in HANDLE ProcessId, __in PIMAGE_INFO ImageInfo ); 下面是實現(xiàn)模塊監(jiān)控,并且拒絕Powertool的驅(qū)動加載的例子代碼: #include <ntddk.h> #include <ntimage.h>#define dprintf DbgPrintBOOLEAN VxkCopyMemory( PVOID pDestination, PVOID pSourceAddress, SIZE_T SizeOfCopy ) {PMDL pMdl = NULL;PVOID pSafeAddress = NULL;pMdl = IoAllocateMdl( pSourceAddress, (ULONG)SizeOfCopy, FALSE, FALSE, NULL );if( !pMdl ) return FALSE;__try{MmProbeAndLockPages( pMdl, KernelMode, IoReadAccess );}__except(EXCEPTION_EXECUTE_HANDLER){IoFreeMdl( pMdl );return FALSE;}pSafeAddress = MmGetSystemAddressForMdlSafe( pMdl, NormalPagePriority );if( !pSafeAddress ) return FALSE;RtlCopyMemory( pDestination, pSafeAddress, SizeOfCopy );MmUnlockPages( pMdl );IoFreeMdl( pMdl );return TRUE; }VOID UnicodeToChar(PUNICODE_STRING dst, char *src) {ANSI_STRING string;RtlUnicodeStringToAnsiString(&string,dst, TRUE);strcpy(src,string.Buffer);RtlFreeAnsiString(&string); }void DenyLoadDriver(PVOID DriverEntry) { UCHAR fuck[]="\xB8\x22\x00\x00\xC0\xC3"; VxkCopyMemory(DriverEntry,fuck,sizeof(fuck)); }PVOID GetDriverEntryByImageBase(PVOID ImageBase) { PIMAGE_DOS_HEADER pDOSHeader; PIMAGE_NT_HEADERS64 pNTHeader; PVOID pEntryPoint; pDOSHeader = (PIMAGE_DOS_HEADER)ImageBase; pNTHeader = (PIMAGE_NT_HEADERS64)((ULONG64)ImageBase + pDOSHeader->e_lfanew); pEntryPoint = (PVOID)((ULONG64)ImageBase + pNTHeader->OptionalHeader.AddressOfEntryPoint); return pEntryPoint; }VOID LoadImageNotifyRoutine (__in_opt PUNICODE_STRING FullImageName,__in HANDLE ProcessId,__in PIMAGE_INFO ImageInfo ) { PVOID pDrvEntry; char szFullImageName[260]={0}; if(FullImageName!=NULL && MmIsAddressValid(FullImageName)) { if(ProcessId==0) { DbgPrint("[MyDriver]%wZ\n", FullImageName); pDrvEntry=GetDriverEntryByImageBase(ImageInfo->ImageBase); DbgPrint("[MyDriver]DriverEntry: %p\n",pDrvEntry); UnicodeToChar(FullImageName,szFullImageName); if(strstr(_strlwr(szFullImageName),"kevp64.sys")) { DbgPrint("[MyDriver]Deny load [WIN64AST.SYS]"); //禁止加載win64ast.sys DenyLoadDriver(pDrvEntry); } } } }加載: PsSetLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)LoadImageNotifyRoutine); 注銷: PsRemoveLoadImageNotifyRoutine((PLOAD_IMAGE_NOTIFY_ROUTINE)LoadImageNotifyRoutine);????執(zhí)行結(jié)果,通過Pchunter看監(jiān)控當(dāng)前驅(qū)動信息,PowerTool驅(qū)動被拒絕加載之后不但自己沒有提示,而且還在桌面上留下了自己的驅(qū)動文件,這相當(dāng)于是你雙擊了一個exe,結(jié)果在exe入口函數(shù)的地方內(nèi)存編程不可操作了,這種很難檢測出問題來:
禁止加載驅(qū)動的方式也可以用來禁止加載dll。
總結(jié)
以上是生活随笔為你收集整理的Win64 驱动内核编程-13.回调监控模块加载的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Win64 驱动内核编程-12.回调监控
- 下一篇: Win64 驱动内核编程-14.回调监控