目录
文件操作,以及强删文件.
一丶文件操作
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;
}