目录api
操做 |
---|
建立文件/文件夹 |
读/写 |
拷贝 |
移动 |
删除 |
属性访问与设置 |
文件路径表示表格:数组
表示层 | 文件路径表示方法 |
---|---|
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符号链接 |
方法名 | 做用 |
---|---|
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指向一块地址.
#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中便可.
传参的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; }
原理: 使用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; }
在拷贝字符串的时候我拷贝的是宽字符.因此显示如上图.在咱们读文件以前.我稍微修改一下.这里就不在贴出代码了.
内核中读写文件实际上是同样的.打开一个文件.读取数据便可.
代码以下:
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; }
内核中能够删除文件.有两种方式.第一种调用 ZwDeleteFile.你须要包含一个 <ntifs.h>头文件.
可是我包含以后出错.就没再深究.本身声明了一下.
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这个文件.当我要删除这个文件的时候同样删除成功.
这种删除方式更加厉害. 好比上面咱们说的文件可能由于各类因素删除失败.因此采用这种方法. 这种方法是使用 内核中的 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; }