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

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

一丶文件操做

1.文件操做的幾種方式

操做
建立文件/文件夾
讀/寫
拷貝
移動
刪除
屬性訪問與設置

1.2 文件的表示

文件路徑表示表格:數組

表示層 文件路徑表示方法
Ring3 L"C:\HelloWorld.txt"
Ring0 L"\??\C:\HelloWorld.txt"

其中兩個 ****是表明一個.表明的是轉義字符.異步

內核層的兩個??實際上是符號連接.表明的是是
\device\harddiskvolume3函數

內核中的文件路徑完整表達是: ** L"\device\harddiskvolume3\HelloWorld.txt**設計

Ring3跟Ring0的其它路徑.如設備對象.(符號連接)3d

表示層 路徑表示
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
    );

查詢文件類型code

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傳入的是什麼枚舉.他就會返回查詢的結構體給參數三.
僞代碼:orm

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

相關文章
相關標籤/搜索