欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言驅(qū)動(dòng)開發(fā)之內(nèi)核文件的讀寫

 更新時(shí)間:2023年06月09日 10:48:09   作者:lyshark  
這篇文章主要為大家詳細(xì)介紹了C語言驅(qū)動(dòng)開發(fā)中內(nèi)核文件的讀寫的系列函數(shù),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

在應(yīng)用層下的文件操作只需要調(diào)用微軟應(yīng)用層下的API函數(shù)及C庫標(biāo)準(zhǔn)函數(shù)即可,而如果在內(nèi)核中讀寫文件則應(yīng)用層的API顯然是無法被使用的,內(nèi)核層需要使用內(nèi)核專有API,某些應(yīng)用層下的API只需要增加Zw開頭即可在內(nèi)核中使用,例如本章要講解的文件與目錄操作相關(guān)函數(shù),多數(shù)ARK反內(nèi)核工具都具有對(duì)文件的管理功能,實(shí)現(xiàn)對(duì)文件或目錄的基本操作功能也是非常有必要的。

首先無論在內(nèi)核態(tài)還是在用戶態(tài),我們調(diào)用的文件操作函數(shù)其最終都會(huì)轉(zhuǎn)換為一個(gè)IRP請(qǐng)求,并發(fā)送到文件系統(tǒng)驅(qū)動(dòng)上的IRP_MJ_READ派遣函數(shù)里面,這個(gè)讀寫流程大體上可分為如下四步;

  • 對(duì)于FAT32分區(qū)會(huì)默認(rèn)分發(fā)到FASTFAT.SYS,而相對(duì)于NTFS分區(qū)則會(huì)分發(fā)到NTFS.SYS驅(qū)動(dòng)上。
  • 文件系統(tǒng)驅(qū)動(dòng)經(jīng)過處理后,就把IRP傳給磁盤類驅(qū)動(dòng)的IRP_MJ_READ分發(fā)函數(shù)處理,當(dāng)磁盤類驅(qū)動(dòng)處理完畢后,又把IRP傳給磁盤小端口驅(qū)動(dòng)。
  • 在磁盤小端口驅(qū)動(dòng)里,無論是讀還是寫,用的都是IRP_MJ_SCSI這個(gè)分發(fā)函數(shù)。
  • IRP被磁盤小端口驅(qū)動(dòng)處理完之后,就要依靠HAL.DLL進(jìn)行端口IO,此時(shí)數(shù)據(jù)就真的從硬盤里讀取了出來。

創(chuàng)建文件或目錄

實(shí)現(xiàn)創(chuàng)建文件或目錄,創(chuàng)建文件或目錄都可調(diào)用ZwCreateFile()這個(gè)內(nèi)核函數(shù)來實(shí)現(xiàn),唯一不同的區(qū)別在于當(dāng)用戶傳入?yún)?shù)中包含有FILE_SYNCHRONOUS_IO_NONALERT屬性時(shí)則會(huì)默認(rèn)創(chuàng)建文件,而如果包含有FILE_DIRECTORY_FILE屬性則默認(rèn)為創(chuàng)建目錄,該函數(shù)的微軟定義以及備注信息如下所示;

NTSYSAPI NTSTATUS ZwCreateFile(
  [out]          PHANDLE            FileHandle,        // 指向HANDLE變量的指針,該變量接收文件的句柄。
  [in]           ACCESS_MASK        DesiredAccess,     // 指定一個(gè)ACCESS_MASK值,該值確定對(duì)對(duì)象的請(qǐng)求訪問權(quán)限。
  [in]           POBJECT_ATTRIBUTES ObjectAttributes,  // 指向OBJECT_ATTRIBUTES結(jié)構(gòu)的指針,該結(jié)構(gòu)指定對(duì)象名稱和其他屬性。
  [out]          PIO_STATUS_BLOCK   IoStatusBlock,     // 指向IO_STATUS_BLOCK結(jié)構(gòu)的指針,該結(jié)構(gòu)接收最終完成狀態(tài)和有關(guān)所請(qǐng)求操作的其他信息。 
  [in, optional] PLARGE_INTEGER     AllocationSize,    // 指向LARGE_INTEGER的指針,其中包含創(chuàng)建或覆蓋的文件的初始分配大小(以字節(jié)為單位)。
  [in]           ULONG              FileAttributes,    // 指定一個(gè)或多個(gè)FILE_ATTRIBUTE_XXX標(biāo)志,這些標(biāo)志表示在創(chuàng)建或覆蓋文件時(shí)要設(shè)置的文件屬性。
  [in]           ULONG              ShareAccess,       // 共享訪問的類型,指定為零或以下標(biāo)志的任意組合。
  [in]           ULONG              CreateDisposition, // 指定在文件存在或不存在時(shí)要執(zhí)行的操作。
  [in]           ULONG              CreateOptions,     // 指定要在驅(qū)動(dòng)程序創(chuàng)建或打開文件時(shí)應(yīng)用的選項(xiàng)。
  [in, optional] PVOID              EaBuffer,          // 對(duì)于設(shè)備和中間驅(qū)動(dòng)程序,此參數(shù)必須是NULL指針。
  [in]           ULONG              EaLength           // 對(duì)于設(shè)備和中間驅(qū)動(dòng)程序,此參數(shù)必須為零。
);

參數(shù)DesiredAccess用于指明對(duì)象訪問權(quán)限的,常用的權(quán)限有FILE_READ_DATA讀取文件,FILE_WRITE_DATA寫入文件,FILE_APPEND_DATA追加文件,FILE_READ_ATTRIBUTES讀取文件屬性,以及FILE_WRITE_ATTRIBUTES寫入文件屬性。

參數(shù)ObjectAttributes指向了一個(gè)OBJECT_ATTRIBUTES指針,通常會(huì)通過InitializeObjectAttributes()宏對(duì)其進(jìn)行初始化,當(dāng)一個(gè)例程打開對(duì)象時(shí)由此結(jié)構(gòu)體指定目標(biāo)對(duì)象的屬性。

參數(shù)ShareAccess用于指定訪問屬性,通常屬性有FILE_SHARE_READ讀取,FILE_SHARE_WRITE寫入,FILE_SHARE_DELETE刪除。

參數(shù)CreateDisposition用于指定在文件存在或不存在時(shí)要執(zhí)行的操作,一般而言我們會(huì)指定為FILE_OPEN_IF打開文件,或FILE_OVERWRITE_IF打開文件并覆蓋,FILE_SUPERSEDE替換文件。

參數(shù)CreateOptions用于指定創(chuàng)建文件或目錄,一般FILE_SYNCHRONOUS_IO_NONALERT代表創(chuàng)建文件,參數(shù)FILE_DIRECTORY_FILE代表創(chuàng)建目錄。

相對(duì)于創(chuàng)建文件而言刪除文件或目錄只需要調(diào)用ZwDeleteFile()系列函數(shù)即可,此類函數(shù)只需要傳遞一個(gè)OBJECT_ATTRIBUTES參數(shù)即可,其微軟定義如下所示;

NTSYSAPI NTSTATUS ZwDeleteFile(
  [in] POBJECT_ATTRIBUTES ObjectAttributes
);

接下來我們就封裝三個(gè)函數(shù)MyCreateFile()用于創(chuàng)建文件,MyCreateFileFolder()用于創(chuàng)建目錄,MyDeleteFileOrFileFolder()用于刪除空目錄。

// 署名權(quán)
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include <ntifs.h>
#include <ntstrsafe.h>
// 創(chuàng)建文件
BOOLEAN MyCreateFile(UNICODE_STRING ustrFilePath)
{
	HANDLE hFile = NULL;
	OBJECT_ATTRIBUTES objectAttributes = { 0 };
	IO_STATUS_BLOCK iosb = { 0 };
	NTSTATUS status = STATUS_SUCCESS;
	// 初始化對(duì)象屬性結(jié)構(gòu)體 FILE_SYNCHRONOUS_IO_NONALERT
	InitializeObjectAttributes(&objectAttributes, &ustrFilePath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
	// 創(chuàng)建文件
	status = ZwCreateFile(&hFile, GENERIC_READ, &objectAttributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
	if (!NT_SUCCESS(status))
	{
		return FALSE;
	}
	// 關(guān)閉句柄
	ZwClose(hFile);
	return TRUE;
}
// 創(chuàng)建目錄
BOOLEAN MyCreateFileFolder(UNICODE_STRING ustrFileFolderPath)
{
	HANDLE hFile = NULL;
	OBJECT_ATTRIBUTES objectAttributes = { 0 };
	IO_STATUS_BLOCK iosb = { 0 };
	NTSTATUS status = STATUS_SUCCESS;
	// 初始化對(duì)象屬性結(jié)構(gòu)體
	InitializeObjectAttributes(&objectAttributes, &ustrFileFolderPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
	// 創(chuàng)建目錄 FILE_DIRECTORY_FILE
	status = ZwCreateFile(&hFile, GENERIC_READ, &objectAttributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_CREATE, FILE_DIRECTORY_FILE, NULL, 0);
	if (!NT_SUCCESS(status))
	{
		return FALSE;
	}
	// 關(guān)閉句柄
	ZwClose(hFile);
	return TRUE;
}
// 刪除文件或是空目錄
BOOLEAN MyDeleteFileOrFileFolder(UNICODE_STRING ustrFileName)
{
	NTSTATUS status = STATUS_SUCCESS;
	OBJECT_ATTRIBUTES objectAttributes = { 0 };
	// 初始化屬性
	InitializeObjectAttributes(&objectAttributes, &ustrFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
	// 執(zhí)行刪除操作
	status = ZwDeleteFile(&objectAttributes);
	if (!NT_SUCCESS(status))
	{
		return FALSE;
	}
	return TRUE;
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
	BOOLEAN ref = FALSE;
	// 刪除文件
	UNICODE_STRING ustrDeleteFile;
	RtlInitUnicodeString(&ustrDeleteFile, L"\\??\\C:\\LySharkFolder\\lyshark.txt");
	ref = MyDeleteFileOrFileFolder(ustrDeleteFile);
	if (ref != FALSE)
	{
		DbgPrint("[LyShark] 刪除文件成功 \n");
	}
	else
	{
		DbgPrint("[LyShark] 刪除文件失敗 \n");
	}
	// 刪除空目錄
	UNICODE_STRING ustrDeleteFilder;
	RtlInitUnicodeString(&ustrDeleteFilder, L"\\??\\C:\\LySharkFolder");
	ref = MyDeleteFileOrFileFolder(ustrDeleteFilder);
	if (ref != FALSE)
	{
		DbgPrint("[LyShark] 刪除空目錄成功 \n");
	}
	else
	{
		DbgPrint("[LyShark] 刪除空目錄失敗 \n");
	}
	DbgPrint("驅(qū)動(dòng)卸載 \n");
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
	DbgPrint("hello lyshark.com \n");
	BOOLEAN ref = FALSE;
	// 創(chuàng)建目錄
	UNICODE_STRING ustrDirectory;
	RtlInitUnicodeString(&ustrDirectory, L"\\??\\C:\\LySharkFolder");
	ref = MyCreateFileFolder(ustrDirectory);
	if (ref != FALSE)
	{
		DbgPrint("[LyShark] 創(chuàng)建目錄成功 \n");
	}
	else
	{
		DbgPrint("[LyShark] 創(chuàng)建文件失敗 \n");
	}
	// 創(chuàng)建文件
	UNICODE_STRING ustrCreateFile;
	RtlInitUnicodeString(&ustrCreateFile, L"\\??\\C:\\LySharkFolder\\lyshark.txt");
	ref = MyCreateFile(ustrCreateFile);
	if (ref != FALSE)
	{
		DbgPrint("[LyShark] 創(chuàng)建文件成功 \n");
	}
	else
	{
		DbgPrint("[LyShark] 創(chuàng)建文件失敗 \n");
	}
	Driver->DriverUnload = UnDriver;
	return STATUS_SUCCESS;
}

運(yùn)行如上代碼,分別創(chuàng)建LySharkFolder目錄,并在其中創(chuàng)建lyshark.txt最終再將其刪除,輸出效果如下;

重命名文·件或目錄

在內(nèi)核中重命名文件或目錄核心功能的實(shí)現(xiàn)依賴于ZwSetInformationFile()這個(gè)內(nèi)核函數(shù),該函數(shù)可用于更改有關(guān)文件對(duì)象的各種信息,其微軟官方定義如下;

NTSYSAPI NTSTATUS ZwSetInformationFile(
  [in]  HANDLE                 FileHandle,          // 文件句柄
  [out] PIO_STATUS_BLOCK       IoStatusBlock,       // 指向 IO_STATUS_BLOCK 結(jié)構(gòu)的指針
  [in]  PVOID                  FileInformation,     // 指向緩沖區(qū)的指針,該緩沖區(qū)包含要為文件設(shè)置的信息。
  [in]  ULONG                  Length,              // 緩沖區(qū)的大小(以字節(jié)為單位)
  [in]  FILE_INFORMATION_CLASS FileInformationClass // 為文件設(shè)置的類型
);

這其中最重要的參數(shù)就是FileInformationClass根據(jù)該參數(shù)的不同則對(duì)文件的操作方式也就不同,如果需要重命名文件則此處應(yīng)使用FileRenameInformation而如果需要修改文件的當(dāng)前信息則應(yīng)使用FilePositionInformation創(chuàng)建鏈接文件則使用FileLinkInformation即可,以重命名為例,首先我們需要定義一個(gè)FILE_RENAME_INFORMATION結(jié)構(gòu)并按照要求填充,最后直接使用ZwSetInformationFile()并傳入相關(guān)信息后即可完成修改,其完整代碼流程如下;

// 署名權(quán)
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include <ntifs.h>
#include <ntstrsafe.h>
// 重命名文件或文件夾
BOOLEAN MyRename(UNICODE_STRING ustrSrcFileName, UNICODE_STRING ustrDestFileName)
{
	HANDLE hFile = NULL;
	OBJECT_ATTRIBUTES objectAttributes = { 0 };
	IO_STATUS_BLOCK iosb = { 0 };
	NTSTATUS status = STATUS_SUCCESS;
	PFILE_RENAME_INFORMATION pRenameInfo = NULL;
	ULONG ulLength = (1024 + sizeof(FILE_RENAME_INFORMATION));
	// 為PFILE_RENAME_INFORMATION結(jié)構(gòu)申請(qǐng)內(nèi)存
	pRenameInfo = (PFILE_RENAME_INFORMATION)ExAllocatePool(NonPagedPool, ulLength);
	if (NULL == pRenameInfo)
	{
		return FALSE;
	}
	// 設(shè)置重命名信息
	RtlZeroMemory(pRenameInfo, ulLength);
	// 設(shè)置文件名長度以及文件名
	pRenameInfo->FileNameLength = ustrDestFileName.Length;
	wcscpy(pRenameInfo->FileName, ustrDestFileName.Buffer);
	pRenameInfo->ReplaceIfExists = 0;
	pRenameInfo->RootDirectory = NULL;
	// 初始化結(jié)構(gòu)
	InitializeObjectAttributes(&objectAttributes, &ustrSrcFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
	// 打開文件
	status = ZwCreateFile(&hFile, SYNCHRONIZE | DELETE, &objectAttributes, &iosb, NULL, 0, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT | FILE_NO_INTERMEDIATE_BUFFERING, NULL, 0);
	if (!NT_SUCCESS(status))
	{
		ExFreePool(pRenameInfo);
		return FALSE;
	}
	// 利用ZwSetInformationFile來設(shè)置文件信息
	status = ZwSetInformationFile(hFile, &iosb, pRenameInfo, ulLength, FileRenameInformation);
	if (!NT_SUCCESS(status))
	{
		ZwClose(hFile);
		ExFreePool(pRenameInfo);
		return FALSE;
	}
	// 釋放內(nèi)存,關(guān)閉句柄
	ExFreePool(pRenameInfo);
	ZwClose(hFile);
	return TRUE;
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
	DbgPrint("驅(qū)動(dòng)卸載 \n");
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
	DbgPrint("hello lyshark.com \n");
	// 重命名文件
	UNICODE_STRING ustrOldFile, ustrNewFile;
	RtlInitUnicodeString(&ustrOldFile, L"\\??\\C:\\MyCreateFolder\\lyshark.txt");
	RtlInitUnicodeString(&ustrNewFile, L"\\??\\C:\\MyCreateFolder\\hello_lyshark.txt");
	BOOLEAN ref = MyRename(ustrOldFile, ustrNewFile);
	if (ref == TRUE)
	{
		DbgPrint("已完成改名 \n");
	}
	Driver->DriverUnload = UnDriver;
	return STATUS_SUCCESS;
}

運(yùn)行后將會(huì)把C:\\MyCreateFolder\\lyshark.txt目錄下的文件改名為hello_lyshark.txt,前提是該目錄與該文件必須存在;

那么如果你需要將文件設(shè)置為只讀模式或修改文件的創(chuàng)建日期,那么你就需要看一下微軟的定義FILE_BASIC_INFORMATION結(jié)構(gòu),依次填充此結(jié)構(gòu)體并調(diào)用ZwSetInformationFile()即可實(shí)現(xiàn)修改,該結(jié)構(gòu)的定義如下所示;

typedef struct _FILE_BASIC_INFORMATION {
    LARGE_INTEGER CreationTime;
    LARGE_INTEGER LastAccessTime;
    LARGE_INTEGER LastWriteTime;
    LARGE_INTEGER ChangeTime;
    ULONG FileAttributes;
} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;

當(dāng)然如果你要修改日期你還需要自行填充LARGE_INTEGER結(jié)構(gòu),該結(jié)構(gòu)的微軟定義如下所示,分為高位和低位依次填充即可;

#if defined(MIDL_PASS)
typedef struct _LARGE_INTEGER {
#else // MIDL_PASS
typedef union _LARGE_INTEGER {
    struct {
        ULONG LowPart;
        LONG HighPart;
    } DUMMYSTRUCTNAME;
    struct {
        ULONG LowPart;
        LONG HighPart;
    } u;
#endif //MIDL_PASS
    LONGLONG QuadPart;
} LARGE_INTEGER;

我們就以修改文件屬性為只讀模式為例,其核心代碼可以被描述為如下樣子,相比于改名而言其唯一的變化就是更換了PFILE_BASIC_INFORMATION結(jié)構(gòu)體,其他的基本一致;

HANDLE hFile = NULL;
OBJECT_ATTRIBUTES objectAttributes = { 0 };
IO_STATUS_BLOCK iosb = { 0 };
NTSTATUS status = STATUS_SUCCESS;
PFILE_BASIC_INFORMATION pReplaceInfo = NULL;
ULONG ulLength = (1024 + sizeof(FILE_BASIC_INFORMATION));
// 為FILE_POSITION_INFORMATION結(jié)構(gòu)申請(qǐng)內(nèi)存
pReplaceInfo = (PFILE_BASIC_INFORMATION)ExAllocatePool(NonPagedPool, ulLength);
if (NULL == pReplaceInfo)
{
  return FALSE;
}
RtlZeroMemory(pReplaceInfo, ulLength);
// 設(shè)置文件基礎(chǔ)信息,將文件設(shè)置為只讀模式
pReplaceInfo->FileAttributes |= FILE_ATTRIBUTE_READONLY;

讀取文件大小

讀取特定文件的所占空間,核心原理是調(diào)用了ZwQueryInformationFile()這個(gè)內(nèi)核函數(shù),該函數(shù)可以返回有關(guān)文件對(duì)象的各種信息,參數(shù)傳遞上與ZwSetInformationFile()很相似,其FileInformationClass都需要傳入一個(gè)文件類型結(jié)構(gòu),該函數(shù)的完整定義如下;

NTSYSAPI NTSTATUS ZwQueryInformationFile(
  [in]  HANDLE                 FileHandle,          // 文件句柄。
  [out] PIO_STATUS_BLOCK       IoStatusBlock,       // 指向接收最終完成狀態(tài)和操作相關(guān)信息的 IO_STATUS_BLOCK 結(jié)構(gòu)的指針。
  [out] PVOID                  FileInformation,     // 指向調(diào)用方分配的緩沖區(qū)的指針,例程將請(qǐng)求的有關(guān)文件對(duì)象的信息寫入其中。
  [in]  ULONG                  Length,              // 長度。
  [in]  FILE_INFORMATION_CLASS FileInformationClass // 指定要在 FileInformation 指向的緩沖區(qū)中返回的有關(guān)文件的信息類型。
);

本例中我們需要讀入文件的所占字節(jié)數(shù),那么FileInformation字段就需要傳入FileStandardInformation來獲取文件的基本信息,獲取到的信息會(huì)被存儲(chǔ)到FILE_STANDARD_INFORMATION結(jié)構(gòu)內(nèi),用戶只需要解析該結(jié)構(gòu)體fsi.EndOfFile.QuadPart即可得到文件長度,其完整代碼如下所示;

// 署名權(quán)
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include <ntifs.h>
#include <ntstrsafe.h>
// 獲取文件大小
ULONG64 MyGetFileSize(UNICODE_STRING ustrFileName)
{
	HANDLE hFile = NULL;
	OBJECT_ATTRIBUTES objectAttributes = { 0 };
	IO_STATUS_BLOCK iosb = { 0 };
	NTSTATUS status = STATUS_SUCCESS;
	FILE_STANDARD_INFORMATION fsi = { 0 };
	// 初始化結(jié)構(gòu)
	InitializeObjectAttributes(&objectAttributes, &ustrFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
	// 打開文件
	status = ZwCreateFile(&hFile, GENERIC_READ, &objectAttributes, &iosb, NULL, 0, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
	if (!NT_SUCCESS(status))
	{
		return 0;
	}
	// 獲取文件大小信息
	status = ZwQueryInformationFile(hFile, &iosb, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation);
	if (!NT_SUCCESS(status))
	{
		ZwClose(hFile);
		return 0;
	}
	return fsi.EndOfFile.QuadPart;
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
	DbgPrint("驅(qū)動(dòng)卸載 \n");
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
	DbgPrint("hello lyshark.com \n");
	// 獲取文件大小
	UNICODE_STRING ustrFileSize;
	RtlInitUnicodeString(&ustrFileSize, L"\\??\\C:\\lyshark.exe");
	ULONG64 ullFileSize = MyGetFileSize(ustrFileSize);
	DbgPrint("獲取文件大小: %I64d Bytes \n", ullFileSize);
	Driver->DriverUnload = UnDriver;
	return STATUS_SUCCESS;
}

編譯并運(yùn)行如上程序,即可讀取到C盤下的lyshark.exe程序的大小字節(jié)數(shù),如下圖所示;

內(nèi)核文件讀寫

內(nèi)核讀取文件可以使用ZwReadFile(),內(nèi)核寫入文件則可使用ZwWriteFile(),這兩個(gè)函數(shù)的參數(shù)傳遞基本上一致,如下是讀寫兩個(gè)函數(shù)的對(duì)比參數(shù)。

NTSYSAPI NTSTATUS ZwReadFile(
  [in]           HANDLE           FileHandle,      // 文件對(duì)象的句柄。
  [in, optional] HANDLE           Event,           // (可選)事件對(duì)象的句柄,在讀取操作完成后設(shè)置為信號(hào)狀態(tài)。
  [in, optional] PIO_APC_ROUTINE  ApcRoutine,      // 此參數(shù)為保留參數(shù)。
  [in, optional] PVOID            ApcContext,      // 此參數(shù)為保留參數(shù)。
  [out]          PIO_STATUS_BLOCK IoStatusBlock,   // 接收實(shí)際從文件讀取的字節(jié)數(shù)。
  [out]          PVOID            Buffer,          // 指向調(diào)用方分配的緩沖區(qū)的指針,該緩沖區(qū)接收從文件讀取的數(shù)據(jù)。
  [in]           ULONG            Length,          // 緩沖區(qū)指向的緩沖區(qū)的大小(以字節(jié)為單位)。
  [in, optional] PLARGE_INTEGER   ByteOffset,      // 指定將開始讀取操作的文件中的起始字節(jié)偏移量。
  [in, optional] PULONG           Key
);
NTSYSAPI NTSTATUS ZwWriteFile(
  [in]           HANDLE           FileHandle,
  [in, optional] HANDLE           Event,
  [in, optional] PIO_APC_ROUTINE  ApcRoutine,
  [in, optional] PVOID            ApcContext,
  [out]          PIO_STATUS_BLOCK IoStatusBlock,
  [in]           PVOID            Buffer,
  [in]           ULONG            Length,
  [in, optional] PLARGE_INTEGER   ByteOffset,
  [in, optional] PULONG           Key
);

讀取文件的代碼如下所示,分配非分頁pBuffer內(nèi)存,然后調(diào)用MyReadFile()函數(shù),將數(shù)據(jù)讀入到pBuffer并輸出,完整代碼如下所示;

// 署名權(quán)
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include <ntifs.h>
#include <ntstrsafe.h>
// 讀取文件數(shù)據(jù)
BOOLEAN MyReadFile(UNICODE_STRING ustrFileName, LARGE_INTEGER liOffset, PUCHAR pReadData, PULONG pulReadDataSize)
{
	HANDLE hFile = NULL;
	IO_STATUS_BLOCK iosb = { 0 };
	OBJECT_ATTRIBUTES objectAttributes = { 0 };
	NTSTATUS status = STATUS_SUCCESS;
	// 初始化結(jié)構(gòu)
	InitializeObjectAttributes(&objectAttributes, &ustrFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
	// 打開文件
	status = ZwCreateFile(&hFile, GENERIC_READ, &objectAttributes, &iosb, NULL,FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN,FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
	if (!NT_SUCCESS(status))
	{
		return FALSE;
	}
	// 初始化
	RtlZeroMemory(&iosb, sizeof(iosb));
	// 讀入文件
	status = ZwReadFile(hFile, NULL, NULL, NULL, &iosb, pReadData, *pulReadDataSize, &liOffset, NULL);
	if (!NT_SUCCESS(status))
	{
		*pulReadDataSize = iosb.Information;
		ZwClose(hFile);
		return FALSE;
	}
	// 獲取實(shí)際讀取的數(shù)據(jù)
	*pulReadDataSize = iosb.Information;
	// 關(guān)閉句柄
	ZwClose(hFile);
	return TRUE;
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
	DbgPrint("驅(qū)動(dòng)卸載 \n");
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
	DbgPrint("hello lyshark.com \n");
	UNICODE_STRING ustrScrFile;
	ULONG ulBufferSize = 40960;
	LARGE_INTEGER liOffset = { 0 };
	// 初始化需要讀取的文件名
	RtlInitUnicodeString(&ustrScrFile, L"\\??\\C:\\lyshark.exe");
	// 分配非分頁內(nèi)存
	PUCHAR pBuffer = ExAllocatePool(NonPagedPool, ulBufferSize);
	// 讀取文件
	MyReadFile(ustrScrFile, liOffset, pBuffer, &ulBufferSize);
	// 輸出文件前16個(gè)字節(jié)
	for (size_t i = 0; i < 16; i++)
	{
		DbgPrint("%02X \n", pBuffer[i]);
	}
	Driver->DriverUnload = UnDriver;
	return STATUS_SUCCESS;
}

編譯并運(yùn)行這段代碼,并循環(huán)輸出lyshark.exe文件的頭16個(gè)字節(jié)的數(shù)據(jù),效果圖如下所示;

文件寫入MyWriteFile()與讀取類似,如下通過運(yùn)用文件讀寫實(shí)現(xiàn)了文件拷貝功能,實(shí)現(xiàn)完整代碼如下所示;

// 署名權(quán)
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include <ntifs.h>
#include <ntstrsafe.h>
// 讀取文件數(shù)據(jù)
BOOLEAN MyReadFile(UNICODE_STRING ustrFileName, LARGE_INTEGER liOffset, PUCHAR pReadData, PULONG pulReadDataSize)
{
	HANDLE hFile = NULL;
	IO_STATUS_BLOCK iosb = { 0 };
	OBJECT_ATTRIBUTES objectAttributes = { 0 };
	NTSTATUS status = STATUS_SUCCESS;
	// 初始化結(jié)構(gòu)
	InitializeObjectAttributes(&objectAttributes, &ustrFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
	// 打開文件
	status = ZwCreateFile(&hFile, GENERIC_READ, &objectAttributes, &iosb, NULL,FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN,FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
	if (!NT_SUCCESS(status))
	{
		return FALSE;
	}
	// 初始化
	RtlZeroMemory(&iosb, sizeof(iosb));
	// 讀入文件
	status = ZwReadFile(hFile, NULL, NULL, NULL, &iosb, pReadData, *pulReadDataSize, &liOffset, NULL);
	if (!NT_SUCCESS(status))
	{
		*pulReadDataSize = iosb.Information;
		ZwClose(hFile);
		return FALSE;
	}
	// 獲取實(shí)際讀取的數(shù)據(jù)
	*pulReadDataSize = iosb.Information;
	// 關(guān)閉句柄
	ZwClose(hFile);
	return TRUE;
}
// 向文件寫入數(shù)據(jù)
BOOLEAN MyWriteFile(UNICODE_STRING ustrFileName, LARGE_INTEGER liOffset, PUCHAR pWriteData, PULONG pulWriteDataSize)
{
	HANDLE hFile = NULL;
	IO_STATUS_BLOCK iosb = { 0 };
	OBJECT_ATTRIBUTES objectAttributes = { 0 };
	NTSTATUS status = STATUS_SUCCESS;
	// 初始化結(jié)構(gòu)
	InitializeObjectAttributes(&objectAttributes, &ustrFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
	// 打開文件
	status = ZwCreateFile(&hFile, GENERIC_WRITE, &objectAttributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
	if (!NT_SUCCESS(status))
	{
		return FALSE;
	}
	// 初始化
	RtlZeroMemory(&iosb, sizeof(iosb));
	// 寫出文件
	status = ZwWriteFile(hFile, NULL, NULL, NULL, &iosb, pWriteData, *pulWriteDataSize, &liOffset, NULL);
	if (!NT_SUCCESS(status))
	{
		*pulWriteDataSize = iosb.Information;
		ZwClose(hFile);
		return FALSE;
	}
	// 獲取實(shí)際寫入的數(shù)據(jù)
	*pulWriteDataSize = iosb.Information;
	// 關(guān)閉句柄
	ZwClose(hFile);
	return TRUE;
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
	DbgPrint("驅(qū)動(dòng)卸載 \n");
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
	DbgPrint("hello lyshark.com \n");
	// 文件讀寫
	UNICODE_STRING ustrScrFile, ustrDestFile;
	RtlInitUnicodeString(&ustrScrFile, L"\\??\\C:\\lyshark.exe");
	RtlInitUnicodeString(&ustrDestFile, L"\\??\\C:\\LyShark\\new_lyshark.exe");
	ULONG ulBufferSize = 40960;
	ULONG ulReadDataSize = ulBufferSize;
	LARGE_INTEGER liOffset = { 0 };
	// 分配非分頁內(nèi)存
	PUCHAR pBuffer = ExAllocatePool(NonPagedPool, ulBufferSize);
	do
	{
		// 讀取文件
		ulReadDataSize = ulBufferSize;
		MyReadFile(ustrScrFile, liOffset, pBuffer, &ulReadDataSize);
		// 數(shù)據(jù)為空則讀取結(jié)束
		if (0 >= ulReadDataSize)
		{
			break;
		}
		// 寫入文件
		MyWriteFile(ustrDestFile, liOffset, pBuffer, &ulReadDataSize);
		// 更新偏移
		liOffset.QuadPart = liOffset.QuadPart + ulReadDataSize;
		DbgPrint("[+] 更新偏移: %d \n", liOffset.QuadPart);
	} while (TRUE);
	// 釋放內(nèi)存
	ExFreePool(pBuffer);
	DbgPrint("[*] 已將文件復(fù)制到新目錄 \n");
	Driver->DriverUnload = UnDriver;
	return STATUS_SUCCESS;
}

編譯并運(yùn)行這段程序,則自動(dòng)將C:\\lyshark.exe盤符下的文件拷貝到C:\\LyShark\\new_lyshark.exe目錄下,實(shí)現(xiàn)效果圖如下所示;

實(shí)現(xiàn)文件讀寫傳遞

通過如上學(xué)習(xí)相信你已經(jīng)掌握了如何使用文件讀寫系列函數(shù)了,接下來將封裝一個(gè)文件讀寫驅(qū)動(dòng),應(yīng)用層接收,驅(qū)動(dòng)層讀??;

此驅(qū)動(dòng)部分完整代碼如下所示;

// 署名權(quán)
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include <ntifs.h>
#include <windef.h>
#define READ_FILE_SIZE_CODE CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ALL_ACCESS)
#define READ_FILE_CODE CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ALL_ACCESS)
#define DEVICENAME L"\\Device\\ReadWriteDevice"
#define SYMBOLNAME L"\\??\\ReadWriteSymbolName"
typedef struct
{
	ULONG64 size;      // 讀寫長度
	BYTE* data;        // 讀寫數(shù)據(jù)集
}FileData;
// 獲取文件大小
ULONG64 MyGetFileSize(UNICODE_STRING ustrFileName)
{
	HANDLE hFile = NULL;
	OBJECT_ATTRIBUTES objectAttributes = { 0 };
	IO_STATUS_BLOCK iosb = { 0 };
	NTSTATUS status = STATUS_SUCCESS;
	FILE_STANDARD_INFORMATION fsi = { 0 };
	// 初始化結(jié)構(gòu)
	InitializeObjectAttributes(&objectAttributes, &ustrFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
	// 打開文件
	status = ZwCreateFile(&hFile, GENERIC_READ, &objectAttributes, &iosb, NULL, 0, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
	if (!NT_SUCCESS(status))
	{
		return 0;
	}
	// 獲取文件大小信息
	status = ZwQueryInformationFile(hFile, &iosb, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation);
	if (!NT_SUCCESS(status))
	{
		ZwClose(hFile);
		return 0;
	}
	return fsi.EndOfFile.QuadPart;
}
// 讀取文件數(shù)據(jù)
BOOLEAN MyReadFile(UNICODE_STRING ustrFileName, LARGE_INTEGER liOffset, PUCHAR pReadData, PULONG pulReadDataSize)
{
	HANDLE hFile = NULL;
	IO_STATUS_BLOCK iosb = { 0 };
	OBJECT_ATTRIBUTES objectAttributes = { 0 };
	NTSTATUS status = STATUS_SUCCESS;
	// 初始化結(jié)構(gòu)
	InitializeObjectAttributes(&objectAttributes, &ustrFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
	// 打開文件
	status = ZwCreateFile(&hFile, GENERIC_READ, &objectAttributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
	if (!NT_SUCCESS(status))
	{
		return FALSE;
	}
	// 初始化
	RtlZeroMemory(&iosb, sizeof(iosb));
	// 讀入文件
	status = ZwReadFile(hFile, NULL, NULL, NULL, &iosb, pReadData, *pulReadDataSize, &liOffset, NULL);
	if (!NT_SUCCESS(status))
	{
		*pulReadDataSize = iosb.Information;
		ZwClose(hFile);
		return FALSE;
	}
	// 獲取實(shí)際讀取的數(shù)據(jù)
	*pulReadDataSize = iosb.Information;
	// 關(guān)閉句柄
	ZwClose(hFile);
	return TRUE;
}
NTSTATUS DriverIrpCtl(PDEVICE_OBJECT device, PIRP pirp)
{
	PIO_STACK_LOCATION stack;
	stack = IoGetCurrentIrpStackLocation(pirp);
	FileData* FileDataPtr;
	switch (stack->MajorFunction)
	{
	case IRP_MJ_CREATE:
	{
		break;
	}
	case IRP_MJ_CLOSE:
	{
		break;
	}
	case IRP_MJ_DEVICE_CONTROL:
	{
		// 獲取應(yīng)用層傳值
		FileDataPtr = pirp->AssociatedIrp.SystemBuffer;
		switch (stack->Parameters.DeviceIoControl.IoControlCode)
		{
			// 讀取內(nèi)存函數(shù)
		case READ_FILE_SIZE_CODE:
		{
			LARGE_INTEGER liOffset = { 0 };
			UNICODE_STRING ustrFileSize;
			RtlInitUnicodeString(&ustrFileSize, L"\\??\\C:\\Windows\\system32\\ntoskrnl.exe");
			// 獲取文件長度
			ULONG64 ulBufferSize = MyGetFileSize(ustrFileSize);
			DbgPrint("獲取文件大小: %I64d Bytes \n", ulBufferSize);
			// 將長度返回應(yīng)用層
			FileDataPtr->size = ulBufferSize;
			break;
		}
		// 讀取文件
		case READ_FILE_CODE:
		{
			FileData ptr;
			LARGE_INTEGER liOffset = { 0 };
			UNICODE_STRING ustrFileSize;
			RtlInitUnicodeString(&ustrFileSize, L"\\??\\C:\\Windows\\system32\\ntoskrnl.exe");
			// 獲取文件長度
			ULONG64 ulBufferSize = MyGetFileSize(ustrFileSize);
			DbgPrint("獲取文件大小: %I64d Bytes \n", ulBufferSize);
			// 讀取內(nèi)存到緩沖區(qū)
			BYTE* pBuffer = ExAllocatePool(NonPagedPool, ulBufferSize);
			MyReadFile(ustrFileSize, liOffset, pBuffer, &ulBufferSize);
			// 返回?cái)?shù)據(jù)
			FileDataPtr->size = ulBufferSize;
			RtlCopyMemory(FileDataPtr->data, pBuffer, FileDataPtr->size);
			break;
		}
		}
		pirp->IoStatus.Information = sizeof(FileDataPtr);
		break;
	}
	}
	pirp->IoStatus.Status = STATUS_SUCCESS;
	IoCompleteRequest(pirp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
	if (driver->DeviceObject)
	{
		UNICODE_STRING SymbolName;
		RtlInitUnicodeString(&SymbolName, SYMBOLNAME);
		// 刪除符號(hào)鏈接
		IoDeleteSymbolicLink(&SymbolName);
		IoDeleteDevice(driver->DeviceObject);
	}
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
	NTSTATUS status = STATUS_SUCCESS;
	PDEVICE_OBJECT device = NULL;
	UNICODE_STRING DeviceName;
	DbgPrint("[LyShark] hello lyshark.com \n");
	// 初始化設(shè)備名
	RtlInitUnicodeString(&DeviceName, DEVICENAME);
	// 創(chuàng)建設(shè)備
	status = IoCreateDevice(Driver, sizeof(Driver->DriverExtension), &DeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &device);
	if (status == STATUS_SUCCESS)
	{
		UNICODE_STRING SymbolName;
		RtlInitUnicodeString(&SymbolName, SYMBOLNAME);
		// 創(chuàng)建符號(hào)鏈接
		status = IoCreateSymbolicLink(&SymbolName, &DeviceName);
		// 失敗則刪除設(shè)備
		if (status != STATUS_SUCCESS)
		{
			IoDeleteDevice(device);
		}
	}
	// 派遣函數(shù)初始化
	Driver->MajorFunction[IRP_MJ_CREATE] = DriverIrpCtl;
	Driver->MajorFunction[IRP_MJ_CLOSE] = DriverIrpCtl;
	Driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverIrpCtl;
	// 卸載驅(qū)動(dòng)
	Driver->DriverUnload = UnDriver;
	return STATUS_SUCCESS;
}

客戶端完整代碼如下所示;

// 署名權(quán)
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <iostream>
#define READ_FILE_SIZE_CODE CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ALL_ACCESS)
#define READ_FILE_CODE CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ALL_ACCESS)
typedef struct
{
	DWORD size;      // 讀寫長度
	BYTE* data;      // 讀寫數(shù)據(jù)集
}FileData;
int main(int argc, char* argv[])
{
	// 連接到驅(qū)動(dòng)
	HANDLE handle = CreateFileA("\\??\\ReadWriteSymbolName", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	FileData data;
	DWORD dwSize = 0;
	// 首先得到文件長度
	DeviceIoControl(handle, READ_FILE_SIZE_CODE, 0, 0, &data, sizeof(data), &dwSize, NULL);
	printf("%d \n", data.size);
	// 讀取機(jī)器碼到BYTE字節(jié)數(shù)組
	data.data = new BYTE[data.size];
	DeviceIoControl(handle, READ_FILE_CODE, &data, sizeof(data), &data, sizeof(data), &dwSize, NULL);
	for (int i = 0; i < data.size; i++)
	{
		printf("0x%02X ", data.data[i]);
	}
	printf("\n");
	getchar();
	CloseHandle(handle);
	return 0;
}

通過驅(qū)動(dòng)加載工具將WinDDK.sys拉起來,然后啟動(dòng)客戶端進(jìn)程,即可輸出ntoskrnl.exe的文件數(shù)據(jù),如下圖所示;

以上就是C語言驅(qū)動(dòng)開發(fā)之內(nèi)核文件的讀寫的詳細(xì)內(nèi)容,更多關(guān)于C語言內(nèi)核文件讀寫的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論