实现FileCopy(Ring0 x86 x64)
1.1 内核不接受一个字符串文件路径,必须填写一个OBJECT_ATTRIBUTES结构。 这个结构,在InitializeObjectAttributes初始化 typedef struct _OBJECT_ATTRIBUTES { ULONG Length; HANDLE RootDirectory; PUNICODE_STRING ObjectName; //路径 ULONG Attributes; PVOID SecurityDescriptor; PVOID SecurityQualityOfService; } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; typedef CONST OBJECT_ATTRIBUTES *PCOBJECT_ATTRIBUTES; VOID InitializeObjectAttributes( OUT POBJECT_ATTRIBUTES InitializedAttributes, IN PUNICODE_STRING ObjectName, //路径 IN ULONG Attributes, //OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE 忽略大小写 |打开内核句柄 IN HANDLE RootDirectory, IN PSECURITY_DESCRIPTOR SecurityDescriptor //打开的是内核句柄 传NULL ); NTSTATUS ZwCreateFile( __out PHANDLE FileHandle, __in ACCESS_MASK DesiredAccess, //申请的权限GENERIC_ALL __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 ); 如果CreateOptions 带有FILE_NO_INTERMEDIATE_BUFFERING CreateOptions 表示不通过缓冲区 直接操作磁盘,所以每次 操作读写都必须以磁盘扇区大小(通常为512字节)对齐,否则返回错误, typedef struct _IO_STATUS_BLOCK { union { NTSTATUS Status; //成功则为STATUS_SUCCESS PVOID Pointer; } DUMMYUNIONNAME; ULONG_PTR Information; //返回的更多信息 } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; NTSTATUS ZwReadFile( IN HANDLE FileHandle, IN HANDLE Event OPTIONAL, //用于异步完成时 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, //异步完成时的回调例程 IN PVOID ApcContext OPTIONAL, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID Buffer, //缓冲区 IN ULONG Length, //缓冲区长度 IN PLARGE_INTEGER ByteOffset OPTIONAL, // IN PULONG Key OPTIONAL ); 读取的实际长度在ioStatusBlock.Information里 读取完 返回STATUS_END_OF_FILE NTSTATUS ZwWriteFile( IN HANDLE FileHandle, IN HANDLE Event OPTIONAL, IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, IN PVOID ApcContext OPTIONAL, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PVOID Buffer, IN ULONG Length, IN PLARGE_INTEGER ByteOffset OPTIONAL, IN PULONG Key OPTIONAL );
下面是实现代码:
/*************************************************************************************** * AUTHOR : icqw * DATE : 2015-7-30 * MODULE : FileOption.H * * IOCTRL Sample Driver * * Description: * Demonstrates communications between USER and KERNEL. * **************************************************************************************** * Copyright (C) 2010 icqw. ****************************************************************************************/ #ifndef CXX_FILEOPTION_H #define CXX_FILEOPTION_H #include <ntifs.h> #include <devioctl.h> NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObj, IN PUNICODE_STRING pRegistryString); VOID DriverUnload(IN PDRIVER_OBJECT pDriverObj); HANDLE OpenFile(WCHAR* wzFilePath); NTSTATUS ReadFile(HANDLE hFile,CHAR* szBuffer,PULONG ulLength,PLARGE_INTEGER Offset); NTSTATUS WriteFile(HANDLE hFile,CHAR* szBuffer,PULONG ulLength,PLARGE_INTEGER Offset); NTSTATUS FileCopy(WCHAR* wzDest,WCHAR* wzSour); #endif
#ifndef CXX_FILEOPTION_H # include "FileOption.h" #endif NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING pRegisterPath) { NTSTATUS status = STATUS_SUCCESS; // #if DBG // _asm int 3 // // #endif DriverObject->DriverUnload = DriverUnload; FileCopy(L"\\??\\D:\\Dest.txt",L"\\??\\D:\\Sour.txt"); DbgPrint("[FileOption] DriverEntry Success\r\n"); return STATUS_SUCCESS; } NTSTATUS FileCopy(WCHAR* wzDest,WCHAR* wzSour) { HANDLE hSourFile = OpenFile(wzSour); HANDLE hDestFile = OpenFile(wzDest); ULONG ulLength = 0; CHAR* szBuffer = NULL; NTSTATUS Status = STATUS_UNSUCCESSFUL; LARGE_INTEGER Offset = {0}; if (hSourFile==NULL||hDestFile==NULL) { return STATUS_UNSUCCESSFUL; } szBuffer = (char*)ExAllocatePool(NonPagedPool,4*1024+1); while(TRUE) { RtlZeroMemory(szBuffer,4*1024+1); ulLength = 4*1024; //读 Status = ReadFile(hSourFile, szBuffer, &ulLength, &Offset); if (!NT_SUCCESS(Status)) { break; } //写 Status = WriteFile(hDestFile, szBuffer, &ulLength, &Offset); if (!NT_SUCCESS(Status)) { break; } } DbgPrint("Copy Success!"); ZwClose(hSourFile); ZwClose(hDestFile); return STATUS_SUCCESS; } HANDLE OpenFile(WCHAR* wzFilePath) { UNICODE_STRING uniName; OBJECT_ATTRIBUTES Ob; HANDLE hFile = NULL; NTSTATUS Status = STATUS_UNSUCCESSFUL; IO_STATUS_BLOCK ioStatus = {0}; RtlInitUnicodeString(&uniName,wzFilePath); InitializeObjectAttributes(&Ob, &uniName, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwCreateFile(&hFile, GENERIC_ALL|SYNCHRONIZE, &Ob, &ioStatus, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE| FILE_RANDOM_ACCESS| FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (!NT_SUCCESS(Status)) { return NULL; } return hFile; } //读文件 ulLength 为读取实际长度 NTSTATUS ReadFile(HANDLE hFile,CHAR* szBuffer,PULONG ulLength,PLARGE_INTEGER Offset) { //这里用 NTSTATUS Status = STATUS_UNSUCCESSFUL; IO_STATUS_BLOCK ioStatus = {0}; Status = ZwReadFile(hFile, NULL, NULL, NULL, &ioStatus, szBuffer, *ulLength, Offset, NULL); if (!NT_SUCCESS(Status)) { //Status==STATUS_END_OF_FILE) return STATUS_UNSUCCESSFUL; } *ulLength = ioStatus.Information; return Status;; } //写文件 NTSTATUS WriteFile(HANDLE hFile,CHAR* szBuffer,PULONG ulLength,PLARGE_INTEGER Offset) { NTSTATUS Status = STATUS_UNSUCCESSFUL; IO_STATUS_BLOCK ioStatus = {0}; Status = ZwWriteFile(hFile, NULL, NULL, NULL, &ioStatus, szBuffer, *ulLength, Offset, NULL); if (!NT_SUCCESS(Status)) { return STATUS_UNSUCCESSFUL; //!!!! } (*Offset).QuadPart += *ulLength; //Offset移动 return Status;; } VOID DriverUnload(IN PDRIVER_OBJECT pDriverObj) { DbgPrint("[FileOption] Unloaded Success\r\n"); return; }