Win64 驅動核心程式設計-34.對抗與列舉MiniFilter
對抗與列舉MiniFilter
MiniFilter 是目前防毒軟體用來實現“檔案系統自我保護”和“檔案實時監控”的方法。
由於 MiniFilter 模型簡單,開發快捷,通用性好,以前用 FSD HOOK 或者標準過濾驅動來實現相關功能的殺軟紛紛改用 MiniFilter,比如卡巴斯基。不過,列舉 MiniFilter 就跟之前列舉回撥的方法不太相同了,因為 MiniFilter 的框架不在 NTOSKRNL 裡,自成一套系統,有專用的 API。不過“自成一套系統,有專用 API”的好處就是,無需我們自己通過特徵碼來定位陣列或者連結串列,直接使用 MiniFilter 提供的 API
列舉MiniFilter主要使用FltEnumerateFilters這個API,它會返回過濾器物件(FLT_FILTER)的地址,然後根據過濾器物件的地址,加上一個偏移,獲得記錄過濾器 PreCall、PostCall、IRP 等資訊的結構體指標(PFLT_OPERATION_REGISTRATION)。上文之所以說要加上偏移,是因為 FLT_FILTER 的定義在每個系統都不同,比如 WIN7X64 中的定義為:
nt!DbgBreakPointWithStatus:
fffff800`03e74f60 cc int 3
kd> dt fltmgr!_FLT_FILTER
+0x000 Base : _FLT_OBJECT
+0x020 Frame : Ptr64 _FLTP_FRAME
+0x028 Name : _UNICODE_STRING
+0x038 DefaultAltitude : _UNICODE_STRING
+0x048 Flags : _FLT_FILTER_FLAGS
+0x050 DriverObject : Ptr64 _DRIVER_OBJECT
+0x058 InstanceList : _FLT_RESOURCE_LIST_HEAD
+0x0d8 VerifierExtension : Ptr64 _FLT_VERIFIER_EXTENSION
+0x0e0 VerifiedFiltersLink : _LIST_ENTRY
+0x0f0 FilterUnload : Ptr64 long
+0x0f8 InstanceSetup : Ptr64 long
+0x100 InstanceQueryTeardown : Ptr64 long
+0x108 InstanceTeardownStart : Ptr64 void
+0x110 InstanceTeardownComplete : Ptr64 void
+0x118 SupportedContextsListHead : Ptr64 _ALLOCATE_CONTEXT_HEADER
+0x120 SupportedContexts : [6] Ptr64 _ALLOCATE_CONTEXT_HEADER
+0x150 PreVolumeMount : Ptr64 _FLT_PREOP_CALLBACK_STATUS
+0x158 PostVolumeMount : Ptr64 _FLT_POSTOP_CALLBACK_STATUS
+0x160 GenerateFileName : Ptr64 long
+0x168 NormalizeNameComponent : Ptr64 long
+0x170 NormalizeNameComponentEx : Ptr64 long
+0x178 NormalizeContextCleanup : Ptr64 void
+0x180 KtmNotification : Ptr64 long
+0x188 Operations : Ptr64 _FLT_OPERATION_REGISTRATION
+0x190 OldDriverUnload : Ptr64 void
+0x198 ActiveOpens : _FLT_MUTEX_LIST_HEAD
+0x1e8 ConnectionList : _FLT_MUTEX_LIST_HEAD
+0x238 PortList : _FLT_MUTEX_LIST_HEAD
+0x288 PortLock : _EX_PUSH_LOCK
FLT_OPERATION_REGISTRATION 的結構體定義是不變的:
列舉程式碼如下:
#include <Fltkernel.h>
ULONG FltFilterOperationsOffset=0x188; //WIN7 OFFSET of fltmgr!_FLT_FILTER->PFLT_OPERATION_REGISTRATION
//typedef struct _FLT_OPERATION_REGISTRATION
//{
//UCHARMajorFunction;
//ULONGFlags;
//PVOIDPreOperation;
//PVOIDPostOperation;
//PVOIDReserved1;
//} FLT_OPERATION_REGISTRATION, *PFLT_OPERATION_REGISTRATION;
typedef struct _FLT_FILTER
{
UCHAR buffer[1024];
} FLT_FILTER, *PFLT_FILTER;
//NTSTATUS
//__fastcall
//FltEnumerateFilters
//(
// PFLT_FILTER *FilterList,
// ULONG FilterListSize,
// PULONG NumberFiltersReturned
//);
//
//NTSTATUS
//__fastcall
//FltObjectDereference
//(
// PVOID FltObject
//);
ULONG EnumMiniFilter()
{
long ntStatus;
ULONG uNumber;
PVOID pBuffer = NULL;
ULONG uIndex = 0, DrvCount = 0;
PVOID pCallBacks = NULL, pFilter = NULL;
PFLT_OPERATION_REGISTRATION pNode;
do
{
if(pBuffer != NULL)
{
ExFreePool(pBuffer);
pBuffer = NULL;
}
ntStatus = FltEnumerateFilters(NULL, 0, &uNumber);
if(ntStatus != STATUS_BUFFER_TOO_SMALL)
break;
pBuffer = ExAllocatePoolWithTag(NonPagedPool, sizeof(PFLT_FILTER) * uNumber, 'mnft');
if(pBuffer == NULL)
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
break;
}
ntStatus = FltEnumerateFilters(pBuffer, uNumber, &uNumber);
}
while (ntStatus == STATUS_BUFFER_TOO_SMALL);
if(! NT_SUCCESS(ntStatus))
{
if(pBuffer != NULL)
ExFreePool(pBuffer);
return 0;
}
DbgPrint("MiniFilter Count: %ld\n",uNumber);
DbgPrint("------\n");
__try
{
while(DrvCount<uNumber)
{
pFilter = (PVOID)(*(PULONG64)((PUCHAR)pBuffer + DrvCount * 8));
pCallBacks = (PVOID)((PUCHAR)pFilter + FltFilterOperationsOffset);
pNode = (PFLT_OPERATION_REGISTRATION)(*(PULONG64)pCallBacks);
__try
{
while(pNode->MajorFunction != 0x80) //IRP_MJ_OPERATION_END
{
if(pNode->MajorFunction<28) //MajorFunction id is 0~27
{
DbgPrint("Object=%p\tPreFunc=%p\tPostFunc=%p\tIRP=%d\n",
pFilter,
pNode->PreOperation,
pNode->PostOperation,
pNode->MajorFunction);
}
pNode++;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
FltObjectDereference(pFilter);
DbgPrint("[EnumMiniFilter]EXCEPTION_EXECUTE_HANDLER: pNode->MajorFunction\n");
ntStatus = GetExceptionCode();
ExFreePool(pBuffer);
return uIndex;
}
DrvCount++;
FltObjectDereference(pFilter);
DbgPrint("------\n");
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
FltObjectDereference(pFilter);
DbgPrint("[EnumMiniFilter]EXCEPTION_EXECUTE_HANDLER\n");
ntStatus = GetExceptionCode();
ExFreePool(pBuffer);
return uIndex;
}
if(pBuffer != NULL)
{
ExFreePool(pBuffer);
ntStatus=STATUS_SUCCESS;
}
return uIndex;}
執行結果:
不過對抗 MiniFilter 似乎就只有兩種方法了:
1.把記錄的函式地址改為自己設定的空函式;
2.把處理函式頭改為 RET 直接返回。 為什麼不能把 直接把 MiniFilter 物件 反註冊呢?因為MSDN 對 對 FltUnregisterFilter 的 用途 給出了 這樣的解釋 :A minifilter driver can only callFltUnregisterFilter to unregister itself, not another minifilter driver。據我測試,如果第三方驅動強制使用此函式登出一個 MiniFilter,輕則無效,重則藍屏。
把 MINIFILTER 的處理函式禁用掉之後,卡巴斯基 2013 在 WIN64 系統上的檔案保護就徹底失效了,可以直接使用最簡單的方法來刪除卡巴斯基資料夾內的檔案,國內那些採用同樣方法實現檔案自我保護的防毒軟體(****)同理。