调用:
KernelCopyFile(L"\??\C:\888.exe", L"\??\C:\567.exe");
注意点:
1、文件过大怎么读写?
readoffset.QuadPart = 0 这个是读取文件位置,如果读取的文件很大,可以通过这个参数来分批读入
2、ZwClose(hfile2); 最后不关闭句柄的效果
文件的打开,读取,创建,写入 都包含在这个函数
///KernelCopyFile内核拷贝函数
///执行流程基于旧文件的打开,旧文件内容的读取,新文件的创建最后新文件的写入
/// 参数1是新文件路径,参数2是旧文件路径
NTSTATUS KernelCopyFile(PWCHAR defile_path, PWCH sourcefile_path)
{
NTSTATUS status = STATUS_SUCCESS;// 定义一个返回值
HANDLE hfile1 = NULL; //定义一个句柄
UNICODE_STRING sourcefilepath = {
0 }; //源文件路径
OBJECT_ATTRIBUTES obja1 = {
0 }; //源文件参数
IO_STATUS_BLOCK iostack1 = {
0 };//旧文件操作记录
RtlInitUnicodeString(&sourcefilepath, sourcefile_path);//初始化一个文件路径
//初始化
InitializeObjectAttributes(&obja1, &sourcefilepath, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);
//打开文件旧文件
//参数1:文件句柄
//参数2:访问权限
//参数3:&iostack1 会记录这次操作的一些信息
//参数4:FILE_SHARE_READ 共享读、FILE_SHARE_WRITE共享写
status = ZwOpenFile(&hfile1, GENERIC_ALL, &obja1, &iostack1, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
// 判断打开文件是否成功
if (!NT_SUCCESS(status))
{
DbgPrint("Open SourceFile Failed:%x\n", status);
return status;
}
FILE_STANDARD_INFORMATION fbi = {
0 }; //获取文件大小用
//查询文件信息
status = ZwQueryInformationFile(hfile1, &iostack1, &fbi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation);
if (!NT_SUCCESS(status))
{
//查询文件信息失败
DbgPrint("QueryInformation SorceFile:%x\n", status);
//关闭文件
ZwClose(hfile1);
return status;
}
//到这里文件查询就成功了
PVOID filebuffer = NULL; //定义一个文件缓存区
//参数2 是缓冲区大小,这里就是上面获取旧文件的大小
filebuffer = ExAllocatePool(NonPagedPool, fbi.EndOfFile.QuadPart);//申请一个缓冲区
if (!filebuffer)
{
//申请缓冲区失败信息
DbgPrint("AllocteBuffer Failed:%x\n", status);
ZwClose(hfile1);
return status;
}
RtlZeroMemory(filebuffer, fbi.EndOfFile.QuadPart);//缓冲区清零
//接下来开始读取文件
LARGE_INTEGER readoffset = {
0};
readoffset.QuadPart = 0;
//读文件
//参数1:读取文件的句柄
//参数2:NULL 表示读事件,异步读
//参数3:NULL 异步读需要一个什么东西,这里没有填
//参数4: &iostack1 里面有请求的基本信息,请求的长度、结果等
//参数5:fbi.EndOfFile.QuadPart 缓冲区的长度
//参数6:从哪里开始读文件 ,readoffset 这里是从0开始读
//最后一个参数KEY 一般传空 NULL
status = ZwReadFile(hfile1, NULL, NULL, NULL, &iostack1, filebuffer, fbi.EndOfFile.QuadPart, &readoffset, NULL);
if (!NT_SUCCESS(status))
{
//读取失败
DbgPrint("ReadFile Failed:%x\n", status);
ZwClose(hfile1);
ExFreePool(filebuffer);
return status;
}
//打印出信息
DbgPrint("-----IoInfo----%d\n",iostack1.Information);
ZwClose(hfile1);//关闭旧文件的句柄,文件已经读到内存
//
// 下面开始创建新文件
//
HANDLE hfile2 = NULL;
UNICODE_STRING defilepath = {
0};
OBJECT_ATTRIBUTES obja2 = {
0 }; //新文件参数
IO_STATUS_BLOCK iostack2 = {
0 };//新文件IO操作记录
RtlInitUnicodeString(&defilepath, defile_path);//新文件路径
//初始化文件描述
InitializeObjectAttributes(&obja2,&defilepath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
//ZwCreateFile可以创建新文件,也可以打开设备,可以打开任何东西
//参数1:&hfile2 句柄
//参数2:访问权限 GENERIC_ALL是全部权限
//参数3:&obja2文件信息描述
//参数4:iostack2 IO操作记录
//参数5:一个指针 提前申请文件大小,本例先设置NULL,不设置大小 先创建
//参数6:FILE_ATTRIBUTE_NORMAL 文件的描述
//参数7:FILE_SHARE_WRITE这
//参数8:这个参数比较重要,如果文件已经存在怎么办? FILE_SUPERSEDE 这个参数表示如果文件存在就用新创建的文件替换
//参数9:FILE_SYNCHRONOUS_IO_NONALERT和ZwOpenFile一样
//参数10:NULL 用到网络通信,本例用不到 设置NULL ,打开TCP UDP设备的时候用到这个参数
//参数11: 0 用到网络通信,本例用不到 设置0 ,打开TCP UDP设备的时候用到这个参数
status = ZwCreateFile(&hfile2, GENERIC_ALL, &obja2, &iostack2, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, FILE_SUPERSEDE, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(status))
{
//创建文件失败
DbgPrint("Create File Failed:%x\n", status);
ZwClose(hfile2);
ExFreePool(filebuffer);
return status;
}
//到这里文件就创建成功了
//接下来就写入文件
LARGE_INTEGER writeoffset = {
0 };
writeoffset.QuadPart = 0; //从哪里开始写文件,这里是新文件从0开始写
/// <写入文件>
/// ZwWriteFile
/// 参数1:hfile2 文件句柄
/// 参数2:NULL 事件
/// 参数3:NULL 是否APC异步写
/// 参数4:NULL
/// 参数5:&iostack2
/// 参数6:filebuffe 内存中的文件
/// 参数7:fbi.EndOfFile.QuadPart文件的长度
/// 参数8:writeoffset.QuadPart 从哪里开始写
/// 参数9:NULL
status = ZwWriteFile(hfile2,NULL,NULL, NULL, &iostack2,filebuffer, fbi.EndOfFile.QuadPart, writeoffset.QuadPart,NULL);
if (!NT_SUCCESS(status))
{
//创建文件失败
DbgPrint("Write File Failed:%x\n", status);
ExFreePool(filebuffer);
ZwClose(hfile2);
return status;
}
//打印出实际写入的信息
DbgPrint("----Write----%d\n", iostack2.Information );
//最后收尾释放
ExFreePool(filebuffer);
ZwClose(hfile2);//如果不加这一句关闭文件句柄 ,文件会被系统进程锁住,该文件不能删除也不能运行,俗称占坑
return STATUS_SUCCESS;
}