目录

  • 文件操作,以及强删文件.

    • 一丶文件操作

      • 1.文件操作的几种方式
      • 1.2 文件的表示
    • 二丶文件操作的常见内核API
      • 三丶内核中三种定义结构体的方式
      • 四丶驱动创建文件的完整代码示例
      • 4.1.4内核中读文件
      • 4.1.4内核中删除文件的两种方式

文件操作,以及强删文件.

一丶文件操作

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,                   读写的BufferIN 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 valuechar szBuffer[100]
}

这种类型.我们的szBuffer就是占你给定的大小.

指针类型


struct point
{int valuechar *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("打开文件失败,删除失败");}}//进行强制删除文件 通过 ZwSetInformationFileIBdelPostion.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;
}

转载于:https://www.cnblogs.com/iBinary/p/10990683.html

64位内核开发第8讲,文件操作.以及删除文件.相关推荐

  1. 64位内核开发第二讲.内核编程注意事项,以及UNICODE_STRING

    目录 一丶驱动是如何运行的 1.服务注册驱动 二丶Ring3跟Ring0通讯的几种方式 1.IOCTRL_CODE 控制代码的几种IO 2.非控制 缓冲区的三种方式. 三丶Ring3跟Ring0开发区 ...

  2. 64位内核开发第五讲,调试与反调试

    目录 反调试与反反调试 一丶反调试的几种方法 1.DebugPort端口清零 2.KdDisableDebugger 3.ring3下的 isDebuggerpresent和CheckRemoteDe ...

  3. 64位内核开发第14将,路径的相互转换以及获取.

    待定 转载于:https://www.cnblogs.com/iBinary/p/11257361.html

  4. 64位内核第一讲,和32位内核的区别

    64位内核第一讲,和32位内核的区别 双击调试配置请查看 连接: https://www.cnblogs.com/aliflycoris/p/5877323.html 一丶编译的区别. 首先,还是使用 ...

  5. 64位内核第二讲,进程保护之对象钩子

    64位内核第二讲,进程保护. 一丶什么是保护. 什么是保护. 比如我们安装了xxx杀毒软件.那么此时你用任务管理器关闭.是关闭不了的.原因是内核已经做了保护. 那么去掉保护的前提就是你要给自己的软件做 ...

  6. AIX 64位内核与32位内核区别

    Q:怎么确定机器会运行 64 位内核?  A:运行 64 位内核要求 64 位硬件.对于 AIX 5.2,所有 IBM eServer pSeries 64 位硬件都能运行 64 位或 32 位内核. ...

  7. 1g的树莓派4b能做什么_树莓派4B(Raspbian)切换64位内核+简单性能测试

    首先说明两点: 1.目前来看来看(20200108测试,基于Raspbian 2019-09-26),是没有什么卵用的,切换之后性能不增反降,且软件兼容性不能得到保证. 2.教程来源于贴吧大佬,感谢大 ...

  8. android5.1内核版本,Android-x86现已基于5.1.1 Lollipop:支持UEFI和64位内核

    由于采用了Linux 4.0.9内核,Android-x86 5.1 RC1也是首个支持64位内核的版本.此外,它还支持多点触控.UEFI启动.蓝牙.摄像头.以太网(仅HDCP).Wi-Fi.音频.以 ...

  9. mac开启64位内核

    sudo nvram boot-args="arch=x86_64" 查看是否是64位: 桌面左上角的小苹果,关于本机,更多信息,软件,64位内核,开启 在终端输入上面的命令就能开 ...

最新文章

  1. swig error : Unrecognized option -doxygen Ubuntu 安装 swig-3.0.12
  2. Windows下配置NodeJS环境详解
  3. ubuntu16.04:成功解决ubuntu16.04 忘记root密码
  4. linux c++ queue 多线程,C++多线程,消息队列用法
  5. 马上工作了,想问下要注意哪些问题?
  6. android发送点击事件,Android 模拟发送事件
  7. 175. 组合两个表
  8. Linux rmdir命令:删除空目录
  9. Spring包名代码提示
  10. hibernate一对多自关联的记录(以树形菜单为例)
  11. 嵌入式linux led驱动有几种写法,嵌入式Linux字符驱动LED灯设计
  12. flash跟随鼠标样式
  13. session与cookie的区别和用法
  14. WEB免费打印控件推荐(4款)
  15. 焊接计算机软件系统,计算机在焊接中的应用
  16. 无线投影服务器连接投影仪,无线投屏器怎么与投影机连接
  17. win10linux双系统时间,win10与linux双系统切换时间不一致的调整
  18. 刚构桥的优缺点_桥梁的优缺点
  19. 1.大量数据导出Excel 之 多重影分身之术
  20. php酷狗音乐API接口,酷狗音乐抓取api

热门文章

  1. OpenCV4.0 Mask RCNN 实例分割示例 C++/Python实现
  2. PyTorch | 通过torch.arange创建等差数列张量 | torch.arange()如何使用?torch.arange()使用方法 torch.arange()举例说明
  3. 解决Python中sum函数出现的TypeError: unsupported operand type(s) for +: 'int' and 'list'错误问题
  4. java 抛出异常效率_Java异常处理机制
  5. 深度学习(四十)caffe使用点滴记录
  6. 针对Hybrid A*论文解析(5)中的方法的一些验证
  7. 部编版是什么版本_教材部编版和人教版的区别
  8. maven打包忽略注解_maven打包后pom.properties中的注释问题-阿里云开发者社区
  9. cacti 升级php,Cacti 升级备忘
  10. 计算机一级office考试题库及答案,2016下半年计算机一级msoffice考试试题及答案