文件操作,以及強刪文件.
一丶文件操作
1.文件操作的幾種方式
操作 |
---|
創建文件/文件夾 |
讀/寫 |
拷貝 |
移動 |
刪除 |
屬性訪問與設置 |
1.2 文件的表示
文件路徑表示表格:
表示層 | 文件路徑表示方法 |
---|---|
Ring3 | L"C:\HelloWorld.txt" |
Ring0 | L"\??\C:\HelloWorld.txt" |
其中兩個 ****是代表一個.代表的是轉義字符.
內核層的兩個??其實是符號鏈接.代表的是是
\device\harddiskvolume3
內核中的文件路徑完整表達是: ** L"\device\harddiskvolume3\HelloWorld.txt**
Ring3跟Ring0的其它路徑.如設備對象.(符號鏈接)
表示層 | 路徑表示 |
---|---|
Ring3設備名 | L"\\.\xxx符號名,或者 \\?\xxx符號名 |
Ring0設備名稱 | L"\device\xxx |
Ring0符號連接名 | L"\dosDevices\xxx符號連接名 或者\??\xxx符號連接 |
二丶文件操作的常見內核API
方法名 | 作用 |
---|---|
ZwCreateFile | 創建文件或者文件夾 |
ZwWriteFile | 寫文件 |
ZwReadFile | 讀文件 |
ZwQueryInfomationFile | 查詢文件 |
ZwQueryFullAttributeFile | 查詢文件 |
ZwSetInfomationFile | 設置文件信息,設置文件大小,設置文件訪問日期.設置屬性隱藏文件.重命名.刪除.對應IRP = Irp_mj_Set_Information. |
ZwClose | 關閉文件句柄 |
ZwQueryDirectoryFile | 枚舉文件跟目錄 |
如ZwCreateFile
NTSTATUS
ZwCreateFile(
__out PHANDLE FileHandle, 文件句柄
__in ACCESS_MASK DesiredAccess, 創建權限
__in POBJECT_ATTRIBUTES ObjectAttributes,文件路徑.這里放文件了解那個
__out PIO_STATUS_BLOCK IoStatusBlock,
__in_opt PLARGE_INTEGER AllocationSize,
__in ULONG FileAttributes,
__in ULONG ShareAccess, 文件是創建還是打開
__in ULONG CreateDisposition,
__in ULONG CreateOptions,
__in_opt PVOID EaBuffer,
__in ULONG EaLength
);
NTSTATUS
ZwReadFile(
IN HANDLE FileHandle, 文件句柄
IN HANDLE Event OPTIONAL, 異步過程調用
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,異步過程
IN PVOID ApcContext OPTIONAL, 異步過程調用
OUT PIO_STATUS_BLOCK IoStatusBlock, 讀寫的IO狀態
OUT PVOID Buffer, 讀寫的Buffer
IN ULONG Length, 讀寫的長度
IN PLARGE_INTEGER ByteOffset OPTIONAL, 讀寫的偏移
IN PULONG Key OPTIONAL
);
查詢文件類型
NTSTATUS
ZwQueryInformationFile(
IN HANDLE FileHandle, 文件句柄
OUT PIO_STATUS_BLOCK IoStatusBlock, IO狀態
OUT PVOID FileInformation, 根據參數四.傳出的一個結構體樂行
IN ULONG Length, 查詢文件類型的長度
IN FILE_INFORMATION_CLASS FileInformationClass 查詢的文件的類型, 你查詢的信息是個結構體.這里放什么上面就放這個信息結構體的大小.
);
上面這個函數簡單來說就是 你參數4傳入一個枚舉類型.表示你想查詢什么類型信息. 然后查詢的信息通過參數3. FileInformation傳出. 你參數4傳入的是什么枚舉.他就會返回查詢的結構體給參數三.
偽代碼:
ZwQueryInfomationFile(hfile,&Iostatus,&FileInformatin,sizeof(FileInforMation),FileBaseicInfoMation
具體信息查詢WDK幫助文檔即可.
設置文件信息
NTSTATUS
ZwSetInformationFile(
IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass 文件的類型
);
跟查詢文件相反.只不過需要我們傳入信息.
比如: 下面就是刪除文件
FILE_DISPOSITION_INFORMATION FileInformation;
ZwSetInformationFile(hfile,&ioStatus,&FileInformation,sizeof(FileInformation),FileDispositionInformation);
三丶內核中三種定義結構體的方式
為什么說這個.因為在上面文件操作.如果你查詢Wdk文檔的話.會看到不同的結構體定義.
如:
typedef struct _FILE_RENAME_INFORMATION {
BOOLEAN ReplaceIfExists;
HANDLE RootDirectory;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;
更改名字的結構體.
可以看到第三個參數 跟第四個參數. 為什么這樣定義.
這樣定義代表這個結構體利用數組可以溢出的原理.設計的一個邊長結構體.
他這個數組的大小根據第三個參數決定.
其余的兩種就很簡單了
struct stack
{
int value
char szBuffer[100]
}
這種類型.我們的szBuffer就是占你給定的大小.
指針類型
struct point
{
int value
char *pszBuffer
}
這種類型則是指針定義.pszBuffer指向一塊地址.
四丶驅動創建文件的完整代碼示例
4.1內核中創建一個文件
#include <ntddk.h>
#include <wdm.h>
#include <ntdef.h>
#include <ntstrsafe.h>
#define DEVICENAME L""
#define SYMBOLICLINKENAME L""
DRIVER_UNLOAD DriverUnload; //函數聲明
NTSTATUS NtDeleteFile(const WCHAR *FileNmae);//刪除文件的第一種方式.
NTSTATUS NtCreateFile(UNICODE_STRING ustr);
NTSTATUS NtCreateFile(UNICODE_STRING ustr)
{
//創建文件
/*
#define InitializeObjectAttributes( p, n, a, r, s ) { \
(p)->Length = sizeof( OBJECT_ATTRIBUTES ); \
(p)->RootDirectory = r; \
(p)->Attributes = a; \
(p)->ObjectName = n; \
(p)->SecurityDescriptor = s; \
(p)->SecurityQualityOfService = NULL; \
}
*/
NTSTATUS NtStatus = 0;
HANDLE hFile;
IO_STATUS_BLOCK io_Status = { 0 };
OBJECT_ATTRIBUTES ObjAttus = { 0 };
InitializeObjectAttributes(&ObjAttus, //初始化ObjAttus結構.
&ustr,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
NtStatus = ZwCreateFile(&hFile,
GENERIC_WRITE,
&ObjAttus,
&io_Status,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN_IF,
FILE_SYNCHRONOUS_IO_ALERT | FILE_NON_DIRECTORY_FILE,
NULL,
0);
if (NT_SUCCESS(NtStatus))
{
//創建成功了
ZwClose(hFile);
}
return NtStatus;
}
void DriverUnload(DRIVER_OBJECT *DriverObject)
{
UNICODE_STRING ustr;
RtlUnicodeStringInit(&ustr,L"Driver UnLoad");
DbgPrint("%wZ",&ustr);
}
NTSTATUS DriverEntry(PDRIVER_OBJECT PdriverObject, PUNICODE_STRING RegistryPath)
{
//創建設備對象
UNICODE_STRING uPrintString = { 0 };
UNICODE_STRING uPathName = { 0 };
NTSTATUS NtStatus;
PdriverObject->DriverUnload = DriverUnload;
RtlUnicodeStringInit(&uPrintString, L"啟動驅動安裝");
DbgPrint("%wZ", &uPrintString);
RtlUnicodeStringInit(&uPathName, L"\\??\\c:\\1.txt");//初始化字符串路徑
NtStatus = NtCreateFile(uPathName);
if (NT_SUCCESS(NtStatus))
{
DbgPrint("創建文件成功");
}
return STATUS_UNSUCCESSFUL;
}
創建完畢截圖:
下面只提供核心接口代碼.直接添加到DLL DriverEntry中即可.
4.1.2 內核中創建文件目錄
傳參的uPathName = L"\\??\\c:\\IBinary\\"
NTSTATUS IBinaryNtCreateDirectory(UNICODE_STRING uPathName)
{
NTSTATUS ntStatus;
HANDLE hFile;
OBJECT_ATTRIBUTES objAttus = { 0 };
IO_STATUS_BLOCK ioStatus = { 0 };
//初始化文件屬性結構體
InitializeObjectAttributes(&objAttus,
&uPathName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL);
ntStatus = ZwCreateFile(&hFile,
GENERIC_READ | GENERIC_WRITE,
&objAttus,
&ioStatus,
NULL,
FILE_ATTRIBUTE_DIRECTORY, //注意這個屬性.我們設置創建文件
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN_IF,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, //表示創建的是目錄,並且是同步執行
NULL,
0);
if (NT_SUCCESS(ntStatus))
{
ZwClose(hFile);
}
return ntStatus;
}
4.1.3內核中寫文件
原理: 使用ZwCreateFile打開文件.獲取文件句柄.然后使用ZwWriteFile寫文件即可.
uPathName = "\\??\\C:\\1.txt"
NTSTATUS IBinaryNtWriteFile(UNICODE_STRING uPathName)
{
//首先打開文件,然后寫入文件.
OBJECT_ATTRIBUTES objAttri = { 0 };
NTSTATUS ntStatus;
HANDLE hFile;
IO_STATUS_BLOCK ioStatus = { 0 };
PVOID pWriteBuffer = NULL;
KdBreakPoint();
InitializeObjectAttributes(&objAttri,
&uPathName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
0);
ntStatus = ZwCreateFile(&hFile,
GENERIC_WRITE | GENERIC_WRITE,
&objAttri,
&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))
{
return ntStatus;
}
//開始寫文件
pWriteBuffer = ExAllocatePoolWithTag(PagedPool, 0x20, "niBI");
if (pWriteBuffer == NULL)
{
DbgPrint("寫文件分配內存出錯");
ZwClose(hFile);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(pWriteBuffer, 0x20);
RtlCopyMemory(pWriteBuffer, L"HelloIBinary", wcslen(L"HelloIBinary"));
ntStatus = ZwWriteFile(hFile,
NULL,
NULL,
NULL,
&ioStatus,
pWriteBuffer,
0x20,
NULL,
NULL);
if (!NT_SUCCESS(ntStatus))
{
ZwClose(hFile);
return STATUS_INSUFFICIENT_RESOURCES;
}
ZwClose(hFile);
ExFreePoolWithTag(pWriteBuffer, "niBI");
return ntStatus;
}
在拷貝字符串的時候我拷貝的是寬字符.所以顯示如上圖.在我們讀文件之前.我稍微修改一下.這里就不在貼出代碼了.
4.1.4內核中讀文件
內核中讀寫文件其實是一樣的.打開一個文件.讀取數據即可.
代碼如下:
uPathName = L"\\??\\c:\\1.txt
傳入了緩沖區.只需要往緩沖區中讀取數據即可.
NTSTATUS IBinaryNtReadFile(PVOID pszBuffer, UNICODE_STRING uPathName)
{
OBJECT_ATTRIBUTES objAttri = { 0 };
NTSTATUS ntStaus;
HANDLE hFile;
IO_STATUS_BLOCK ioStatus = { 0 };
PVOID pReadBuffer = NULL;
if (NULL == pszBuffer)
return STATUS_INTEGER_DIVIDE_BY_ZERO;
//打開文件讀取文件.
InitializeObjectAttributes(&objAttri,
&uPathName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
0);
ntStaus = ZwCreateFile(&hFile,
GENERIC_READ | GENERIC_WRITE,
&objAttri,
&ioStatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
NULL);
if (!NT_SUCCESS(ntStaus))
{
ZwClose(hFile);
if (NULL != pReadBuffer)
ExFreePoolWithTag(pReadBuffer, "niBI");
return STATUS_INTEGER_DIVIDE_BY_ZERO;
}
//讀取文件
pReadBuffer = ExAllocatePoolWithTag(PagedPool, 100, "niBI");
if (NULL == pReadBuffer)
return STATUS_INTEGER_DIVIDE_BY_ZERO;
ntStaus = ZwReadFile(hFile, NULL, NULL, NULL, &ioStatus, pReadBuffer, 100, NULL, NULL);
if (!NT_SUCCESS(ntStaus))
{
ZwClose(hFile);
if (NULL != pReadBuffer)
ExFreePoolWithTag(pReadBuffer, "niBI");
return STATUS_INTEGER_DIVIDE_BY_ZERO;
}
//將讀取的內容拷貝到傳入的緩沖區.
RtlCopyMemory(pszBuffer, pReadBuffer, 100);
ZwClose(hFile);
if (NULL != pReadBuffer)
ExFreePoolWithTag(pReadBuffer, "niBI");
return ntStaus;
}
4.1.4內核中刪除文件的兩種方式
內核中可以刪除文件.有兩種方式.第一種調用 ZwDeleteFile.你需要包含一個 <ntifs.h>頭文件.
但是我包含之后出錯.就沒再深究.自己聲明了一下.
4.1.4.1 內核中刪除文件第一種方式
uDeletePathName = L"\\??\\c:\\1.txt"
#include <ntddk.h>
#include <wdm.h>
#include <ntdef.h>
#include <ntstrsafe.h>
NTSTATUS ZwDeleteFile( IN POBJECT_ATTRIBUTES ObjectAttributes); //函數聲明
NTSTATUS IBinaryNtZwDeleteFile(UNICODE_STRING uDeletePathName)
{
OBJECT_ATTRIBUTES obAttri = { 0 };
//初始化源文件路徑並且打開
InitializeObjectAttributes(&obAttri,
&uDeletePathName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL
);
return ZwDeleteFile(&obAttri);
}
這種方式刪除文件.但是可能刪除失敗.比如文件被獨占打開等等.我沒有進行嘗試.在虛擬機中我就算 打開 1.txt這個文件.當我要刪除這個文件的時候一樣刪除成功.
4.1.4.2 內核中第二種刪除文件方式
這種刪除方式更加厲害. 比如上面我們說的文件可能因為各種因素刪除失敗.所以采用這種方法. 這種方法是使用 內核中的 ZwSetInformationFile設置文件信息從而進行刪除的.
代碼如下:
NTSTATUS IBinaryNtSetInformationFileDeleteFile(UNICODE_STRING uDeletePathName)
{
//刪除文件的第二種方式
/*
思路:
1.初始化文件路徑
2.使用讀寫方式打開文件. 以共享模式打開.
3.如果是拒絕,則以另一種方式打開文件.並且設置這個文件的信息.
4.設置成功之后就可以刪除了.
*/
OBJECT_ATTRIBUTES objAttri;
NTSTATUS ntStatus;
HANDLE hFile;
IO_STATUS_BLOCK ioStatus;
FILE_DISPOSITION_INFORMATION IBdelPostion = { 0 }; //通過ZwSetInformationFile刪除.需要這個結構體
__try
{
InitializeObjectAttributes(&objAttri,
&uDeletePathName,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
ntStatus = ZwCreateFile(&hFile,
DELETE | FILE_WRITE_DATA | SYNCHRONIZE, //注意權限,以刪除權限.寫權限.
&objAttri,
&ioStatus,
NULL,
FILE_ATTRIBUTE_NORMAL, //文件的屬性是默認
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,//文件的共享模式 刪除 讀寫
FILE_OPEN, //文件的打開方式是 打開.如果不存在則返回失敗.
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DELETE_ON_CLOSE, //文件的應用選項,如果是FILE_DELETE_ON_CLOSE則使用ZwClose關閉文件句柄的時候刪除這個文件
NULL,
0
);
if (!NT_SUCCESS(ntStatus))
{
//如果不成功,判斷文件是否拒絕訪問.是的話我們就設置為可以訪問.並且進行刪除.
if (STATUS_ACCESS_DENIED == ntStatus)
{
ntStatus = ZwCreateFile(&hFile,
SYNCHRONIZE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,//刪除權限失敗就以讀寫模式
&objAttri,
&ioStatus,
NULL,
FILE_ATTRIBUTE_NORMAL, //文件的屬性為默認
FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ,//文件的共享屬性為 讀寫刪除
FILE_OPEN, //文件的打開方式為 打開,不存在則失敗
FILE_SYNCHRONOUS_IO_NONALERT, //文件的應用選項.
NULL,
0
);
//如果打開成功了.則設置這個文件的信息
if (NT_SUCCESS(ntStatus))
{
FILE_BASIC_INFORMATION IBFileBasic = { 0 };//
/*
使用ZwQueryInformationfile遍歷文件的信息.這里遍歷的是文件的基本信息
*/
ntStatus = ZwQueryInformationFile(
hFile,
&ioStatus,
&IBFileBasic,
sizeof(IBFileBasic),
FileBasicInformation
);
//遍歷失敗.輸出打印信息
if (!NT_SUCCESS(ntStatus))
DbgPrint("刪除文件失敗,遍歷文件信息出錯 文件名= %wZ", &uDeletePathName);
//設置文件的基本信息
IBFileBasic.FileAttributes = FILE_ATTRIBUTE_NORMAL; //設置屬性為默認屬性
ntStatus = ZwSetInformationFile(
hFile,
&ioStatus,
&IBFileBasic,
sizeof(IBFileBasic),
FileBasicInformation); //將我的FileBasic基本屬性設置到這個文件中
if (!NT_SUCCESS(ntStatus))
DbgPrint("刪除文件失敗,設置文件信息出錯");
//如果成功關閉文件句柄.
ZwClose(hFile);
//重新打開這個設置信息后的文件.
ntStatus = ZwCreateFile(&hFile,
SYNCHRONIZE | FILE_WRITE_DATA | DELETE,
&objAttri,
&ioStatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_DELETE_ON_CLOSE,
NULL,
0);
}
if (!NT_SUCCESS(ntStatus))
DbgPrint("打開文件失敗,刪除失敗");
}
}
//進行強制刪除文件 通過 ZwSetInformationFile
IBdelPostion.DeleteFile = TRUE; //此標志設置為TRUE即可刪除
ntStatus = ZwSetInformationFile(hFile, &ioStatus, &IBdelPostion, sizeof(IBdelPostion), FileDispositionInformation);
if (!NT_SUCCESS(ntStatus))
{
ZwClose(hFile);
DbgPrint("刪除文件失敗,設置文件信息出錯");
return ntStatus;
}
ZwClose(hFile);
}
__except (1)
{
DbgPrint("刪除文件出現異常");
}
return ntStatus;
}