首页
社区
课程
招聘
[原创]内核无HOOK文件防删除,可以过冰刃,xuetr,easydelete
发表于: 2010-5-8 13:15 19508

[原创]内核无HOOK文件防删除,可以过冰刃,xuetr,easydelete

2010-5-8 13:15
19508
本来是打算写暴力删除文件的程序的,结果意外发现,只需要在内核发送irp打开一个文件,之后不关闭Object,就拒绝其他程序访问了,easydelete这个工具还是比较强的,不过也不能删除,关键是不挂钩任何函数,不修该系统内核,看属性的时候只能看到一个常规,其它的什么都看不到,当然了360(7.0)版本的文件粉碎机也是搞不定的,其它工具没试 ,大家可以自己试试玩玩,打开文件使用炉子的代码:
NTSTATUS
IoCompletionRoutine(
      IN PDEVICE_OBJECT DeviceObject,
      IN PIRP Irp,
      IN PVOID Context)
{
*Irp->UserIosb = Irp->IoStatus;
if (Irp->UserEvent)
   KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, 0);
if (Irp->MdlAddress)
{
   IoFreeMdl(Irp->MdlAddress);
   Irp->MdlAddress = NULL;
}
IoFreeIrp(Irp);
return STATUS_MORE_PROCESSING_REQUIRED;
}

NTSTATUS
IrpCreateFile(
     OUT PFILE_OBJECT *FileObject,
     IN ACCESS_MASK DesiredAccess,
     IN PUNICODE_STRING FilePath,
     OUT PIO_STATUS_BLOCK IoStatusBlock,
     IN PLARGE_INTEGER AllocationSize OPTIONAL,
     IN ULONG FileAttributes,
     IN ULONG ShareAccess,
     IN ULONG CreateDisposition,
     IN ULONG CreateOptions,
     IN PVOID EaBuffer OPTIONAL,
     IN ULONG EaLength)
{
NTSTATUS ntStatus;

HANDLE hFile;
PFILE_OBJECT pFile, _FileObject;
UNICODE_STRING UniDeviceNameString;
OBJECT_ATTRIBUTES ObjectAttributes;
PDEVICE_OBJECT DeviceObject, RealDevice;

PIRP Irp;
KEVENT kEvent;
PIO_STACK_LOCATION IrpSp;
ACCESS_STATE AccessState;
AUX_ACCESS_DATA AuxData;
IO_SECURITY_CONTEXT SecurityContext;

WCHAR DeviceNameString[]=L"\\DosDevices\\*:\\";

if(FilePath->Length < 6)
   return STATUS_INVALID_PARAMETER;
// \\??\c:\xxxx

DeviceNameString[12]=FilePath->Buffer[0];

RtlInitUnicodeString( &UniDeviceNameString, DeviceNameString);
InitializeObjectAttributes(&ObjectAttributes, &UniDeviceNameString, OBJ_KERNEL_HANDLE, NULL, NULL);

ntStatus = IoCreateFile(&hFile,
   GENERIC_READ|SYNCHRONIZE,
   &ObjectAttributes,
   IoStatusBlock,
   NULL,
   FILE_ATTRIBUTE_NORMAL,
   FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
   FILE_OPEN,
   FILE_SYNCHRONOUS_IO_NONALERT,
   NULL,
   0,
   CreateFileTypeNone,
   NULL,
   IO_NO_PARAMETER_CHECKING);

if(!NT_SUCCESS(ntStatus))
{
   KdPrint(("IrpCreateFile: IoCreateFile 0x%X.\n",ntStatus));
   return ntStatus;
}
        RecoverOneKernelRoutine("ObReferenceObjectByHandle");
ntStatus = ObReferenceObjectByHandle(hFile,
   FILE_READ_ACCESS, // ACCESS_MASK
   *IoFileObjectType,
   KernelMode,
   (PVOID*)&pFile,
   0);

NtClose(hFile);

if(!NT_SUCCESS(ntStatus))
{
   KdPrint(("IrpCreateFile: ObReferenceObjectByHandle 0x%X.\n",ntStatus));
   return ntStatus;
}

DeviceObject = pFile->Vpb->DeviceObject;
RealDevice = pFile->Vpb->RealDevice;
ObDereferenceObject(pFile);

InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_CASE_INSENSITIVE, 0, NULL);

ntStatus = ObCreateObject(KernelMode,
   *IoFileObjectType,
   &ObjectAttributes,
   KernelMode,
   NULL,
   sizeof(FILE_OBJECT),
   0,
   0,
   (PVOID*)&_FileObject);

if(!NT_SUCCESS(ntStatus))
{
   KdPrint(("IrpCreateFile: ObCreateObject 0x%X.\n",ntStatus));
   return ntStatus;
}

Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if(Irp == NULL)
{
   KdPrint(("IrpCreateFile: IoAllocateIrp 0x%X.\n",ntStatus));
   ObDereferenceObject(_FileObject);
   return STATUS_INSUFFICIENT_RESOURCES;
}

KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);

RtlZeroMemory(_FileObject, sizeof(FILE_OBJECT));
_FileObject->Type = IO_TYPE_FILE;
_FileObject->Size = sizeof(FILE_OBJECT);
_FileObject->DeviceObject = RealDevice;
_FileObject->Flags = FO_SYNCHRONOUS_IO;
////////\\??\c:\xxxxx
RtlInitUnicodeString( &_FileObject->FileName, &FilePath->Buffer[2]);
KdPrint(("准备打开文件:%ws\n",_FileObject->FileName.Buffer));
KeInitializeEvent(&_FileObject->Lock, SynchronizationEvent, FALSE);
KeInitializeEvent(&_FileObject->Event, NotificationEvent, FALSE);

RtlZeroMemory(&AuxData, sizeof(AUX_ACCESS_DATA));
ntStatus = SeCreateAccessState( &AccessState,
   &AuxData,
   DesiredAccess,
   IoGetFileObjectGenericMapping());

if (!NT_SUCCESS(ntStatus))
{
   KdPrint((" IrpCreateFile: SeCreateAccessState 0x%X.\n",ntStatus));
   IoFreeIrp(Irp);
   ObDereferenceObject(_FileObject);
   return ntStatus;
}

SecurityContext.SecurityQos = NULL;
SecurityContext.AccessState = &AccessState;
SecurityContext.DesiredAccess = DesiredAccess;
SecurityContext.FullCreateOptions = 0;

Irp->MdlAddress = NULL;
Irp->AssociatedIrp.SystemBuffer = EaBuffer;
Irp->Flags = IRP_CREATE_OPERATION|IRP_SYNCHRONOUS_API;
Irp->RequestorMode = KernelMode;
Irp->UserIosb = IoStatusBlock;
Irp->UserEvent = &kEvent;
Irp->PendingReturned = FALSE;
Irp->Cancel = FALSE;
Irp->CancelRoutine = NULL;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
Irp->Tail.Overlay.OriginalFileObject = _FileObject;

IrpSp = IoGetNextIrpStackLocation(Irp);
IrpSp->MajorFunction = IRP_MJ_CREATE;
IrpSp->DeviceObject = DeviceObject;
IrpSp->FileObject = _FileObject;
IrpSp->Parameters.Create.SecurityContext = &SecurityContext;
IrpSp->Parameters.Create.Options = (CreateDisposition << 24) | CreateOptions;
IrpSp->Parameters.Create.FileAttributes = (USHORT)FileAttributes;
IrpSp->Parameters.Create.ShareAccess = (USHORT)ShareAccess;
IrpSp->Parameters.Create.EaLength = EaLength;

IoSetCompletionRoutine(Irp, IoCompletionRoutine, 0, TRUE, TRUE, TRUE);
//add 
RecoverIopfCompleteRequest();
ntStatus = IofCallDriverEx(DeviceObject, Irp);
if(ntStatus == STATUS_PENDING)
   KeWaitForSingleObject(&kEvent, Executive, KernelMode, TRUE, 0);

ntStatus = IoStatusBlock->Status;


if(!NT_SUCCESS(ntStatus))
{
   KdPrint(("IrpCreateFile: IoCallDriver 0x%X.\n",ntStatus));
   _FileObject->DeviceObject = NULL;
   ObDereferenceObject(_FileObject);
}
else
{
   InterlockedIncrement((volatile LONG *)&_FileObject->DeviceObject->ReferenceCount);
   if (_FileObject->Vpb)
    InterlockedIncrement((volatile LONG *)&_FileObject->Vpb->ReferenceCount);
   *FileObject = _FileObject;
}

return ntStatus;
}
//UNICODE_STRING Name;
//IO_STATUS_BLOCK IoBlock;
//RtlInitUnicodeString(&Name,L"C:\\test1.exe");
//Status=IrpCreateFile(&FileObj,GENERIC_READ|DELETE,&Name,&IoBlock,0,FILE_ATTRIBUTE_NORMAL,FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,FILE_OPEN,0,0,0);


上面是测试代码,打开之后不ObDereferenceObject,直接返回,之后文件就被保护起来了

[课程]Linux pwn 探索篇!

收藏
免费 7
支持
分享
最新回复 (20)
雪    币: 350
活跃值: (87)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
2
以上代码我测试了一下,好像在WIN7中蓝屏
2010-5-8 20:41
0
雪    币: 8865
活跃值: (2379)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
3
SeCreateAccessState时某个参数的大小不对,于是蓝屏了~
AUX_ACCESS_DATA的实际大小要比DDK里定义的大小要大不少,跟DriverObject类似~
2010-5-8 21:22
0
雪    币: 220
活跃值: (701)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
还是V大牛呀。建议LZ修正后发个完整工程
2010-5-8 22:38
0
雪    币: 27
活跃值: (43)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
mark

以后回头来看
2010-5-8 22:42
0
雪    币: 522
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
6
发出来 估计就不能用了  
2010-5-9 00:35
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
7
http://hi.baidu.com/_achillis/blog/item/23b32a28ad5bdef298250a0c.html
2010-5-9 11:46
0
雪    币: 66
活跃值: (835)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
强贴留名。
2010-5-9 12:10
0
雪    币: 284
活跃值: (106)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
9
膜拜教主,自己确实没在Windows7下测试……
2010-5-9 12:37
0
雪    币: 8865
活跃值: (2379)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
10
其实对付这种情况有一个统一的有效的方法就是直接申请1MB的nonpagedpool给它呀玩~
2010-5-9 16:25
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
11
有效是有效,但也得先知道原因在哪儿才行啊~~
2010-5-9 19:52
0
雪    币: 226
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
这个的原因是为什么呢?
2010-5-9 20:25
0
雪    币: 226
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
下载了符号后就一目了然了。。。
2010-5-9 20:27
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
14
有符号怎么了?有符号就什么都看得出来了?undocument的东西啊~~
2010-5-9 21:08
0
雪    币: 451
活跃值: (78)
能力值: ( LV12,RANK:470 )
在线值:
发帖
回帖
粉丝
15
人家可能是用的私有符号
貌似只有私有符号里面有变量和结构的实际大小
2010-5-9 21:25
0
雪    币: 451
活跃值: (78)
能力值: ( LV12,RANK:470 )
在线值:
发帖
回帖
粉丝
16
引用的文字都保存到论坛里面一份,下文出处是教主的blog
这也许是我这个假期唯一做的跟Code有关的事了,已经一个多月没写代码了~~
问题是这样的,某同学A,在自己的工程中使用了PsVoid的部分驱动源码(感谢炉子开源~~),提到里面的IrpCreateFile函数在Win7下始终会蓝屏,希望我能帮忙解决一下。于是,拿出调试器开始debug之旅~~
先简单介绍下,IrpCreateFile中PsVoid中Irp文件操作库中的一个函数,主要功能就是直接发IRP实现文件打开操作。该函数在 WinXP/2003下均正常工作,但是在Win7下总是会蓝屏。写了个测试驱动扔到Vmware里,挂上调试器跟踪了一下,初步发现问题出在填充完 IRP准备向下IoCallDriver时。现场如下:
kd> u IofCallDriver
nt!IofCallDriver:
83a7b458 8bff mov edi,edi
83a7b45a 55 push ebp
83a7b45b 8bec mov ebp,esp
83a7b45d 51 push ecx
83a7b45e a15c7aba83 mov eax,dword ptr [nt!pIofCallDriver (83ba7a5c)]
83a7b463 56 push esi
83a7b464 8bf1 mov esi,ecx //DeviceObject参数保存至esi
83a7b466 33c9 xor ecx,ecx
....
83a88492 8a08 mov cl,byte ptr [eax] //eax指向IoStackLocation,這里是判断MajorFunction
83a88494 897014 mov dword ptr [eax+14h],esi //取刚才保存的DeviceObject参数,赋给IrpStack->DeviceObject
83a88497 80f916 cmp cl,16h
83a8849a 7514 jne nt!IofCallDriver+0x57 (83a884b0)
kd> p
nt!IofCallDriver+0x57:
83a884b0 8b4608 mov eax,dword ptr [esi+8] //取DeviceObject->DriverObject,很不幸这里DeviceObject是NULL,于是杯具发生了。。。
大概就是这样的,DeviceObject是IrpCreateFile函数中的一个局部变量,当IoCallDriver时DeviceObject参数竟然是NULL,那取DeviceObject->DriverObject必然会蓝屏了~~
刚开始,我怀疑前面取到的DeviceObject就是NULL,代码如下:
DbgPrint("The Volume FileObject=0x%08X\n",pFile);
DeviceObject = pFile->Vpb->DeviceObject;
DbgPrint("pFile->Vpb->DeviceObject = 0x%08X\n",DeviceObject);
RealDevice = pFile->Vpb->RealDevice;
DbgPrint("pFile->Vpb->RealDevice = 0x%08X\n",RealDevice);
但是再次调试,发现这里是正常的,DeviceObject的值有效,不知怎的在准备IoCallDriver时变成了0,于是,再次调试~~
这次调试时,密切监视DeviceObject值的变化。终于发现,在走过以下代码之后,DeviceObject变成了0
RtlZeroMemory(&AuxData, sizeof(AUX_ACCESS_DATA));
ntStatus = SeCreateAccessState( &AccessState,
&AuxData,
DesiredAccess,
IoGetFileObjectGenericMapping());
在调用完SeCreateAccessState之后,DeviceObject变成了0,很莫名的问题啊。不过,目标已经锁定在SeCreateAccessState,再重启,再次来过。。。
过程如下:
在IrpCreateFile中:
//DeviceObject = pFile->Vpb->DeviceObject;
93f14759 8b4df4 mov ecx,dword ptr [ebp-0Ch]
93f1475c 8b5108 mov edx,dword ptr [ecx+8]
93f1475f 8b4208 mov eax,dword ptr [edx+8]
93f14762 898550ffffff mov dword ptr [ebp-0B0h],eax //DeviceObject保存在了ebp-b0处,如下:
kd> dd ebp-b0
807e1994 85bcb020 00000006 807e19b4 83e16b29 //可以看到,此时DeviceObject=85bcb020,是有效值
807e19a4 83b2ac02 80000574 3c8fb9d2 83b2ac02
807e19b4 807e19c0 83e16cca 534fa145 807e19d0
继续往下,一直到调用SeCreateAccessState之前,这个值都没有变化。
到了SeCreateAccessState,跟进去,发现这个函数只是直接调用了SeCreateAccessStateEx函数,WRK中源码如下,Win7中也没什么变化。
NTSTATUS
SeCreateAccessState(
__out PACCESS_STATE AccessState,
__out PAUX_ACCESS_DATA AuxData,
__in ACCESS_MASK DesiredAccess,
__in_opt PGENERIC_MAPPING GenericMapping
)
{
return SeCreateAccessStateEx (PsGetCurrentThread (),
PsGetCurrentProcess (),
AccessState,
AuxData,
DesiredAccess,
GenericMapping);
}
继续跟进至SeCreateAccessStateEx。。。
发现了两个memset调用~~
kd>
nt!SeCreateAccessStateEx+0x23:
83c6f633 e8e0440400 call nt!RtlMapGenericMask (83cb3b18)
83c6f638 8b7d10 mov edi,dword ptr [ebp+10h] //取第三个参数至edi
83c6f63b 6a74 push 74h
83c6f63d 6a00 push 0
83c6f63f 57 push edi
83c6f640 e8fbe7e0ff call nt!memset (83a7de40) //将第三个参数AccessState指向的内存清零
83c6f645 8b7514 mov esi,dword ptr [ebp+14h] ////取第三个参数至esi
83c6f648 83c40c add esp,0Ch
83c6f64b 68c0000000 push 0C0h
83c6f650 6a00 push 0
83c6f652 56 push esi
83c6f653 e8e8e7e0ff call nt!memset (83a7de40) //将第四个参数AuxData指向的内存清零
这两句对应于以下代码:
RtlZeroMemory(AccessState, sizeof(ACCESS_STATE));
RtlZeroMemory(AuxData, sizeof(AUX_ACCESS_DATA));
//在SeCreateAccessStateEx这个函数中:
kd> p
nt!SeCreateAccessStateEx+0x3b:
83c3664b 68c0000000 push 0C0h
83c36650 6a00 push 0
83c36652 56 push esi
83c36653 e8e8e7e0ff call nt!memset (83a44e40) //准备清零
kd> dd esp l4
8cc678cc 8cc6793c 00000000 000000c0 8cc67958 //memset的参数
kd> dd 8cc67994 //此时局部变量DeviceObject的值,仍然是正确值
8cc67994 85bd4020 00040001 00000000 8cc679a0
8cc679a4 8cc679a0 80000648 00000000 00000000
kd> ? 8cc6793c+c0
Evaluate expression: -1933149700 = 8cc679fc
也就是说,要memset清零的区域是从8cc6793c到8cc679fc, 我们的局部变量的地址8cc67994就在这之间,于是被清零了。。。

为什么会出现这样一个结果呢?AuxData是一个结构体,该参数是从IrpCreateFile中传过来的,和DeviceObject都是局部变量。而现在,对AuxData的操作竟然影响到了DeviceObject,能想到的,就是从他们在栈中的布局入手了。


可以看到,AuxData位于ebp-108h处,与它相邻的局部变量是SourceString,位于ebp-ECh处。
也就是说,AuxData的实际大小只有0x108-0xEC=0x1C
而在SeCreateAccessStateEx中,我们明显可以看到系统认为这个结构的大小是0xC0,那么进行memset时,实际影响的范围是
从ebp-108h到ebp-108h+0xC0=ebp-48h,而我们的局部变量DeviceObject位于ebp-B0h处,正位于这个范围之间,于是就被清零了,同样受影响的还有位于该范围内的 SourceString,NameBuffer,ntStatus,ObjectAttributes,DeviceObject,Event,Handle,AccessState 等局部变量,如果要再使用这些变量的话,同样会出现问题,比如你要使用Handle的时候,发现竟然成无效句柄了。。。
所以,根本原因就是使用了不正确的结构定义,导致SeCreateAccessStateEx函数对局部变量AuxData清零初始化时同时修改了其它局部变量的值。
原因既然找到了,解决起来就容易了。经询问,A同学说这个结构是他根据PsVoid源码中的定义自己修改的,是一个未文档化的结构。恩,未文档化的东西,用起来难免会有不可靠的时候啊~~~
解决方案:修改AUX_ACCESS_DATA的定义就行了。该结构原来的定义为:
typedef struct _AUX_ACCESS_DATA {
PPRIVILEGE_SET PrivilegesUsed;
GENERIC_MAPPING GenericMapping;
ACCESS_MASK AccessesToAudit;
ACCESS_MASK MaximumAuditMask;
} AUX_ACCESS_DATA, *PAUX_ACCESS_DATA;
该结构现在的大小为0x1C,而Win7中该结构实际大小为0xC0。(0xC0-0x1C)/sizeof(ULONG)=0x29=41,那么修改定义如下:
typedef struct _AUX_ACCESS_DATA {
PPRIVILEGE_SET PrivilegesUsed;
GENERIC_MAPPING GenericMapping;
ACCESS_MASK AccessesToAudit;
ACCESS_MASK MaximumAuditMask;
ULONG Unknown[41];
} AUX_ACCESS_DATA, *PAUX_ACCESS_DATA;
修改之后,经测试,蓝屏问题解决~~
2010-5-9 21:27
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
有效是有效,但也得先知道原因在哪儿才行啊~~
2010-5-9 21:29
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
18
私有符号我知道,但是问题就是这玩意儿一般人没有吧~~
2010-5-9 21:52
0
雪    币: 8865
活跃值: (2379)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
19
原因直接用意念猜测就行了。话说那个IrpCreateFile看起来很眼熟。
2010-5-9 23:44
0
雪    币: 196
活跃值: (33)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
强 留名强 留名
2010-5-11 18:24
0
雪    币: 1001
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
你好,能发一份修正的吗?这个win7下蓝屏
2017-9-16 17:54
0
游客
登录 | 注册 方可回帖
返回
//