這也是好久以前的代碼了。我是菜鳥,在這個問題上研究的不夠深,說錯了還請大牛指正。
這個問題也是一個老問題,不過我是菜鳥我有話要說。我在做這個問題的時候查閱了好多資料,其實這個問題不能算解決,這篇文章你將會看到一段比較長的代碼,其實這段代碼不是我寫的,是網上一個比較有名的人(人稱MJ)寫的,據說這段代碼是通過360檔案粉碎機逆向出來的。
我查了好多資料,發現能夠實現標題所說的功能大概有兩種常用的方法,一個是本文提到的直接發送IRP給目標檔案的裝置驅動強刪檔案,還有一種就是掛鈎MmFlushImageSection函數,很遺憾的是後一種方法沒有什麼實質性的源碼可以參考(不過哪位大神寫一段的話可以拿來分享一下),MmFlushImageSection不是一個系統服務,SSDT的方法當然不行,因為SSDT表沒有匯出這個函數,我記憶不錯的話按照“列寧”大神的說法MmFlushImageSection函數更加底層,是由核心匯出的一個核心功能。以我的才疏學淺的知識不明白如何掛鈎這樣的函數。如果有哪位大神看見了本菜鳥的疑惑還請不吝賜教。
另外還想提到的一點是,之前被一個論壇的好友迷惑了一下,他說只要使用NtDeleteFile這個系統服務就可以實現這樣的功能,這個系統服務有這麼一個功能:
在《The Undocumented Functions》一書中可以看到它對NtDeleteFile的解釋如下:
It's very interesting NT System Call... Normally, file deletion is realised as FileDispositionInformation class in a call to NtSetInformationFile. When you use NtDeleteFile, file will be deleted immediatly after call (system
isn't waiting for close last HANDLE to file).
從上述說明可以看出,如果我們直接調用NtDeleteFile,目標檔案將會被立即刪除而不會等到所有控制代碼都被關閉。
原文在此
於是就試了一下,誒?果然能刪除檔案,我是用一個記事本試的,比如aa.txt。其實這種方式是不正確的,為什麼呢?仔細想想,aa.txt是自己開啟的嗎?不是,是由記事本程式開啟的,也就是notepad.exe,你刪除了檔案並不能表示你可以刪除正在啟動並執行exe檔案,果然,事實證明這樣寫不能刪除正在啟動並執行exe檔案。下面也附上我寫的這段代碼吧,雖然方法上是不正確的。
#include "windows.h"typedef struct _UNICODE_STRING {USHORT Length;USHORT MaximumLength;PWSTR Buffer;} UNICODE_STRING, *PUNICODE_STRING;typedef struct _OBJECT_ATTRIBUTES { ULONG Length; HANDLE RootDirectory; PUNICODE_STRING ObjectName; ULONG Attributes; PVOID SecurityDescriptor; PVOID SecurityQualityOfService;} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;static VOID InitializeObjectAttributes ( OUT POBJECT_ATTRIBUTES InitializedAttributes, IN PUNICODE_STRING ObjectName, IN ULONG Attributes, IN HANDLE RootDirectory, IN PSECURITY_DESCRIPTOR SecurityDescriptor ) { InitializedAttributes->Length = sizeof( OBJECT_ATTRIBUTES ); InitializedAttributes->RootDirectory = RootDirectory; InitializedAttributes->Attributes = Attributes; InitializedAttributes->ObjectName = ObjectName; InitializedAttributes->SecurityDescriptor = SecurityDescriptor; InitializedAttributes->SecurityQualityOfService = NULL; return; }//extern "C" __declspec(dllimport) long __stdcall NtDeleteFile(POBJECT_ATTRIBUTES ObjectAttribtues);typedef ULONG (__stdcall *_NtDeleteFile)(IN POBJECT_ATTRIBUTES ObjectAttributes);_NtDeleteFile NtDeleteFile;void main(){HMODULE m_handle=LoadLibrary("ntdll.dll");UNICODE_STRING uniname ;WCHAR m_file_name[]={L"\\??\\e:\\aa.txt"};uniname.Buffer=m_file_name;uniname.Length = sizeof(m_file_name) - sizeof(WCHAR);uniname.MaximumLength = sizeof(uniname);OBJECT_ATTRIBUTES oba ;if (m_handle!=NULL){InitializeObjectAttributes(&oba , &uniname , 0x40 , 0 , 0 );NtDeleteFile=(_NtDeleteFile)GetProcAddress(m_handle,"NtDeleteFile");NtDeleteFile(&oba);}}
這是一個使用者態的程式,直接從ntdll中匯出了NtDeleteFile。
然後我也附上Mj大神的發送IRP強刪檔案的方法:
#include <ntddk.h>#define NT_DEVICE_NAME L"\\Device\\360SuperKill"#define DOS_DEVICE_NAME L"\\DosDevices\\360SuperKill"NTSTATUS NTAPI VfatBuildRequest (PDEVICE_OBJECT DeviceObject, PIRP Irp);VOID SKillUnloadDriver( IN PDRIVER_OBJECT DriverObject ){ PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject; UNICODE_STRING uniSymLink; RtlInitUnicodeString(&uniSymLink, DOS_DEVICE_NAME); IoDeleteSymbolicLink(&uniSymLink); IoDeleteDevice(deviceObject);}HANDLESkillIoOpenFile(IN PCWSTR FileName,IN ACCESS_MASK DesiredAccess,IN ULONG ShareAccess){ NTSTATUS ntStatus; UNICODE_STRING uniFileName; OBJECT_ATTRIBUTES objectAttributes; HANDLE ntFileHandle; IO_STATUS_BLOCK ioStatus; if (KeGetCurrentIrql() > PASSIVE_LEVEL) { return 0; } RtlInitUnicodeString(&uniFileName, FileName); InitializeObjectAttributes(&objectAttributes, &uniFileName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); ntStatus = IoCreateFile(&ntFileHandle, DesiredAccess, &objectAttributes, &ioStatus, 0, FILE_ATTRIBUTE_NORMAL, ShareAccess, FILE_OPEN, 0, NULL, 0, 0, NULL, IO_NO_PARAMETER_CHECKING); if (!NT_SUCCESS(ntStatus)) { return 0; } return ntFileHandle;}//回呼函數NTSTATUSSkillSetFileCompletion( 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);//釋放IRP return STATUS_MORE_PROCESSING_REQUIRED;}BOOLEAN SKillDeleteFile(IN HANDLE FileHandle){ 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; ntStatus = ObReferenceObjectByHandle(FileHandle, DELETE, *IoFileObjectType, KernelMode, &fileObject, NULL);//開啟檔案的裝置對象 if (!NT_SUCCESS(ntStatus)) { return FALSE; } DeviceObject = IoGetRelatedDeviceObject(fileObject); //返回開啟的對象指標 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE); //分配一個該裝置對象的IRP if (Irp == NULL) { ObDereferenceObject(fileObject); return FALSE; } KeInitializeEvent(&event, SynchronizationEvent, FALSE);//初始化IRP的訊號狀態 FileInformation.DeleteFile = TRUE;//設定IRP 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;//設定完成IPR請求的回呼函數 IoSetCompletionRoutine( Irp, SkillSetFileCompletion, &event, TRUE, TRUE, TRUE); pSectionObjectPointer = fileObject->SectionObjectPointer; pSectionObjectPointer->ImageSectionObject = 0; pSectionObjectPointer->DataSectionObject = 0; IoCallDriver(DeviceObject, Irp); //發送IRP KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, NULL); ObDereferenceObject(fileObject); //關閉裝置對象 return TRUE;}NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ){ UNICODE_STRING uniDeviceName; UNICODE_STRING uniSymLink; NTSTATUS ntStatus; PDEVICE_OBJECT deviceObject = NULL; HANDLE hFileHandle; RtlInitUnicodeString(&uniDeviceName, NT_DEVICE_NAME); RtlInitUnicodeString(&uniSymLink, DOS_DEVICE_NAME); //建立裝置對象 ntStatus = IoCreateDevice( DriverObject, 0, &uniDeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &deviceObject); if (!NT_SUCCESS(ntStatus)) { return ntStatus; } //設定裝置對象的名稱 ntStatus = IoCreateSymbolicLink(&uniSymLink, &uniDeviceName); if (!NT_SUCCESS(ntStatus)) { IoDeleteDevice(deviceObject); return ntStatus; } DriverObject->DriverUnload = SKillUnloadDriver; //開啟檔案 hFileHandle = SkillIoOpenFile(L"\\??\\c:\\calc.exe", FILE_READ_ATTRIBUTES, FILE_SHARE_DELETE); DbgPrint("hFileHandle:%08X/n",hFileHandle); if (hFileHandle!=NULL) { SKillDeleteFile(hFileHandle); //刪除檔案 ZwClose(hFileHandle); } return STATUS_SUCCESS;}
這是一段驅動代碼,需要DDK編譯成驅動檔案。大題的思路我已經用注釋說明,細節部分還有待仔細研究。
菜鳥言論,僅供娛樂。