创建文件夹
// 文件名的格式为: \\??\\C:\\dale
NTSTATUS CreateDirectory(PWCHAR wsDesFileName)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
OBJECT_ATTRIBUTES oa;
UNICODE_STRING usDesFileName;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE FileHandle = NULL;
RtlInitUnicodeString(&usDesFileName, wsDesFileName);
InitializeObjectAttributes(&oa,
&usDesFileName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL
);
//把内存中的数据写入到文件中
status = ZwCreateFile(
&FileHandle,
GENERIC_READ,
&oa,
&IoStatusBlock,
0,
FILE_ATTRIBUTE_NORMAL | SYNCHRONIZE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
FILE_CREATE,
FILE_DIRECTORY_FILE,
NULL,
0
);
if (!NT_SUCCESS(status))
{
KdPrint(("目标文件创建失败 错误码:%x\n", status));
return status;
}
ZwClose(FileHandle);
return STATUS_SUCCESS;
}
文件复制
内核中文件路径格式为 “\??\C:\dale”
wsSrcFileName 要复制的源文件名 已存在的文件
wsDesFileName 复制到的目标文件 需要程序创建的文件
// 文件名的格式为: \\??\\C:\\dale
NTSTATUS CopyFile(PCWSTR wsDesFileName, PCWSTR wsSrcFileName)
{
NTSTATUS status = STATUS_SUCCESS;
//打开文件
HANDLE hSrcFile=NULL;
HANDLE hDesFile=NULL;
PUCHAR buffer = NULL;
OBJECT_ATTRIBUTES oa;
UNICODE_STRING usSrcFileName;
//参数有效性检查
if (!wsDesFileName || !wsSrcFileName)
{
KdPrint(("路径不能为空\n"));
return STATUS_INVALID_PARAMETER;
}
do
{
RtlInitUnicodeString(&usSrcFileName, wsSrcFileName);
InitializeObjectAttributes(&oa,
&usSrcFileName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL
);
IO_STATUS_BLOCK IoStatusBlock;
//打开需要复制的源文件
status = ZwCreateFile(&hSrcFile,
GENERIC_ALL,
&oa,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_VALID_FLAGS,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (!NT_SUCCESS(status))
{
KdPrint(("源文件打开失败 错误码:%x\n", status));
return status;
}
//获取源文件大小
FILE_STANDARD_INFORMATION fsi = { 0 };
status = ZwQueryInformationFile(hSrcFile, &IoStatusBlock, &fsi, sizeof(fsi), FileStandardInformation);
if (!NT_SUCCESS(status) || !fsi.EndOfFile.QuadPart)
{
KdPrint(("查询源文件信息失败 错误码:%x\n", status));
break;
}
//申请源文件大小的内存
buffer = (PUCHAR)ExAllocatePoolWithTag(PagedPool, fsi.EndOfFile.LowPart, 'dale');
if (!buffer)
{
KdPrint(("内存申请失败\n"));
break;
}
RtlZeroMemory(buffer, fsi.EndOfFile.LowPart);
//把文件读到一块内存中
status = ZwReadFile(hSrcFile,
NULL, NULL, NULL,
&IoStatusBlock,
buffer, //保存读取内容的buffer
fsi.EndOfFile.LowPart,//读取的长度
0,//始读取的位置
NULL
);
if (!NT_SUCCESS(status))
{
KdPrint(("读取文件内容失败 错误码:%x\n", status));
break;
}
UNICODE_STRING usDesFileName;
RtlInitUnicodeString(&usDesFileName, wsDesFileName);
InitializeObjectAttributes(&oa,
&usDesFileName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL
);
//把内存中的数据写入到文件中
status = ZwCreateFile(&hDesFile,
GENERIC_ALL,
&oa,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_VALID_FLAGS,
FILE_OVERWRITE_IF,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (!NT_SUCCESS(status))
{
KdPrint(("目标文件创建失败 错误码:%x\n", status));
break;
}
status = ZwWriteFile(hDesFile, NULL, NULL, NULL, &IoStatusBlock, buffer, fsi.EndOfFile.LowPart, 0, NULL);
if (!NT_SUCCESS(status))
{
KdPrint(("写入目标文件失败 错误码:%x\n", status));
break;
}
} while (FALSE);
//关闭源文件句柄
if (NULL != hSrcFile)
{
ZwClose(hSrcFile);
hSrcFile = NULL;
}
//关闭目标文件句柄
if (NULL != hDesFile)
{
ZwClose(hDesFile);
hSrcFile = NULL;
}
if (NULL!= buffer)
{
ExFreePoolWithTag(buffer, 'dale');
buffer = NULL;
}
return status;
}
文件删除操作
调用函数ZwDeleteFile即可删除文件,也可以删除文件夹 ,需要包含头文件Ntifs.h 并且要在ntddk.h的前面
只能删除空文件家或者文件
#include < Ntifs.h>
#include <ntddk.h>
NTSTATUS KeDeleteFile(PCWSTR DesFileName)
{
if(!DesFileName)
{
KdPrint(("要删除的文件路径不能为空\n"));
return STATUS_INVALID_PARAMETER;
}
NTSTATUS status=STATUS_SUCCESS;
OBJECT_ATTRIBUTES oa;
UNICODE_STRING FileName;
RtlInitUnicodeString(&FileName, DesFileName);
InitializeObjectAttributes(&oa, &FileName, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,NULL,NULL);
status=ZwDeleteFile(&oa);
if(!NT_SUCCESS(status))
{
KdPrint(("文件删除失败,错误码:%x\n",status));
return status;
}
return status;
}
文件重命名
NTSTATUS ReNameFile(PCWSTR NewFileName, PCWSTR OriginalFileName)
{
NTSTATUS status=STATUS_SUCCESS;
//打开文件
HANDLE hSrcFile;
OBJECT_ATTRIBUTES oa;
UNICODE_STRING usSrcFileName;
if (!NewFileName || !OriginalFileName)
{
KdPrint(("路径不能为空\n"));
return STATUS_INVALID_PARAMETER;
}
RtlInitUnicodeString(&usSrcFileName, OriginalFileName);
InitializeObjectAttributes(&oa,
&usSrcFileName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL
);
IO_STATUS_BLOCK IoStatusBlock;
status = ZwCreateFile(&hSrcFile,
GENERIC_ALL,
&oa,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (!NT_SUCCESS(status))
{
KdPrint(("源文件打开失败 错误码:%x\n", status));
return status;
}
//计算出需要分配的内存大小,结构体PFILE_RENAME_INFORMATION+重命名的长度
ULONG BufferLength = sizeof(FILE_RENAME_INFORMATION) + wcslen(NewFileName)*sizeof(WCHAR);
//分配内存
PFILE_RENAME_INFORMATION pri = (PFILE_RENAME_INFORMATION)ExAllocatePoolWithTag(PagedPool, BufferLength, 'dale');
if (!pri)
{
KdPrint(("文件名分配失败\n"));
ZwClose(hSrcFile);
return STATUS_UNSUCCESSFUL;
}
//初始化内存
RtlZeroMemory(pri, BufferLength);
//把文件名复制到结构体中
RtlCopyMemory(pri->FileName, NewFileName, wcslen(NewFileName)*sizeof(WCHAR));
pri->FileNameLength = wcslen(NewFileName)*sizeof(WCHAR);
pri->ReplaceIfExists = TRUE; //如果文件名存在就替换文件
//设置文件信息
status = ZwSetInformationFile(hSrcFile, &IoStatusBlock, pri, BufferLength, FileRenameInformation);
if (!NT_SUCCESS(status))
{
KdPrint(("重命名文件失败,status=%x\n",status));
}
ExFreePoolWithTag(pri, 'dale');
ZwClose(hSrcFile);
return status;
}
遍历文件
typedef struct _FILE_BOTH_DIR_INFORMATION {
ULONG NextEntryOffset; //到下一个entry的偏移 这个值也可以看成是这个块的大小.
ULONG FileIndex;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes; //文件属性
ULONG FileNameLength; //文件名的长度
ULONG EaSize;
CCHAR ShortNameLength;
WCHAR ShortName[12];
WCHAR FileName[1]; //文件名
} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;
NTSTATUS Ergodic(PCWSTR FileDirName)
{
NTSTATUS status = STATUS_SUCCESS;
//打开文件
HANDLE hFileDir;
OBJECT_ATTRIBUTES oa;
UNICODE_STRING usSrcFileName;
if (!FileDirName)
{
KdPrint(("路径不能为空\n"));
return STATUS_INVALID_PARAMETER;
}
RtlInitUnicodeString(&usSrcFileName, FileDirName);
InitializeObjectAttributes(&oa,
&usSrcFileName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL
);
IO_STATUS_BLOCK IoStatusBlock;
status = ZwCreateFile(&hFileDir,
FILE_LIST_DIRECTORY | SYNCHRONIZE | FILE_ANY_ACCESS,
&oa,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
NULL,
0);
if (!NT_SUCCESS(status))
{
KdPrint(("源文件打开失败 错误码:%x\n", status));
return status;
}
IO_STATUS_BLOCK IoStackBlock;
PFILE_BOTH_DIR_INFORMATION pbdi;
pbdi = (PFILE_BOTH_DIR_INFORMATION)ExAllocatePoolWithTag(PagedPool, 1024*1024, 'dale');
if (!pbdi)
{
KdPrint(("内存分配失败, status=%x\n", status));
ZwClose(hFileDir);
}
RtlZeroMemory(pbdi, 1024*1024);
WCHAR buffer[200] = { 0 };
status = ZwQueryDirectoryFile(hFileDir,
NULL,
NULL,
NULL,
&IoStatusBlock,
pbdi,
1024*1024,
FileBothDirectoryInformation,
FALSE,//如果只需要返回一个条目,就设置为TRUE
NULL,
FALSE//如果要从目录中的第一个条目开始扫描,则设置为true。如果从上一次调用恢复扫描,则设置为false。
);
//怎样在不分配较大内存的情况下获得这个需要分配的值?
KdPrint(("需要分配的内存大小是:%x\n",IoStatusBlock.Information));
if (!NT_SUCCESS(status))
{
KdPrint(("查询目录失败,status=%x\n", status));
ZwClose(hFileDir);
ExFreePoolWithTag(pbdi, 'dale');
return status;
}
PFILE_BOTH_DIR_INFORMATION pcdi = pbdi;
while (TRUE)
{
RtlZeroMemory(buffer,sizeof(buffer));
RtlCopyMemory(buffer, pcdi->FileName, pcdi->FileNameLength);
KdPrint(("文件名:%S \n", buffer));
if (pcdi->NextEntryOffset == 0)
{
break;
}
//在64位下类型转换出现了错误,使用ULONG会蓝屏,要使用ULONG_PTR
pcdi = (PFILE_BOTH_DIR_INFORMATION)((ULONG_PTR)pcdi + pcdi->NextEntryOffset);
}
ExFreePoolWithTag(pbdi, 'dale');
ZwClose(hFileDir);
return status;
}