首页
社区
课程
招聘
[原创]minifilter实现文件隐藏
发表于: 2018-4-20 18:02 12261

[原创]minifilter实现文件隐藏

2018-4-20 18:02
12261

用minifilter  实现文件隐藏(大神可以绕道了),主要是根据网上的一些资料自己整合的一个系统,包括驱动层和应用层。

开发环境:win7_x64, QT5.2,WDK7600,8G

测试环境:win7_x86,2G


在看雪上也呆了一年多,经常问问题,看别人的精华帖,现在自己也来贡献一篇。


文中只处理了IRP_MJ_DIRECTORY_CONTROL这一个IRP,是在它的后操作中来实现的

CONST FLT_OPERATION_REGISTRATION Callbacks[] = {

		{ IRP_MJ_DIRECTORY_CONTROL, 
		0,
		NULL,
		PtPostOperationHide 
		},

		{ IRP_MJ_OPERATION_END }


主要是根据路径和文件名来隐藏,根据应用层传过来的信息判断是隐藏文件还是路径

NTSTATUS MHideMessage(  __in PVOID ConnectionCookie,
						__in_bcount_opt(InputBufferSize) PVOID InputBuffer,
						__in ULONG InputBufferSize, 
						__out_bcount_part_opt(OutputBufferSize,*ReturnOutputBufferLength) PVOID OutputBuffer, 
						__in ULONG OutputBufferSize, 
						__out PULONG ReturnOutputBufferLength )
{

	INPUT_BUFFER inputBuf;
	MY_COMMAND command;
	PAGED_CODE();
	UNREFERENCED_PARAMETER( ConnectionCookie );
	UNREFERENCED_PARAMETER( OutputBufferSize );
	UNREFERENCED_PARAMETER( OutputBuffer );
	KdPrint(("接收应用层传过来的消息 \n"));
	RtlZeroMemory(&inputBuf ,sizeof(INPUT_BUFFER));
	if ((InputBuffer == NULL ) || (InputBufferSize > sizeof(INPUT_BUFFER)))
	{
		return STATUS_INVALID_PARAMETER;
	}
	RtlCopyMemory(&inputBuf , InputBuffer,InputBufferSize);
	command = inputBuf.command;
	switch(command)
	{
	case ADD_HIDE_PATH: 	
		KdPrint(("inputBuf.hidePath = %S \n",inputBuf.hidePath));	
		AddHidePath(inputBuf.hidePath);	
		break;
	case SHOW_HIDE_PATH:
		KdPrint(("即将进入ShowHidePath\n"));
		ShowHidePath(inputBuf.hidePath);
		break;
	default:
		break;
	}
	return STATUS_SUCCESS;
}

将传入的文件信息依次放入链表中(与后操作中的文件信息进行对比,符合就断链) ,传入要隐藏的文件

VOID AddHidePath(PWSTR xxPath){
	PHIDE_PATH_LIST pathListNode ,pathList;
	BOOL bRet;
	KIRQL Irql;
	pathListNode = (PHIDE_PATH_LIST)ExAllocatePoolWithTag(NonPagedPool,sizeof(HIDE_PATH_LIST),HIDE_TAG);
	if (pathListNode == NULL)
	{
		return ;
	}
			wcscpy(pathListNode->xxPath,xxPath);
		KeAcquireSpinLock(&HidePathListLock,&Irql);
	InsertTailList(&HidePathListHeader,&pathListNode->listNode);
		KeReleaseSpinLock(&HidePathListLock,Irql);
}


传入要取消隐藏的文件

VOID ShowHidePath(PWSTR xxPath){
	PHIDE_PATH_LIST hideList;
	PLIST_ENTRY pListNode;
	KIRQL Irql;
	KdPrint(("ShowHidePath\n"));
	if (!IsListEmpty(&HidePathListHeader))
	{
		for (pListNode = HidePathListHeader.Flink; pListNode!=&HidePathListHeader; pListNode = pListNode->Flink)
		{
			hideList = CONTAINING_RECORD(pListNode,HIDE_PATH_LIST,listNode);
			if (wcscmp(hideList->xxPath,xxPath) == 0)
			{
				KeAcquireSpinLock(&HidePathListLock,&Irql);
				RemoveEntryList(&hideList->listNode);
				ExFreePoolWithTag(hideList , HIDE_TAG);	
				KeReleaseSpinLock(&HidePathListLock,Irql);
				return ;

			}
		}
	}
}

IRP_MJ_DIRECTORY_CONTROL的后操作

//主要的隐藏函数
FLT_POSTOP_CALLBACK_STATUS
PtPostOperationHide (
    __inout PFLT_CALLBACK_DATA Data,
    __in PCFLT_RELATED_OBJECTS FltObjects,
    __in_opt PVOID CompletionContext,
    __in FLT_POST_OPERATION_FLAGS Flags
    )
{
  

    ULONG nextOffset = 0;
	static wchar_t szFilePath[PAGE_SIZE] = {0};
	int modified = 0;
	int removedAllEntries = 1;  
	wchar_t *fullPathLongName = NULL;
	UNICODE_STRING strFilePathName;  
	wchar_t* pFileName = NULL;  

   
	PFLT_FILE_NAME_INFORMATION nameInfo;
	PFILE_ID_BOTH_DIR_INFORMATION currentFileInfo = 0;
	PFILE_ID_BOTH_DIR_INFORMATION nextFileInfo = 0;
	PFILE_ID_BOTH_DIR_INFORMATION previousFileInfo = 0;
	PHIDE_PATH_LIST pthName;
    
    UNREFERENCED_PARAMETER( FltObjects );
    UNREFERENCED_PARAMETER( CompletionContext );
	UNREFERENCED_PARAMETER( Data );
    UNREFERENCED_PARAMETER( Flags );

	 if( FlagOn( Flags, FLTFL_POST_OPERATION_DRAINING ) )
    {
		/************************************************************************/
		/*   如果Flags位FLTFL_POST_OPERATION_DRAINING,禁止执行普通的结束操作,则返回值必须是    
		FLT_POSTOP_FINISHED_PROCESSING        */
		/************************************************************************/
        return FLT_POSTOP_FINISHED_PROCESSING;
    }
    //目录查询请求,消息类型因文件系统而异
    if( Data->Iopb->MinorFunction == IRP_MN_QUERY_DIRECTORY && 
        Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass == FileIdBothDirectoryInformation  &&
        Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length > 0 &&
        NT_SUCCESS(Data->IoStatus.Status) )
    {
		NTSTATUS status = FltGetFileNameInformation(Data,FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP ,&nameInfo);
		if (!NT_SUCCESS(status)) goto LAST_CODE;

		status = FltParseFileNameInformation(nameInfo);
		if (!NT_SUCCESS(status)) goto LAST_CODE;

		fullPathLongName = ExAllocatePoolWithTag(NonPagedPool , PAGE_SIZE,HIDE_TAG);
		if(fullPathLongName == NULL) goto LAST_CODE;
		RtlZeroMemory(fullPathLongName , PAGE_SIZE);
		RtlCopyMemory(fullPathLongName , nameInfo->Name.Buffer , nameInfo->Name.Length);
		RtlInitUnicodeString(&strFilePathName , fullPathLongName);
		if (strFilePathName.Buffer[strFilePathName.Length / sizeof(wchar_t) - sizeof(char)] != '\\')
		{
			strFilePathName.Buffer[strFilePathName.Length / sizeof(wchar_t)] = '\\' ;
		}
		FltReleaseFileNameInformation(nameInfo);

		if (Data->Iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress != NULL)
		{
			currentFileInfo=(PFILE_BOTH_DIR_INFORMATION)MmGetSystemAddressForMdlSafe( 
				Data->Iopb->Parameters.DirectoryControl.QueryDirectory.MdlAddress,
				NormalPagePriority );            
		}
		else
		{
			 currentFileInfo = (PFILE_ID_BOTH_DIR_INFORMATION)Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer;
		}

		if(currentFileInfo==NULL) goto LAST_CODE ;  

		previousFileInfo = currentFileInfo;//保存下来
            
do{

            nextOffset = currentFileInfo->NextEntryOffset;//距离下一个节点的偏移量
            nextFileInfo = (PFILE_ID_BOTH_DIR_INFORMATION)((PCHAR)(currentFileInfo) + nextOffset);//下一个节点

			//文件名    
			pFileName = (wchar_t *)ExAllocatePoolWithTag(NonPagedPool, currentFileInfo->FileNameLength + sizeof(wchar_t),HIDE_TAG);  
			
			if (pFileName == NULL)break;  
			RtlZeroMemory(pFileName, currentFileInfo->FileNameLength + sizeof(wchar_t));  
			RtlCopyMemory(pFileName, currentFileInfo->FileName, currentFileInfo->FileNameLength);

			RtlStringCbPrintfExW(szFilePath, sizeof(wchar_t)*PAGE_SIZE, NULL, NULL, STRSAFE_FILL_BEHIND_NULL, L"%s%s", fullPathLongName, pFileName);  

		//只需要把磁盘中原有的传入即可,用户输入的在匹配函数中获取,对比用户输入与磁盘上的文件
			if(SearchIsProtect(szFilePath))
			{
				KdPrint(("找到了要隐藏的文件 ! \n"));
				
				//判断是不是最后一个节点
                if( nextOffset == 0 )
                {
                    previousFileInfo->NextEntryOffset = 0;
					KdPrint((" %S 是最后一个节点 \n",currentFileInfo->FileName));
                }
                else
                { 
					KdPrint(("%S 不是最后一个节点,即将去除这个节点 \n",currentFileInfo->FileName));
                    previousFileInfo->NextEntryOffset = (ULONG)((PCHAR)currentFileInfo - (PCHAR)previousFileInfo) + nextOffset;
                }
				modified = 1;
            }
			
            else
            {
				removedAllEntries = 0;
				KdPrint(("没有找到  ! \n"));
               previousFileInfo= currentFileInfo ;
			}
			currentFileInfo = nextFileInfo;

			if (pFileName != NULL)
			{
				ExFreePool(pFileName);	
			}

}while(nextOffset != 0);
	}

	
LAST_CODE:

		if( modified )
		{
			if( removedAllEntries )
			{
				Data->IoStatus.Status = STATUS_NO_MORE_FILES;
			}
			else
			{
				FltSetCallbackDataDirty( Data );
			}
		}   

		if (fullPathLongName)
		{
			ExFreePool(fullPathLongName);
		}

		DbgPrint(" Leave PostMHideFile()\n");


		return FLT_POSTOP_FINISHED_PROCESSING;
}

当然在驱动层还有NT路径转为DOS路径的代码,会在下面的附件里面加上


接下来是应用层的代码,用QT写的,传给驱动层要隐藏的文件

void HideApp::noticeDriver(QStringList strList){
	HANDLE hFsFilter=INVALID_HANDLE_VALUE;
	DWORD dwRet=0;
	BOOL bControlRet=0;
	int i=0;
	INPUT_BUFFER input;
	int num=strList.size();  //pWhitePathList结构中的num
	WritePathBuf *pWhitePathList;
	DWORD length = sizeof(WritePathBuf) + (num-1) * sizeof(WritePathInfo);
	pWhitePathList = (WritePathBuf *)malloc(length);
	memset(pWhitePathList, 0, length);
	pWhitePathList->iWritePathCount = num;

	//////////////////////////////QString to Wchar///////////////////////////////////////////////////////////////////
	int index=0;
	for(QStringList::Iterator it=strList.begin();it!=strList.end();it++)
	{
		TCHAR szDir[260]={0};/////坑爹的 没初始化竟导致循环赋值字符串发生截断
		TCHAR szDosName[3]={0};														//类似C:
		TCHAR szDeviceName[MAX_VOLNAME_SIZE]={0};				//设备连接名称
		TCHAR szDevicePath[MAX_FILE_LEN]={0};
		

		(*it).replace("/","\\");      //路径中的斜杠换成反斜杠
		 qDebug()<<*it;
		((*it).trimmed()).toWCharArray(szDir);    //QString to wchar* array
		wcsncpy_s(szDosName,szDir,2);  //2个字符
		QueryDosDevice(szDosName, szDeviceName, MAX_VOLNAME_SIZE);
		wcscpy_s(szDevicePath,szDeviceName);
		wcscat_s(szDevicePath,(szDir+2));

		wcscpy_s(pWhitePathList->writePath[index].wzWritePath, MAX_FILE_LEN, szDevicePath); //白名单复制到pWhitePathList结构
		index++;
	}

	/////////////////////////////////////////////////////////通知驱动/////////////////////////////////////////////////////
	//打开内核控制设备 
	DWORD result;
	//TCHAR sz[260] ={0};
	ZeroMemory(&input, sizeof(INPUT_BUFFER));

	input.command = ADD_HIDE_PATH;
	for (i ; i < num ;i++)
	{
		printf("%S \n",pWhitePathList->writePath[i].wzWritePath);
		wcscpy(input.hidePath,pWhitePathList->writePath[i].wzWritePath);

		//发送 ADD_HIDE_PATH命令,准备和驱动层进行通信
		FilterSendMessage(g_hPort,
			&input,
			sizeof(INPUT_BUFFER),
			NULL,
			0,
			&result);	
	}
}

传给驱动层要显示的文件

void myTable::showPath(int row ,int colum){

	QString s = mytableWidget->item(row,colum)->text();


	QString SHOW2 = mytableWidget->item(row,colum+2)->text();
	if (SHOW2 == "显示")
	{
		mytableWidget->item(row,colum+1)->setText("隐藏");
	} 
	

	TCHAR szDir[260]={0};/////坑爹的 没初始化竟导致循环赋值字符串发生截断
	TCHAR szDosName[3]={0};														//类似C:
	TCHAR szDeviceName[MAX_VOLNAME_SIZE]={0};				//设备连接名称
	TCHAR szDevicePath[MAX_FILE_LEN]={0};
	INPUT_BUFFER input;

	s.replace("/","\\");      //路径中的斜杠换成反斜杠
	qDebug()<<s;
	((s).trimmed()).toWCharArray(szDir);    //QString to wchar* array
	wcsncpy_s(szDosName,szDir,2);  //2个字符
	QueryDosDevice(szDosName, szDeviceName, MAX_VOLNAME_SIZE);
	wcscpy_s(szDevicePath,szDeviceName);
	wcscat_s(szDevicePath,(szDir+2));
	printf("%S \n",szDevicePath);
	//打开内核控制设备 
	DWORD result;
	ZeroMemory(&input, sizeof(INPUT_BUFFER));

	input.command = SHOW_HIDE_PATH;

	wcscpy(input.hidePath,szDevicePath);

	//发送 SHOW_HIDE_PATH命令,准备和驱动层进行通信
	FilterSendMessage(g_hPort,
		&input,
		sizeof(INPUT_BUFFER),
		NULL,
		0,
		&result);
}

编译驱动文件



测试前的准备及显示



测试后的显示



打开一个新的资源管理器看能不能找到被隐藏的Windows文件夹




驱动文件及驱动的源码在附件中,



生成的应用层的exe比较大(QT的依赖包比较大),大于规定的8M了,我放到了百度网盘上了,

链接:https://pan.baidu.com/s/1TrKiGXZ4IFgZWYq5qPimfQ 

密码:azgx,

有需要的可以下载(只有应用层的程序,没有放应用层的源码, 驱动的源码和应用层的源码我放到CSDN上了 )


当然驱动文件都有啦,应用层可以自己写的啦!


驱动的源码和应用层的源码我放到CSDN上了

https://download.csdn.net/download/feixi7358/10363410 中

附件中的所有可执行程序要以管理员权限打开才行


[课程]Android-CTF解题方法汇总!

最后于 2019-2-2 10:12 被admin编辑 ,原因: 图片本地化
上传的附件:
收藏
免费 3
支持
分享
最新回复 (22)
雪    币: 7
活跃值: (185)
能力值: ( LV3,RANK:25 )
在线值:
发帖
回帖
粉丝
2
巧了,我前段时间也刚学这个
2018-4-20 19:35
0
雪    币: 307
活跃值: (60)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
某字哮天 巧了,我前段时间也刚学这个
我以前弄得,今天才想起来发个帖
2018-4-20 19:48
0
雪    币: 407
活跃值: (1746)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
大手子那个BUG你还没改呀

2018-4-20 23:26
0
雪    币: 238
活跃值: (40)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
win  10系统无效
2018-4-21 20:30
0
雪    币: 1604
活跃值: (640)
能力值: ( LV13,RANK:460 )
在线值:
发帖
回帖
粉丝
6
武装的蔷薇 win 10系统无效
因为许多内核  API  的用法、数据结构的定义发生了变化,而且无法挫败驱动器的离线取证分析
最后于 2018-4-21 22:26 被shayi编辑 ,原因:
2018-4-21 22:25
0
雪    币: 6818
活跃值: (153)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
2018-4-21 23:27
0
雪    币: 5511
活跃值: (2072)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
感谢分享!删除工程的临时文件,重新上传一份
最后于 2018-4-22 00:26 被wanttobeno编辑 ,原因:
上传的附件:
2018-4-22 00:26
0
雪    币: 307
活跃值: (60)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
9
Thead 大手子那个BUG你还没改呀
你这个我还不清楚怎么回事隐藏不了,我也测了好多次,对你写的这个程序不起作用
2018-4-22 10:39
0
雪    币: 307
活跃值: (60)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10
wanttobeno 感谢分享!删除工程的临时文件,重新上传一份
我也是在网上找的资料,网上有根据文件名(把文件名写死在代码中)来进行隐藏的,我只是修改了一些,还是前人的功劳
2018-4-22 10:41
0
雪    币: 407
活跃值: (1746)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
我在Tesla.Angela论坛里发过源码的,也是用minifilter写的隐藏文件的,可以随便下载,你下载下来瞄哈就知道了。我比较懒代码没写完,但是效果杠杠滴。

2018-4-22 12:24
0
雪    币: 8865
活跃值: (2379)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
12
看到miniflt突然想说:
https://github.com/JKornev/hidden  了解一下
2018-4-22 12:35
1
雪    币: 20
活跃值: (26)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
Thead 我在Tesla.Angela论坛里发过源码的,也是用minifilter写的隐藏文件的,可以随便下载,你下载下来瞄哈就知道了。我比较懒代码没写完,但是效果杠杠滴。
能传看雪吗?
2018-4-22 22:10
0
雪    币: 206
活跃值: (2559)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
14
cvcvxk 看到miniflt突然想说: https://github.com/JKornev/hidden 了解一下
一针见血  哈哈哈
2018-4-23 00:09
0
雪    币: 407
活跃值: (1746)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
wx_咖啡_552099 能传看雪吗?
传了
2018-4-23 08:58
0
雪    币: 199
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
谁能教下我怎么用  ~    有偿  留下你的联系方式~
2018-4-30 04:30
0
雪    币: 199
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
冰栈 你这个我还不清楚怎么回事隐藏不了,我也测了好多次,对你写的这个程序不起作用
大佬教教怎么用  有偿~  你的联系方式多少
2018-4-30 04:32
0
雪    币: 307
活跃值: (60)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
18
Nning 谁能教下我怎么用 ~ 有偿 留下你的联系方式~
我在csdn上的介绍里写的很清楚了呀!    https://download.csdn.net/download/feixi7358/10363410      你可以看看,我这个用系统自带的资源管理器是看不见的,但是做的还不行,以后再改。
2018-4-30 15:24
0
雪    币: 199
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
冰栈 我在csdn上的介绍里写的很清楚了呀! https://download.csdn.net/download/feixi7358/10363410 你可以看看,我这个用系统自带的资源管理器是看不 ...
我下载了    不会用~    能加下我  扣  1105613909  吗
2018-4-30 23:13
0
雪    币: 174
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
WIN7  32下成功,  XP  SP3后操作中不会进入FileIdBothDirectoryInformation的if分支,哪位大佬知道原因?
2018-6-7 16:00
0
雪    币: 307
活跃值: (60)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
21
Goldtulip WIN7 32下成功, XP SP3后操作中不会进入FileIdBothDirectoryInformation的if分支,哪位大佬知道原因?
试试      FileBothDirectoryInformation
2018-6-7 18:44
0
雪    币: 174
活跃值: (62)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
冰栈 试试 FileBothDirectoryInformation
正解!
2018-6-8 14:35
0
雪    币: 24
活跃值: (27)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
这个几年前我也做过,  给你加一个  CMD  里隐藏是  FileFullDirectoryInformation 
2018-6-8 15:47
0
游客
登录 | 注册 方可回帖
返回
//