64位內核開發第8講,文件操作.以及刪除文件.


文件操作,以及強刪文件.

一丶文件操作

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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM