本公众号分享的所有技术仅用于学习交流,请勿用于其他非法活动,如有错漏,欢迎留言交流指正
《Windows NT File System Iternals》 文件加解密必备
《Windows驱动开发技术详解》张帆 电子工业出版社 很基础,仅仅适合入门
《Windows 2000设备驱动程序设计智能》 Art Baker等主 机械工业出版社
《寒江独钓:Windows内核安全编程》 邵坚磊等著 电子工业出版社
《Windows内核原理与实现》潘爱民
强删,强杀,穿越
强制删除文件
- 安全软件用
强删
清除病毒木马 - 病毒木马也可以用
强删
来删除系统保护文件或是受杀软保护的文件。
内核层实现强删文件
强删文件思路
- 打开文件
- 删除文件首先要打开文件,得到文件的句柄,打开文件一般是调用
ZwCreateFile
- 通过在windbg看到应用层到内核层的调用栈,可以发现
ZwCreateFile
->NtCreateFile
函数底层调用
的就是IoCreateFile
。 - NTCreteFile很容易就被HOOK(
SSDT HOOK
),而IoCreateFile
更底层,对它的HOOK难度更大一些,更可靠一些,所以强删文件这里使用IoCreateFile
来打开文件。
- 解锁
a. 只读
- 文件或文件夹包含三种属性:
- 1.只读:只读属性是不允许修改的文件。若将文件或文件夹设置为只读属性,则该文件或文件夹
不允许更改
。在应用层是可以删除的。
,在内核层则无法删除
。 - 2.隐藏:隐藏的文件是看不见的。若将文件或文件夹设置为隐藏属性,则该文件或文件夹在常规显示中将不被看到;
- 3.存档:一般的文件的属性是存档的。若将文件或文件夹设置为存档属性,则表示该文件或文件夹已存档,有些程序用此选项来确定哪些文件需做备份
- 1.只读:只读属性是不允许修改的文件。若将文件或文件夹设置为只读属性,则该文件或文件夹
- 解决方法:
- 抹除只读权限后再删除
- @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
中的成员ImageSectionObject
和DataSectionObject
是否都
为0,如果都
不为0,则认为该文件是正在运行的.exe,拒绝删除
。
- 上层调用
pSectionObjectPointer = fileObject->SectionObjectPointer;
psectionObjectPointer->ImageSectionObject = 0;
pSectionObjectPointer->DataSectionObject = 0;
解决方式
:- 可以提前把
ImageSectionObject
和DataSectionObject
设为0,欺骗操作系统。
- 可以提前把
- 构建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(杀进程最终变成杀线程)
- NtTerminateProcess->
- 特征值获取方法:
- 用
windbg
链接上目标系统,加载上系统符号
- 然后使用:
dd函数名L4
就可以获得前16
个字节的特征值
- 用
- 进入内核地址空间:
- 用
NtQueryXXX(win8之后版本好像不支持了)
或者AuxKlibQueryModulelnformation
查询到内核的起始地址
和大小
从而确定ntosknlEndAddr
和ntosknlBase
- 用
- 暴力搜索特征值
/// 在内核空间中暴力搜索,找到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
:重载一个内核思路4
:MJ 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