强删文件,强杀进程,文件注册表穿越

本公众号分享的所有技术仅用于学习交流,请勿用于其他非法活动,如有错漏,欢迎留言交流指正

《Windows NT File System Iternals》 文件加解密必备

《Windows驱动开发技术详解》张帆 电子工业出版社 很基础,仅仅适合入门
《Windows 2000设备驱动程序设计智能》 Art Baker等主 机械工业出版社
《寒江独钓:Windows内核安全编程》 邵坚磊等著 电子工业出版社
《Windows内核原理与实现》潘爱民

强删,强杀,穿越

强制删除文件

  • 安全软件用强删清除病毒木马
  • 病毒木马也可以用强删来删除系统保护文件或是受杀软保护的文件。

内核层实现强删文件

强删文件思路
  1. 打开文件
  • 删除文件首先要打开文件,得到文件的句柄,打开文件一般是调用ZwCreateFile
  • 通过在windbg看到应用层到内核层的调用栈,可以发现ZwCreateFile->NtCreateFile函数底层调用的就是IoCreateFile
  • NTCreteFile很容易就被HOOK(SSDT HOOK),而IoCreateFile更底层,对它的HOOK难度更大一些,更可靠一些,所以强删文件这里使用IoCreateFile来打开文件。
  1. 解锁

a. 只读

  • 文件或文件夹包含三种属性:
    • 1.只读:只读属性是不允许修改的文件。若将文件或文件夹设置为只读属性,则该文件或文件夹不允许更改。在应用层是可以删除的。,在内核层则无法删除
    • 2.隐藏:隐藏的文件是看不见的。若将文件或文件夹设置为隐藏属性,则该文件或文件夹在常规显示中将不被看到;
    • 3.存档:一般的文件的属性是存档的。若将文件或文件夹设置为存档属性,则表示该文件或文件夹已存档,有些程序用此选项来确定哪些文件需做备份
  • 解决方法:
    • 抹除只读权限后再删除
    • @todo 失败

b.被其它程序独占

  • 无法删除的原因:
    • 正常情况下,一个文件被别的进程独占打开时,我们是无法打开该文件的,从而得不到该文件的句柄,自然就删除不了该文件。
  • 解决方法:
    • 调用ZwQuerySystemInfomation 查询全局句柄表,找到要删除的文件句柄和打开该文件的进程
    • 调用ZwDuplicateObject(导出但未文档化的函数,现在可以调用它,但未来可能会失效)把句柄从独占它的进程空间中拷贝过来,同时把这个句柄从目标进程中关闭掉(函数传参传入这个参数DUPLICATE_CLOSE_SOURCE)。从而独占失效,就可以拿到该文件的句柄,将其删除。
  • 这是市面上大多数解锁程序用的技术。但也有局限性,对硬链接没有效果。
    • 硬链接:mklink /h link.txt gb.txt link.txt是对gb.txt的一个alias,链接计数(删除减一)。
    • 当gb.txt被独占了,打不开,link.txt也被独占了,也打不开,此时如果用关句柄的方法去强删link.txt,无法删除,因为硬链接link.txt在句柄表中根本不存在。
    • 硬连接是不能跨卷的(即在C盘中的文件不能在D盘中创建一个硬链接),只有在同一文件系统中的文件之间才能创建链接。
    • 软链接(也叫符号链接)与硬链接不同,文件中存放的内容是另—文件的路径名的指向
    • 软链接就是普通文件,只是数据块内容有点特殊。删除软链接并不影响被指向的文件,若被指向的原文件件被删除,则相关软连接就变成了死链接

c.正在运行.exe

  • 无法删除的原因:(反汇编逆向分析ZwDeleteFile或者ZwSetinformationFile,或者直接看之前泄漏的winxp微软源代码)
    • 上层调用ZwDeleteFile或者ZwSetinformationFile删除文件的时候最终会执行这个函数NtfsSetDispositionlnfo最终会调用MmFlushImageSection
    • 然后在MmFlushImageSection函数内,操作系统会检查要删除文件对象SectionObjectPointer中的成员ImageSectionObjectDataSectionObject是否为0,如果不为0,则认为该文件是正在运行的.exe,拒绝删除
pSectionObjectPointer = fileObject->SectionObjectPointer;
psectionObjectPointer->ImageSectionObject = 0;
pSectionObjectPointer->DataSectionObject = 0;
  • 解决方式
    • 可以提前把 ImageSectionObjectDataSectionObject设为0,欺骗操作系统。
  1. 构建IRP删除文件
    • 一般情况下,在删除文件的时候是调用ZwDeleteFile或者ZwSetinformationFile来删除文件
    • 但有时候基于这些函数对文件的操作已经不可靠了(调用的这些函数已经被病毒或者木马篡改了,当函数被Hook之后,删除病毒和木马,病毒和密木马自我保护,会把删除请求拒绝)。
    • 这时候需要我们自己构建一个专门用来删除文件的Irp来删除文件。
实战

#include <ntddk.h>
#include <ntimage.h>
#include <ntdef.h>
#include "DelFile.h"


PDEVICE_OBJECT	g_HookDevice;

NTSTATUS dfQuerySymbolicLink(
	IN PUNICODE_STRING SymbolicLinkName,
	OUT PUNICODE_STRING LinkTarget
	)                                  
{
	OBJECT_ATTRIBUTES oa;
	NTSTATUS status;
	HANDLE handle;
   
	InitializeObjectAttributes(
		&oa, 
		SymbolicLinkName,
		OBJ_CASE_INSENSITIVE,
		0, 
		0);
   
	status = ZwOpenSymbolicLinkObject(&handle, GENERIC_READ, &oa);
	if (!NT_SUCCESS(status))
	{
		return status;
	}
   
	LinkTarget->MaximumLength = 1024*sizeof(WCHAR);
	LinkTarget->Length = 0;
	LinkTarget->Buffer = ExAllocatePoolWithTag(PagedPool, LinkTarget->MaximumLength, 'A0');
	if (!LinkTarget->Buffer)
	{
		ZwClose(handle);
		return STATUS_INSUFFICIENT_RESOURCES;
	}

	RtlZeroMemory(LinkTarget->Buffer, LinkTarget->MaximumLength);
   
	status = ZwQuerySymbolicLinkObject(handle, LinkTarget, NULL);
	ZwClose(handle);
   
	if (!NT_SUCCESS(status))
	{
		ExFreePool(LinkTarget->Buffer);
	}
   
	return status;
}

BOOLEAN dfCloseFileHandle(WCHAR *name)
{
	
	NTSTATUS					 status;
	PVOID						 buf   = NULL;
	PSYSTEM_HANDLE_INFORMATION 	 pSysHandleInfo;
	SYSTEM_HANDLE_TABLE_ENTRY_INFO handleTEI;

	ULONG						size  = 1;
	ULONG						NumOfHandle = 0;
	ULONG						i;
	CLIENT_ID 					cid;
	HANDLE						hHandle;
	HANDLE						hProcess;
	HANDLE 						hDupObj;
	HANDLE						hFile;
	HANDLE						link_handle;
	OBJECT_ATTRIBUTES 			oa;
	ULONG						FileType; 
	ULONG						processID;
	UNICODE_STRING 				uLinkName;
	UNICODE_STRING				uLink;
	OBJECT_ATTRIBUTES 			objectAttributes;
	IO_STATUS_BLOCK 		 	IoStatus;
	ULONG 						ulRet;
	PVOID    			 		fileObject;
	POBJECT_NAME_INFORMATION 	pObjName = {0};
	UNICODE_STRING				delFileName = {0};
	int							length;
	WCHAR						wVolumeLetter[3];
	WCHAR						*pFilePath;
	UNICODE_STRING				uVolume;
	UNICODE_STRING				uFilePath;
	UNICODE_STRING 				NullString = RTL_CONSTANT_STRING(L"");
	BOOLEAN					bRet = FALSE;


	for ( size = 1; ; size *= 2 ) //句柄表是动态变化的,所以不知道多大的buffer存放合适,从1B开始 指数增长
	{
		if ( NULL == ( buf = ExAllocatePoolWithTag(NonPagedPool,size, 'FILE') ) )
		{
			DbgPrint(("alloc mem failed\n"));
			goto Exit;
		}
		RtlZeroMemory( buf ,size );
		status = ZwQuerySystemInformation( SystemHandleInformation, buf, size, NULL ); //不像ZwEnumerateValueKey函数把参数传NULL就返回buffer的实际大小,所以就需要调整buffer的大小
		if ( !NT_SUCCESS( status ) )
		{
			if ( STATUS_INFO_LENGTH_MISMATCH == status ) //这样写是为了在编译阶段发现status = STATUS_INFO_LENGTH_MISMATCH的错误
			{
				ExFreePool( buf );
				buf = NULL;
			}
			else
			{
				DbgPrint(( "ZwQuerySystemInformation() failed"));
				goto Exit;
			}
		}
		else
		{
			break; //直到buffer能存放全局句柄表退出循环
		}
	}

	pSysHandleInfo = (PSYSTEM_HANDLE_INFORMATION)buf; 
	NumOfHandle = pSysHandleInfo->NumberOfHandles; //句柄个数

	
	//句柄表只有handle和打开这个句柄的进程的PID,所以需要把句柄转换成具体的文件名,
	//而且转换过来的这个文件名是\device\harddiskvolume3\haha.doc这种格式的,但删除文件的文件名硬编码成这种格式"\??\c:\haha.doc",所以还需要转换一下格式
	/* Get the volume character like C: */
	//\??\c:\haha.doc-->\device\harddiskvolume3\haha.doc

	wVolumeLetter[0] = name[4];
	wVolumeLetter[1] = name[5];
	wVolumeLetter[2] = 0;
	uLinkName.Buffer = ExAllocatePoolWithTag(NonPagedPool, 256 + sizeof(ULONG), 'A1');
	uLinkName.MaximumLength = 256;
	RtlInitUnicodeString(&uVolume, wVolumeLetter);
	RtlInitUnicodeString( &uLink, L"\\DosDevices\\");
	RtlCopyUnicodeString(&uLinkName, &uLink);
	
	status = RtlAppendUnicodeStringToString(&uLinkName, &uVolume);
	if (!NT_SUCCESS(status))
	{
		KdPrint(("RtlAppendUnicodeStringToString() failed"));
		return FALSE;
	}
	
	dfQuerySymbolicLink(&uLinkName, &delFileName);
	RtlFreeUnicodeString(&uLinkName);
	KdPrint(("delFileName:%wZ", &delFileName));

	pFilePath = (WCHAR *) &name[6];
	RtlInitUnicodeString( &uFilePath, pFilePath);

	RtlAppendUnicodeStringToString(&delFileName, &uFilePath);
	if (!NT_SUCCESS(status))
	{
		KdPrint(("RtlAppendUnicodeStringToString() failed"));
		return FALSE;
	}

	KdPrint(("delFile:%wZ", &delFileName));

	for(i = 0; i < NumOfHandle ;i++) //遍历全局句柄表
	{
		handleTEI = pSysHandleInfo->Handles[i];
		if (handleTEI.ObjectTypeIndex != 25 && handleTEI.ObjectTypeIndex != 28)//28文件,25设备对象
			continue;
		processID = (ULONG) handleTEI.UniqueProcessId; //打开该句柄的进程PID
		cid.UniqueProcess = (HANDLE)processID;
		cid.UniqueThread = (HANDLE)0;
		hHandle = (HANDLE)handleTEI.HandleValue;
		InitializeObjectAttributes( &oa ,NULL ,0 ,NULL ,NULL );
		status = ZwOpenProcess( &hProcess ,PROCESS_DUP_HANDLE ,&oa ,&cid ); //打开打开该句柄的进程,目的是把目标进程的句柄拷贝到当前进程中来,因为句柄不跨进程只在同一个进程有效,如果把句柄传给另一个进程,它是无效的,只能通过目标进程来访问该句柄
		if ( !NT_SUCCESS( status ) )
		{
			KdPrint(( "ZwOpenProcess:%d Fail ", processID));
			continue;
		}

		status = ZwDuplicateObject( hProcess ,hHandle ,NtCurrentProcess() ,&hDupObj ,\
		 PROCESS_ALL_ACCESS ,0 ,DUPLICATE_SAME_ACCESS ); //第一次拷贝,把句柄从`独占`它的进程空间中`拷贝`过来
		if ( !NT_SUCCESS( status ) )
		{
			DbgPrint(( "ZwDuplicateObject1 : Fail " ));
			continue;
		}
		status = ObReferenceObjectByHandle( //根据句柄得到文件的内核对象
			  hDupObj,
			  FILE_ANY_ACCESS,
			  0,
			  KernelMode,
			  &fileObject,
			  NULL);
		
		if (!NT_SUCCESS(status))
		{
			DbgPrint(( "ObReferenceObjectByHandle : Fail " ));
			continue;
		}  

		pObjName = (POBJECT_NAME_INFORMATION) ExAllocatePoolWithTag(NonPagedPool, \
			sizeof (OBJECT_NAME_INFORMATION) + 1024 * sizeof (WCHAR), 'A1');

		if (STATUS_SUCCESS != (status = ObQueryNameString(fileObject, pObjName, \
			sizeof (OBJECT_NAME_INFORMATION) + 1024 * sizeof (WCHAR), &ulRet))) //查询文件内核对象对应的文件名
		{
		   ObDereferenceObject(fileObject);
		   continue;
		}
		if (RtlCompareUnicodeString(&pObjName->Name, &delFileName, TRUE) == 0) //相等,则是要找被独占的强删的文件
		{

			ObDereferenceObject(fileObject);
			ZwClose(hDupObj);

			status = ZwDuplicateObject( hProcess ,hHandle ,NtCurrentProcess() ,&hDupObj ,\
			 PROCESS_ALL_ACCESS ,0 ,DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE ); //第二次拷贝,把句柄从`独占`它的进程空间中`拷贝`过来,同时把这个句柄从目标进程中`关闭掉`(函数传参传入这个参数`DUPLICATE_CLOSE_SOURCE`)
			if ( !NT_SUCCESS( status ) )
			{
				DbgPrint(( "ZwDuplicateObject2 : Fail " ));
				//return FALSE;
			}
			else
			{
				ZwClose(hDupObj);
				bRet = TRUE;
				//return TRUE;
			}
			break;

		}
			
		ExFreePool(pObjName);
		pObjName = NULL;

		ObDereferenceObject(fileObject);
		ZwClose( hDupObj );
		ZwClose( hProcess );

	}

Exit:
	if (pObjName != NULL)
	{
		ExFreePool(pObjName);
		pObjName = NULL;
	}
	if (delFileName.Buffer != NULL)
	{
		ExFreePool(delFileName.Buffer);	
	}
	if ( buf != NULL )
	{
		ExFreePool( buf );
		buf = NULL;
	}
	return(bRet);

}

NTSTATUS
dfOpenFile(WCHAR* name,PHANDLE phFileHandle, ACCESS_MASK access,ULONG share)
{

   IO_STATUS_BLOCK iosb;
   NTSTATUS stat;
   OBJECT_ATTRIBUTES oba;
   UNICODE_STRING nameus;

   if(KeGetCurrentIrql()>PASSIVE_LEVEL){return 0;}
   RtlInitUnicodeString(&nameus,name);
   InitializeObjectAttributes(
		&oba,
		&nameus,
		OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE,
		0,
		0);
   stat=IoCreateFile(
		phFileHandle,
		access,
		&oba,
		&iosb,
		0,
		FILE_ATTRIBUTE_NORMAL,
		share,
		FILE_OPEN,
		0,
		NULL,
		0,
		0,
		NULL,
		IO_NO_PARAMETER_CHECKING); //不要进行参数校验,IoCreateFile才会调用成功

	return stat;
}

NTSTATUS
dfSkillSetFileCompletion(
	IN PDEVICE_OBJECT DeviceObject,
	IN PIRP Irp,
	IN PVOID Context
	)
{
	Irp->UserIosb->Status = Irp->IoStatus.Status;
	Irp->UserIosb->Information = Irp->IoStatus.Information;

	KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);

	IoFreeIrp(Irp);

	return STATUS_MORE_PROCESSING_REQUIRED;
}
BOOLEAN dfDelFile(WCHAR* name)
{
	NTSTATUS        ntStatus = STATUS_SUCCESS;
	PFILE_OBJECT    fileObject;
	PDEVICE_OBJECT  DeviceObject;
	PIRP            Irp;
	KEVENT          event;
	FILE_DISPOSITION_INFORMATION  FileInformation;
	IO_STATUS_BLOCK ioStatus;
	PIO_STACK_LOCATION irpSp;
	PSECTION_OBJECT_POINTERS pSectionObjectPointer;
	HANDLE handle;
	OBJECT_ATTRIBUTES                	objAttributes = { 0 };
	InitializeObjectAttributes(&objAttributes,
		&name,
		OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
		NULL,
		NULL);
	/// 1.打开文件
	ntStatus = dfOpenFile(name, &handle, FILE_READ_ATTRIBUTES|DELETE,FILE_SHARE_DELETE);
	DbgPrint("dfOpenFile(%ws) failed(%x)\n", &name, ntStatus);
	if (ntStatus == STATUS_OBJECT_NAME_NOT_FOUND || //传的名字错了或者路径错了
		ntStatus == STATUS_OBJECT_PATH_NOT_FOUND )
	{
		DbgPrint("No such file",ntStatus);
		return FALSE;
	}
	else if (!NT_SUCCESS(ntStatus))
	{
		/// 2.a抹除文件的只读属性
		//ntStatus = dfOpenFile(name, &handle, FILE_READ_ATTRIBUTES, FILE_SHARE_DELETE);
		ntStatus = ZwCreateFile(
			&handle,
			SYNCHRONIZE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, 
			&objAttributes,
			&ioStatus,
			NULL,
			FILE_ATTRIBUTE_NORMAL,
			FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
			FILE_OPEN,
			FILE_SYNCHRONOUS_IO_NONALERT,
			NULL,
			0);
		if (NT_SUCCESS(ntStatus))
		{
			FILE_BASIC_INFORMATION        basicInfo = { 0 };

			ntStatus = ZwQueryInformationFile(handle, &ioStatus,
				&basicInfo, sizeof(basicInfo), FileBasicInformation); //把文件的基本属性读出来
			if (!NT_SUCCESS(ntStatus))
			{
				DbgPrint("ZwQueryInformationFile(%ws) failed(%x)\n", &name, ntStatus);
			}

			basicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL; //改成normal
			ntStatus = ZwSetInformationFile(handle, &ioStatus,
				&basicInfo, sizeof(basicInfo), FileBasicInformation); //把修改后的属性在写回去
			if (!NT_SUCCESS(ntStatus))
			{
				DbgPrint("ZwSetInformationFile(%ws) failed(%x)\n", &name, ntStatus);
			}
		}
		/// 2.b 遍历全局句柄表,关闭独占打开的句柄
		if (dfCloseFileHandle(name))
		{
			ntStatus = dfOpenFile(name, &handle, FILE_READ_ATTRIBUTES|DELETE,FILE_SHARE_DELETE); //再次打开文件,就会得到文件的句柄
			if (!NT_SUCCESS(ntStatus))
				return FALSE;
		}
		else
		{
			return FALSE;
		}
	}

	ntStatus = ObReferenceObjectByHandle(handle, //根据句柄拿到内核对象,因为句柄不跨进程只在同一个进程有效,如果把句柄传给另一个进程,它是无效的。所以一般是拿到handle之后直接得到它的`fileobject`
		DELETE,
		*IoFileObjectType, //如果没有指定一个句柄的类型,攻击者可以传入非文件类型的句柄从而造成系统漏洞,得到其他类型的内核对象,对应的结构体的定义里很可能没有一些成员,就会行为未定义或者无效内存,下面如果访问这些缺少的成员,系统会崩溃,造成蓝屏。
		KernelMode,
		&fileObject,
		NULL);

	if (!NT_SUCCESS(ntStatus))
	{
		DbgPrint("ObReferenceObjectByHandle()");
		ZwClose(handle);
		return FALSE;
	}  

	DeviceObject = IoGetRelatedDeviceObject(fileObject); //通过fileObject拿到文件所在的设备对象,用来接受Irp
	/// 3. 构建IRP删除文件
	Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE); 

	if (Irp == NULL)
	{
		ObDereferenceObject(fileObject);
		ZwClose(handle);
		return FALSE;
	}

	KeInitializeEvent(&event, SynchronizationEvent, FALSE); //初始化事件,synchronization事件:自动恢复,比如声控灯。FALSE表示最初为无信号状态
   
	FileInformation.DeleteFile = TRUE; 

	Irp->AssociatedIrp.SystemBuffer = &FileInformation; 
	Irp->UserEvent = &event;
	Irp->UserIosb = &ioStatus;
	Irp->Tail.Overlay.OriginalFileObject = fileObject;
	Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
	Irp->RequestorMode = KernelMode;
   
	irpSp = IoGetNextIrpStackLocation(Irp);
	irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
	irpSp->DeviceObject = DeviceObject;
	irpSp->FileObject = fileObject;
	irpSp->Parameters.SetFile.Length = sizeof(FILE_DISPOSITION_INFORMATION);
	irpSp->Parameters.SetFile.FileInformationClass = FileDispositionInformation;
	irpSp->Parameters.SetFile.FileObject = fileObject;

	/// 为当前IRP设置一个完成例程,相当于回调函数,当下层驱动将Irp结束之后就会调用这个完成例程
	IoSetCompletionRoutine(
			Irp,
			dfSkillSetFileCompletion, //完成例程,在完成例程里面设置事件,通过这个事件通知上层驱动,上层驱动才知道Irp完成了,并且知道Irp的完成状态
			&event,
			TRUE,
			TRUE,
			TRUE);
			
	/// 2.b 删除正在运行中的exe所做的处理,欺骗操作系统
	pSectionObjectPointer = fileObject->SectionObjectPointer;
	if(pSectionObjectPointer)
	{
		pSectionObjectPointer->ImageSectionObject = 0;
		pSectionObjectPointer->DataSectionObject = 0;
	}
	/// 3. 将Irp往下发
	ntStatus = IoCallDriver(DeviceObject, Irp); 
	if (!NT_SUCCESS(ntStatus))
	{
		 ObDereferenceObject(fileObject);
		 ZwClose(handle);
		 return FALSE;
	}  
	/// 等待完成例程中事件发生,NULL表示无限等待
	KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, NULL);
	//IoFreeIrp(Irp);
	ObDereferenceObject(fileObject);
	ZwClose(handle);
	return TRUE;

}


NTSTATUS OnUnload(IN PDRIVER_OBJECT DriverObject)
{
	UNICODE_STRING          deviceLinkUnicodeString;
	PDEVICE_OBJECT	   p_NextObj;


	DbgPrint("OnUnload called\n");

	p_NextObj = DriverObject->DeviceObject;

	if (p_NextObj != NULL)
	{

		RtlInitUnicodeString( &deviceLinkUnicodeString, deviceLinkBuffer );
		IoDeleteSymbolicLink( &deviceLinkUnicodeString );

		IoDeleteDevice( DriverObject->DeviceObject );
	}
	return STATUS_SUCCESS;
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
	NTSTATUS                ntStatus;
	UNICODE_STRING          deviceNameUnicodeString;
	UNICODE_STRING          deviceLinkUnicodeString;

	RtlInitUnicodeString (&deviceNameUnicodeString,deviceNameBuffer );
	RtlInitUnicodeString (&deviceLinkUnicodeString,deviceLinkBuffer );

	ntStatus = IoCreateDevice ( DriverObject,
		0,
		&deviceNameUnicodeString,
		FILE_DEVICE_SWAP,
		0,
		TRUE,
		&g_HookDevice );

	if(! NT_SUCCESS(ntStatus))
	{
		  DbgPrint(("Failed to create device!\n"));
		  return ntStatus;
	 }

	/* We test the DelFile() function here */	
	if (dfDelFile(L"\\??\\c:\\haha.doc")) //硬编码了两个文件的路径
	{
		KdPrint(("Deleted"));
	}
	else
	{
		KdPrint(("Failed"));
	}
	if (dfDelFile(L"\\??\\c:\\filedelet.exe"))
	{
		KdPrint(("Deleted"));
	}
	else
	{
		KdPrint(("Failed"));
	}

	ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,
		&deviceNameUnicodeString );
	if(! NT_SUCCESS(ntStatus)) 
	{
		 IoDeleteDevice(DriverObject->DeviceObject);
			DbgPrint("Failed to create symbolic link!\n");
			return ntStatus;
	 }

	DriverObject->DriverUnload  = OnUnload;
	return STATUS_SUCCESS;
}

应用层实现强删文件

  • 原理与内核层类似
  • 优点:应用层比内核层稳定
  • 存在问题
    • NtQueryObject会导致某些句柄hang住(死锁),但某些句柄并不是文件句柄
    • 如果句柄传给NtQueryObject会hang住,传给GetFileType(hFile)也会超时
    • 所以只需要把这些句柄过滤掉就可以了
  • 解决办法
    • 新建一个线程,调用GetFileType(hFile),设置一个超时,如果超时了,就把该句柄排除掉。
#include "avCloseAllFileHandles.h"

ZWQUERYSYSTEMINFORMATION		NtQuerySystemInformation = NULL;
ZWQUERYOBJECT					NtQueryObject = NULL;
HMODULE							g_hNtDLL = NULL;

BOOL InitNTDLL()
{
	g_hNtDLL = LoadLibrary( "ntdll.dll" );
	if ( !g_hNtDLL )
	{
		return FALSE;
	}

	NtQuerySystemInformation =
		(ZWQUERYSYSTEMINFORMATION)GetProcAddress( g_hNtDLL, "NtQuerySystemInformation");

	NtQueryObject =
		(ZWQUERYOBJECT)GetProcAddress( g_hNtDLL, "NtQueryObject");

	if (NtQuerySystemInformation == NULL ||
		NtQueryObject == NULL)
	{
		return FALSE;
	}

	return TRUE;
}

VOID CloseNTDLL()
{
	if(g_hNtDLL != NULL)
	{
		FreeLibrary(g_hNtDLL);
	}
}

DWORD WINAPI IsHandleSafe(LPVOID lpParam)
{
	HANDLE hFile = (HANDLE)lpParam;
	GetFileType(hFile);
	return 0;
}

BOOL avCloseHandle(HANDLE Process, HANDLE Handle)
{
	BOOL rtn = FALSE;
	HANDLE h = 0;

	rtn = DuplicateHandle(Process, 
		Handle, 
		GetCurrentProcess( ), 
		&h, 
		0, 
		FALSE, 
		DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);

	if(rtn)
		CloseHandle(h);
	return rtn;
}

NTSTATUS avNtQueryObject(
	IN HANDLE ObjectHandle,
	IN ULONG ObjectInformationClass,
	OUT PVOID ObjectInformation,
	IN ULONG ObjectInformationLength,
	OUT PULONG ReturnLength OPTIONAL,
	IN	ULONG waitTime
	)
{
	DWORD 			dwTid=0;
	HANDLE 			hThread;
	DWORD 			dwEax;
	NTSTATUS		st;
	//创建一个线程判断handle是否安全
	hThread = CreateThread(NULL,0,IsHandleSafe,ObjectHandle,0,&dwTid);
	dwEax = WaitForSingleObject(hThread,waitTime);

	if(dwEax == STATUS_TIMEOUT) //如果超时就不会传给NtQueryObject避免死锁
	{
		DWORD dwTimeOut = 0;

		GetExitCodeThread(hThread, &dwTimeOut);
		TerminateThread(hThread, dwTimeOut);

		CloseHandle(hThread);
		return STATUS_UNSUCCESSFUL;
	} 
	CloseHandle(hThread);
	st = NtQueryObject(ObjectHandle, ObjectInformationClass, ObjectInformation, 
		ObjectInformationLength, ReturnLength);
	return st;

}
//比较文件名
BOOL avMatchRemoteFileByHandle(wchar_t *filename, HANDLE Process, HANDLE Handle)
{
	HANDLE			h = NULL;
	ULONG			ret = 0;
	char			*namebuf = NULL;
	BOOLEAN			bMatched = FALSE;
	NTSTATUS		st;
	wchar_t 		*outstr = NULL;

	if(DuplicateHandle(Process, 
		Handle, 
		GetCurrentProcess( ), 
		&h, 
		0, 
		FALSE, 
		DUPLICATE_SAME_ACCESS))
	{

		avNtQueryObject(h, FileNameInformation, NULL, 0, &ret, 100);
		if (ret == 0)
		{
			ret = MAX_PATH;
		}
		namebuf = new char[ret];
		if (namebuf == NULL)
		{
			DebugPrint("No memory available\n");
			CloseHandle(h);
			return FALSE;
		}
		st = avNtQueryObject(h, FileNameInformation, namebuf, ret, NULL, 100); //查询句柄所对应的文件名
		POBJECT_NAME_INFORMATION name = (POBJECT_NAME_INFORMATION)namebuf;
		if (st >= 0)
		{	
			outstr = new wchar_t[MAX_PATH];
			if (outstr == NULL)
			{
				DebugPrint("No memory available");
				if (namebuf)
				{
					delete []namebuf;
				}
				CloseHandle(h);
				return FALSE;
			}
			memset(outstr, 0, MAX_PATH);
			outstr[0] = L'A';
			outstr[1] = L':';
			if (name->Name.Length > 23 && \
				memicmp(name->Name.Buffer, L"\\Device\\HardDiskVolume", 44) == 0)
			{
				outstr[0] = name->Name.Buffer[22] - L'1' + L'C';
				memcpy(&outstr[2], &name->Name.Buffer[23], name->Name.Length-23*2);
				outstr[name->Name.Length/2-21] = 0;
			}
			/*
			if (name->Name.Length > 23 && \
				_memicmp(name->Name.Buffer, L"\\Device\\HardDiskVolume", 44) == 0)
			{
				//查询,非硬编码
				WCHAR szDiskSymbol[] = L"A:";
				for (WCHAR ch = L'C'; ch <= L'Z'; ch++)
				{
					szDiskSymbol[0] = ch;
					WCHAR szBuf[MAX_PATH] = { 0 };
					QueryDosDeviceW(szDiskSymbol, szBuf, MAX_PATH);
					if (szBuf[22] == name->Name.Buffer[22])
					{
						break;
					}
				}

				outstr[0] = szDiskSymbol[0];
				memcpy(&outstr[2], &name->Name.Buffer[23], name->Name.Length - 23 * 2);
				outstr[name->Name.Length / 2 - 21] = 0;
			}
			*/

			if (wcsncmp(outstr, filename, wcslen(filename)) == 0)
			{
				DebugPrint("Found:%ws\n",filename);
				bMatched = TRUE;
			}
			delete []outstr;
			outstr = NULL;
		}
		if (namebuf)
		{
			delete []namebuf;
		}
		CloseHandle(h);
		return bMatched;
	}

	return FALSE;
}
//获得句柄表
PULONG avGetHandleList()
{
   ULONG 			cbBuffer = 0x1000;
   PULONG 			pBuffer = new ULONG[cbBuffer];
   NTSTATUS 		Status;
   DWORD 			dwNumBytesRet = 0x10;
   do
   {
	   Status = NtQuerySystemInformation(
		   SystemHandleInformation,
		   pBuffer,
		   cbBuffer * sizeof * pBuffer,
		   &dwNumBytesRet);

	   if (Status == STATUS_INFO_LENGTH_MISMATCH)
	   {
		   delete [] pBuffer;
		   pBuffer = new ULONG[cbBuffer *= 2];
	   }
	   else if (!NT_SUCCESS(Status))
	   {
		   delete [] pBuffer;
		   return NULL;
	   }
   } while (Status == STATUS_INFO_LENGTH_MISMATCH);

   return pBuffer;
}

BOOL avCloseAllHandlesForFile(wchar_t *filename)
{
	ULONG							dSize = 0;
	ULONG							dData = 0;
	ULONG							NumOfHandle = 0;
	BOOL							rtn = TRUE;
	ULONG							i;
	PSYSTEM_HANDLE_INFORMATION 		pSysHandleInfo;
	SYSTEM_HANDLE_TABLE_ENTRY_INFO	handleTEI;
	char							*namebuf = NULL;
	char							namenull[1000];
	HANDLE							hTmp;
	UCHAR							TypeNum;
	HANDLE							hProcess;
	BOOLEAN							bClosed = FALSE;
	

	GetModuleFileName(NULL,namenull,MAX_PATH);
	hTmp = CreateFile(namenull,
		GENERIC_READ,
		FILE_SHARE_READ,
		0,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		0);
	if (hTmp == 0)
	{
		return FALSE;
	}

	PULONG buf = avGetHandleList();
	if (buf == NULL)
	{
		CloseHandle(hTmp);
		return FALSE;
	}

	pSysHandleInfo = (PSYSTEM_HANDLE_INFORMATION)buf;
	NumOfHandle = pSysHandleInfo->NumberOfHandles;

	/* We get file object header type  dynamically */
	for (i = 0; i < NumOfHandle ;i++)
	{
		handleTEI = pSysHandleInfo->Handles[i];
		if (GetCurrentProcessId() == handleTEI.UniqueProcessId &&
			handleTEI.HandleValue == (USHORT)hTmp)
				TypeNum = handleTEI.ObjectTypeIndex;
	}
	CloseHandle(hTmp);

	for(i = 0; i < NumOfHandle ;i++)
	{
		handleTEI = pSysHandleInfo->Handles[i];
		if (handleTEI.ObjectTypeIndex != TypeNum)
			continue;

		hProcess = OpenProcess(PROCESS_ALL_ACCESS,
			FALSE,
			handleTEI.UniqueProcessId);
		if(hProcess)
		{
			if(avMatchRemoteFileByHandle(filename, hProcess, (HANDLE)handleTEI.HandleValue)) //比较文件名
			{
				if (avCloseHandle(hProcess, (HANDLE)handleTEI.HandleValue)) 
				{
					DebugPrint("file:%ws handle closed\n", filename);
					bClosed = TRUE;
				}
			}
			CloseHandle(hProcess);
		}
	}
	if (buf)
	{
		delete [] buf;
	}
	return bClosed;
}

//We test the function avCloseAllHandlesForFile() here

int main(int argc, char *argv[])
{

	if (argc < 2)
	{
		DebugPrint("Please run it as: closehandle filename\n");
		exit(1);
	}

	wchar_t filename[MAX_PATH + 1];
	ZeroMemory(filename, MAX_PATH + 1);

	int num = MultiByteToWideChar(CP_OEMCP,MB_PRECOMPOSED,argv[1],
		strlen(argv[1]),filename,MAX_PATH + 1);

	filename[strlen(argv[1])] = L'\0';

	if (!InitNTDLL())
	{
		DebugPrint("%s\n","InitNTDLL() failed");
		exit(1);
	}

	if (avCloseAllHandlesForFile(filename))
	{
		DebugPrint("%s\n", "file handle closed");
	}
	else
	{
		DebugPrint("%s\n", "no file handle closed");
	}

	CloseNTDLL();
	return 0;
} 

强杀进程

内核层强杀进程

  • 思路1: 创建一个线程,通过特征码(硬编码,不同系统的补丁不同,特征码不同)暴力搜索未导出比较底层函数来杀进程
  • 过程:
    • NtTerminateProcess->PspTerminateProcess(系统未导出的函数)→PspTerminateThreadByPointer ->PspExitThread(杀进程最终变成杀线程)
  • 特征值获取方法:
    • windbg链接上目标系统,加载上系统符号
    • 然后使用:dd函数名L4就可以获得前16个字节的特征值
  • 进入内核地址空间:
    • NtQueryXXX(win8之后版本好像不支持了)或者AuxKlibQueryModulelnformation查询到内核的起始地址大小从而确定ntosknlEndAddrntosknlBase
  • 暴力搜索特征值
/// 在内核空间中暴力搜索,找到16个字节的特征码
/// xp上的特征码
	0x8B55ff8B
	0xA16456EC
	0x00000124
	0x3B08758B
  • 思路2:往进程里插入APC(异步过程调用(APC :Asynchronous Procedure Call)
    @todo
  • 思路3:内存空间填0
    @todo
内核层实现

/// ioctlcmd.h
#define FILE_DEVICE_SWAP     0x0000800a

//IOCTL_CODE

#define IOCTL_PROC_KILL   (ULONG) CTL_CODE(FILE_DEVICE_SWAP, 0x8009, METHOD_BUFFERED, FILE_WRITE_ACCESS)

#define IOCTL_TRANSFER_TYPE( _iocontrol)   (_iocontrol & 0x3)


/// 驱动代码
#include <ntddk.h>
#include <ntimage.h>
#include <ntdef.h>
#include "Ioctlcmd.h"

const WCHAR deviceLinkBuffer[]  = L"\\DosDevices\\KillProc";
const WCHAR deviceNameBuffer[]  = L"\\Device\\KillProc";

typedef NTSTATUS (*NTQUERYSYSTEMINFORMATION)(
		
		IN ULONG                        SystemInformationClass,
		OUT PVOID                        SystemInformation,
		IN ULONG                        SystemInformationLength,
		OUT PULONG                        ReturnLength OPTIONAL  );
typedef unsigned long DWORD;	
NTQUERYSYSTEMINFORMATION NtQuerySystemInformation;
#define	SystemModuleInformation	11	
typedef struct _SYSTEM_MODULE_INFORMATION
{
		ULONG  Reserved[2];
		PVOID  Base;
		ULONG  Size;
		ULONG  Flags;
		USHORT Index;
		USHORT Unknown;
		USHORT LoadCount;
		USHORT ModuleNameOffset;
		CHAR   ImageName[256];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;

PDEVICE_OBJECT g_HookDevice;
NTSTATUS  PsLookupProcessByProcessId(ULONG ProcessId,PEPROCESS *Process);

typedef  NTSTATUS  (*PSPTERPROC) ( PEPROCESS Process, NTSTATUS ExitStatus );
PSPTERPROC MyPspTerminateProcess = NULL ;


NTSTATUS OnUnload(IN PDRIVER_OBJECT DriverObject)
{
	UNICODE_STRING          deviceLinkUnicodeString;
	PDEVICE_OBJECT	   p_NextObj;


	DbgPrint("OnUnload called\n");

	p_NextObj = DriverObject->DeviceObject;

	if (p_NextObj != NULL)
	{

		RtlInitUnicodeString( &deviceLinkUnicodeString, deviceLinkBuffer );
		IoDeleteSymbolicLink( &deviceLinkUnicodeString );

		IoDeleteDevice( DriverObject->DeviceObject );
	}
	return STATUS_SUCCESS;
}

NTSTATUS 
DispatchControl(
	IN PDEVICE_OBJECT DeviceObject, 
	IN PIRP Irp)
{
	PIO_STACK_LOCATION      irpStack;
	PVOID                   inputBuffer;
	PVOID                   outputBuffer;
	PVOID			     userBuffer;
	ULONG                   inputBufferLength;
	ULONG                   outputBufferLength;
	ULONG                   ioControlCode;
	NTSTATUS		     ntstatus;

	unsigned int i;

	unsigned total = 0;
	ULONG count = 0;

	HANDLE handle;


	ULONG cnt;

	PEPROCESS Eprocess = NULL;
	DWORD pid;


	ntstatus = Irp->IoStatus.Status = STATUS_SUCCESS;
	Irp->IoStatus.Information = 0;

	irpStack = IoGetCurrentIrpStackLocation (Irp);

	inputBuffer             = Irp->AssociatedIrp.SystemBuffer;
	inputBufferLength       = irpStack->Parameters.DeviceIoControl.InputBufferLength;
	outputBuffer            = Irp->AssociatedIrp.SystemBuffer;
	outputBufferLength      = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
	ioControlCode           = irpStack->Parameters.DeviceIoControl.IoControlCode;

	
	
	switch (irpStack->MajorFunction)
   {
	case IRP_MJ_CREATE:
		break;

	case IRP_MJ_SHUTDOWN:
		break;

	case IRP_MJ_CLOSE:
		break;

	case IRP_MJ_DEVICE_CONTROL:

		if(IOCTL_TRANSFER_TYPE(ioControlCode) == METHOD_NEITHER) 
	{
			outputBuffer = Irp->UserBuffer;
		}

		
	switch (ioControlCode ) 
	{

	case IOCTL_PROC_KILL:
				if(MyPspTerminateProcess==NULL) //没有找到函数,直接返回
				{
					*(DWORD*)outputBuffer = -1;
					Irp->IoStatus.Information = sizeof(DWORD);
				}
				else
				{
					pid = *(DWORD*)inputBuffer;
					{
						
						ntstatus = PsLookupProcessByProcessId(pid , &Eprocess);//对Eprocess的引用计数进行了加1,所以后面需要ObDereference对应用计数进行减1
						if(!NT_SUCCESS(ntstatus))
						{
							DbgPrint("Failed to lookup process 0x%x, status %8.8x\n", pid , ntstatus);
							*(DWORD*)outputBuffer = 1;
							Irp->IoStatus.Information = sizeof(DWORD);
							break;
						}
						DbgPrint("Lookup of process 0x%x, PEPROCESS at %8.8x\n", pid, Eprocess);
						ntstatus = MyPspTerminateProcess(Eprocess, 0); //0退出码
						if(!NT_SUCCESS(ntstatus))
						{
							DbgPrint("Failed to terminate process 0x%x, status %8.8x\n", pid, ntstatus);
							*(DWORD*)outputBuffer = 2;
							Irp->IoStatus.Information = sizeof(DWORD);
							break;
						}
						*(DWORD*)outputBuffer = 0;
						Irp->IoStatus.Information = sizeof(DWORD);
						DbgPrint("Process 0x%x terminated\n", pid);
					}
				}
				break;
					
	  
	default:
			break;
		}
	IoCompleteRequest( Irp, IO_NO_INCREMENT );
	 
	}
	return ntstatus;  
}

NTSTATUS DispatchCreate (
		IN PDEVICE_OBJECT	pDevObj,
		IN PIRP		pIrp)
{

	pIrp->IoStatus.Status = STATUS_SUCCESS;
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );
	return STATUS_SUCCESS;
}

ULONG GetFunctionAddr( IN PCWSTR FunctionName)
	{
		UNICODE_STRING UniCodeFunctionName;
		
		RtlInitUnicodeString( &UniCodeFunctionName, FunctionName );
		return (ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName );   //动态获取函数的地址,在某些系统中不一定有要找的函数
		
	}

VOID DoFind(IN PVOID pContext)
	{
		NTSTATUS ret;
		PSYSTEM_MODULE_INFORMATION  module = NULL;
		ULONG n=0;
		void  *buf    = NULL;
		ULONG ntosknlBase;
		ULONG ntosknlEndAddr;
		ULONG curAddr;
		ULONG code1_sp3=0x8b55ff8b,code2_sp3=0xA16456EC,code3_sp3=0x00000124,code4_sp3=0x3B08758B; //特征码
		ULONG i;
		
		NtQuerySystemInformation=(NTQUERYSYSTEMINFORMATION)GetFunctionAddr(L"NtQuerySystemInformation");
		if (!NtQuerySystemInformation) 
		{
			DbgPrint("Find NtQuerySystemInformation faild!");
			goto Ret;
		}
		ret=NtQuerySystemInformation(SystemModuleInformation,&n,0,&n); //第一次查询模块的大小
		if (NULL==( buf=ExAllocatePoolWithTag(NonPagedPool, n, 'DFSP')))
		{
			DbgPrint("ExAllocatePool() failed\n" );
			goto Ret;
		}
		ret=NtQuerySystemInformation(SystemModuleInformation,buf,n,NULL); //第二次查询,把查询的结果放在buf
		if (!NT_SUCCESS(ret))	{
			DbgPrint("NtQuerySystemInformation faild!");
			goto Ret;
		} 
		//+1 reason: The data returned to the SystemInformation buffer is a ULONG count of the number of
		//modules followed immediately by an array of SYSTEM_MODULE_INFORMATION
		module=(PSYSTEM_MODULE_INFORMATION)((PULONG)buf+1); //buf中的前面4Byte表示buf存放模块的个数,内核模块是buf中的第一个模块
		ntosknlEndAddr=(ULONG)module->Base+(ULONG)module->Size;
		ntosknlBase=(ULONG)module->Base;
		curAddr=ntosknlBase;
		ExFreePool(buf);
		//MmIsAddressValid(i) //i可能是无效的,校验一下
		for (i=curAddr;i<=ntosknlEndAddr;i++) //暴力搜索
		{
				if (*((ULONG *)i)==code1_sp3) 
				{
					if (*((ULONG *)(i+4))==code2_sp3) 
					{
						if (*((ULONG *)(i+8))==code3_sp3) 
						{
							if (*((ULONG *)(i+12))==code4_sp3) 
							{
								MyPspTerminateProcess=(PSPTERPROC)i; //地址转换成对应的函数指针
								break;
							}
						}
					}
				}
		}
Ret:
	PsTerminateSystemThread(STATUS_SUCCESS);
	}

VOID GetPspAddr()
{
		HANDLE hThread;
		PVOID objtowait=0;
		NTSTATUS dwStatus = 
			PsCreateSystemThread(
			&hThread,
				  0,
			   NULL,
			(HANDLE)0,
				  NULL,
			   DoFind, //在线程DoFind里面找函数地址
			NULL
			);
		NTSTATUS st;
		if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)
		{
			st=KfRaiseIrql(PASSIVE_LEVEL);//KeLowerIrql()?
		
		}
		if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)
		{
			
			return;
		}
		
		ObReferenceObjectByHandle(
			hThread,
			THREAD_ALL_ACCESS,
			NULL,
			KernelMode,
			&objtowait,
			NULL
			); 

		st=KeWaitForSingleObject(objtowait,Executive,KernelMode,FALSE,NULL); //NULL表示无限期等待.
		return;
	
	
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
	NTSTATUS rc;
	
	RTL_OSVERSIONINFOW osvi;
	NTSTATUS                ntStatus;
	UNICODE_STRING          deviceNameUnicodeString;
	UNICODE_STRING          deviceLinkUnicodeString;   

	RtlInitUnicodeString (&deviceNameUnicodeString,
		deviceNameBuffer );
	RtlInitUnicodeString (&deviceLinkUnicodeString,
		deviceLinkBuffer );

	ntStatus = IoCreateDevice ( DriverObject,
		0,
		&deviceNameUnicodeString,
		FILE_DEVICE_SWAP,
		0,
		TRUE,
		&g_HookDevice );

	if(! NT_SUCCESS(ntStatus))
	{
		  DbgPrint(("Failed to create device!\n"));
		  return ntStatus;
	 }		
	ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,
		&deviceNameUnicodeString );
	if(! NT_SUCCESS(ntStatus)) 
	{
		 IoDeleteDevice(DriverObject->DeviceObject);
			DbgPrint("Failed to create symbolic link!\n");
			return ntStatus;
	 }
		DriverObject->MajorFunction[IRP_MJ_SHUTDOWN]        =
		DriverObject->MajorFunction[IRP_MJ_CREATE]          =   DispatchCreate;
		DriverObject->MajorFunction[IRP_MJ_CLOSE]           =    
	 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]  = DispatchControl;

	DriverObject->DriverUnload  = OnUnload;

	GetPspAddr(); //驱动启动时找到函数地址
	if(MyPspTerminateProcess == NULL)
	{
		DbgPrint("PspFunc Not Find!\n");
	}
	return STATUS_SUCCESS;
}

应用层实现
void CLstProcDlg::OnForceKillproc() 
{
	DWORD ret = 0;
	DWORD read;
	if(m_dwPID==-1)
	{
		MessageBox("请选择进程");
		return;
	}
	if(MessageBox(_T("强杀进程可能会造成系统不稳定,确认要进行吗?"),_T("强杀进程"),MB_YESNO)==IDYES)
	{
		InitDriver();
		Initialized = FALSE;
		DeviceIoControl(gh_Device, 
						IOCTL_PROC_KILL,
						&m_dwPID,
						sizeof(m_dwPID),
						&ret,
						sizeof(ret),
						&read,
						NULL);
		CloseHandle(gh_Device);
		UnloadDeviceDriver(ac_driverName);
		if(ret==0)
			MessageBox(_T("成功执行"));
		else
			MessageBox(_T("执行失败"));
		CloseHandle(gh_Device);
		ShellExecute(NULL, "open", "sc","stop LstProc", NULL, SW_HIDE); 

		
	}	
}

文件注册表穿越

文件穿越思路

@todo

  • 文件穿越目的:不调用系统提供的函数对文件进行操作,是为绕过这些被木马和病毒hook的函数
  • 思路1:打开文件用IoCreateFile,其他比较好发Irp的(比如删除操作)走FSD irp(文件系统),摘掉过滤设备(Irp下发还会被文件过滤驱动拦截)
  • 思路2:自己实现了所有Nt系列操作文件的功能
  • 思路3:重载一个内核
  • 思路4MJ XCB大法(XCB是FCB、VCB、CCB、SCB 、LCB总称)
    • 当文件从磁盘打开,加载到内存中,会构造一个FCB(文件控制块),

    https://bbs.pediy.com/thread-87741.htm
    https://blog.csdn.net/Shevacoming/article/details/7559078
    《Windows NT File System Iternals》 文件加解密必备

    • 特权方式无法打开(带delete标志),带FlLE_ATTRIBUTE_NORMAL方式打开文件,获得FileObject:
      pSCB=FileObject->FsContext
      pCCB=FileObject->FsContext2
    • 伪造句柄完全被关闭的情形来欺骗系统。CleanUpCount针对一个文件被打开的句柄数,,我们打开文件以后,这个值就是2。伪造为1:
      scb->CleanUpCount=1
      fcb->CleanUpCount=1
      ccb->CleanUpCount=1
    • 修改过CleanUpCount之后,调用NtClose关闭句柄。这样在NtClose下层将调用NtfsRemoveLink()移除硬链接;然后NfsDecrementCleanupCounts()将CleanupCounte减1,这样文件对象的引用计数会降为0,并释放所有关联的SCB。然后调用loRemoveShareAccess()将ShareAccess.Openeount会清零,解锁,独占就被解除了。
  • 思路5:直接磁盘填0(不走文件系统,直接以磁盘的方式打开,直接进行扇区操作
    • MFT(Master File Table)表,定位到文件在磁盘的扇区
    • hDrive =CreateFile("\\\\.\\PHYSICALDRIVE0",GENERIC_READ,FlLE_SHARE_READ|FILE_SHAREWRITE,0,OPEN_EXISTING,0.0);
    • TCHAR_devicename[] = \_T("\\\\.\\C")
    • writefile/readfile
    • CNtsFileSys::ReadSector(ULONGLONG sector, ULONG count, PVOID buffer)
    • WIN/7权限问题:DeviceloControl向逻辑分区发一个FSCTL_LOCK_VOLUME指令,把它锁住,然后就可以WriteFile写扇区了
/// (不太靠谱,只要这个扇区中是个系统盘或者包含page file就会失败)
systerm volume or contains a page file, fails .
/// 在这个卷上有任何一个打开的文件,也会失败。
any open files on the volume,fail.no open files.
/// 所以这种方法只能用在实模式下,做磁盘工具或者备份程序。在保护模式下权限不够
useful for disk utilily  and backup programs.

注册表穿越思路

@todo

  • 思路1:将ntoskrnl.exe (内核)reload到内存中,自己调用无SSDT/Inline hook的注册表操作。CmpCallback(一组用于注册表监控的回调函数)清0,这样调用的操作就不会被监控和被拦截了。
  • 思路2:自已实现ssdt注册表函数;
    • CmpCallback清零
    • 找到Cm***Key函数:通过KCBroutine hook(hook _CM_KEY_CONTROL_BLOCK->KeyHive->GetCellRoutine)栈回溯得到以下函数的地址:
b23d0e40 8063578a nt!CmDeleteKey
b23d0e48 8063234a nt!CmEnumerateKey
b23d0e58 80632724 nt!CmQueryValuekey
b23d0e5c 80632170 nt!CmDeletevalueKey
b23d0e60 80633cd2 nt!CmSetvalueKey
b23d0e68 8063578a nt!CmDeleteKey
b23d0e7c 80632422 nt!CmEnumerateValueKey
  • 内存爆搜得到CmpParseKey:
    _CmpCloseKeyObject
    _CmpParseKey
    _CmpQueryKeyName
  • 自己实现ssdt部分直接调用Cm***Key可参考WRK
  • 思路3.reghive注册表解析:

https://www.52pojie.cn/thread-41492-1-1.html sudami

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值