-
-
[原创]强删,强杀,穿越
-
发表于: 2023-2-7 08:19 8677
-
本公众号分享的所有技术仅用于学习交流,请勿用于其他非法活动,如有错漏,欢迎留言交流指正
《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,拒绝删除
。
- 上层调用
1 2 3 | pSectionObjectPointer = fileObject - >SectionObjectPointer; psectionObjectPointer - >ImageSectionObject = 0 ; pSectionObjectPointer - >DataSectionObject = 0 ; |
解决方式
:- 可以提前把
ImageSectionObject
和DataSectionObject
设为0,欺骗操作系统。
- 可以提前把
- 构建IRP删除文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 | #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)
,设置一个超时,如果超时了,就把该句柄排除掉。
- 新建一个线程,调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 | #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
- 用
- 暴力搜索特征值
1 2 3 4 5 6 | / / / 在内核空间中暴力搜索,找到 16 个字节的特征码 / / / xp上的特征码 0x8B55ff8B 0xA16456EC 0x00000124 0x3B08758B |
1 2 3 4 5 6 7 8 | / / / 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) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | / / / 驱动代码 #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; } |
应用层实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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写扇区了
1 2 3 4 5 6 | / / / (不太靠谱,只要这个扇区中是个系统盘或者包含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
)栈回溯得到以下函数的地址:
1 2 3 4 5 6 7 | 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
赞赏记录
参与人
雪币
留言
时间
胖虎404
感谢你的积极参与,期待更多精彩内容!
2024-10-25 13:09
一笑人间万事
为你点赞~
2024-5-31 06:48
一路南寻
为你点赞~
2024-5-31 06:18
嫉妒的死远点
为你点赞~
2024-5-31 06:16
東陽不列山
为你点赞~
2024-5-31 06:14
治愈ckt
为你点赞~
2024-3-18 17:25
704088
为你点赞~
2023-3-31 00:44
赞赏
他的文章
- [原创]java和smali汇编 2736
- [原创]Android逆向前期准备(下) 4545
- [原创]native层逆向分析(上篇) 14048
- [原创]Java层逆向分析方法和技巧 7281
看原图
赞赏
雪币:
留言: