|
RING0 操作文件和 RING3 操作文件在流程上没什么大的区别,也是“获得文件句柄->读/写/删/改->关闭文件句柄”的模式。当然了,只能用内核 API,不能用 WIN32API。在讲解具体的代码之前,先讲解一下文件系统的流程,让大家对整个文件系统有个大概的了解。
假设我们要读写一个文件,无论在 RING3 调用 ReadFile,还是在 RING0 调用 NtReadFile,它们最终会转换为 IRP,发送到文件系统驱动(具体哪个驱动和分区类型相关,如果是 FAT32分区,则是 FASTFAT.SYS;如果是 NTFS 分区,则是 NTFS.SYS)的 IRP_MJ_READ 分发函数里。
文件系统驱动经过一定处理后,就把 IRP 传给磁盘类驱动(通常是 CLASSPNP.SYS,此驱动的源码在 WDK 里有)的 IRP_MJ_READ 分发函数处理。磁盘类驱动处理完毕后,又把 IRP 传给磁盘小端口驱动的 IRP_MJ_SCSI 分发函数处理。磁盘小端口驱动太多了,网上有人用ATAPI.SYS 来指代磁盘小端口驱动,是极端错误的说法。ATAPI.SYS 是磁盘小端口驱动,但磁盘小端口驱动绝非只能是 ATAPI.SYS,常见的磁盘小端口驱动还有 LSI_SAS.SYS 等。如果安装了芯片组驱动,磁盘小端口驱动通常会被替换成主板厂商的驱动。比安装了英特尔 P67、HM77 的芯片组驱动后,磁盘小端口驱动就会变成 iaStroV.sys。在磁盘小端口驱动里,无论是读还是写,用的都是 IRP_MJ_SCSI 的分发函数。IRP 被磁盘小端口驱动处理完之后,就要依靠 HAL.DLL 进行端口 IO,此时数据就真的从硬盘里读取了出来。接下来再按照相反的方向把数据返回到调用者。另外,在内核里,文件夹和文件没啥本质的区别。比如 ZwDeleteFile既可以删除文件,也可以删除文件夹。接下来举几个例子,让大家了解内核里读写、删除、重命名和枚举文件,以及获取文件信息。
1.复制文件(包括了读文件、写文件)
- BOOLEAN ZwCopyFile
- (
- IN PUNICODE_STRING ustrDestFile, // \??\c:\1.txt
- IN PUNICODE_STRING ustrSrcFile // \??\c:\0.txt
- )
- {
- HANDLE hSrcFile, hDestFile;
- PVOID buffer = NULL;
- ULONG length = 0;
- LARGE_INTEGER offset = {0};
- IO_STATUS_BLOCK Io_Status_Block = {0};
- OBJECT_ATTRIBUTES obj_attrib;
- NTSTATUS status;
- BOOLEAN bRet = FALSE;
- do
- {
- // 打开源文件
- InitializeObjectAttributes( &obj_attrib,
- ustrSrcFile,
- OBJ_CASE_INSENSITIVE |
- OBJ_KERNEL_HANDLE,
- NULL,
- NULL);
- status = ZwCreateFile( &hSrcFile,
- GENERIC_READ,
- &obj_attrib,
- &Io_Status_Block,
- NULL,
- FILE_ATTRIBUTE_NORMAL,
- FILE_SHARE_READ,
- FILE_OPEN,
- FILE_NON_DIRECTORY_FILE |
- FILE_SYNCHRONOUS_IO_NONALERT,
- NULL,
- 0 );
- if (!NT_SUCCESS(status))
- {
- bRet = FALSE;
- goto END;
- }
- // 打开目标文件
- InitializeObjectAttributes( &obj_attrib,
- ustrDestFile,
- OBJ_CASE_INSENSITIVE |
- OBJ_KERNEL_HANDLE,
- NULL,
- NULL);
- status = ZwCreateFile( &hDestFile,
- GENERIC_WRITE,
- &obj_attrib,
- &Io_Status_Block,
- NULL,
- FILE_ATTRIBUTE_NORMAL,
- FILE_SHARE_READ,
- FILE_OPEN_IF,
- FILE_NON_DIRECTORY_FILE |
- FILE_SYNCHRONOUS_IO_NONALERT,
- NULL,
- 0 );
- if (!NT_SUCCESS(status))
- {
- bRet = FALSE;
- goto END;
- }
- // 为 buffer 分配 4KB 空间
- buffer = ExAllocatePool(NonPagedPool, 1024 * 4);
- if (buffer == NULL)
- {
- bRet = FALSE;
- goto END;
- }
- // 复制文件
- while (1)
- {
- length = 4 * 1024;
- // 读取源文件
- status = ZwReadFile(hSrcFile,
- NULL,
- NULL,
- NULL,
- &Io_Status_Block,
- buffer,
- length,
- &offset,
- NULL);
- if (!NT_SUCCESS(status))
- {
- // 如果状态为 STATUS_END_OF_FILE,说明文件已经读取到末尾
- if (status == STATUS_END_OF_FILE)
- {
- bRet = TRUE;
- goto END;
- }
- }
- // 获得实际读取的长度
- length = (ULONG)Io_Status_Block.Information;
- // 写入到目标文件
- status = ZwWriteFile( hDestFile,
- NULL,
- NULL,
- NULL,
- &Io_Status_Block,
- buffer,
- length,
- &offset,
- NULL);
- if (!NT_SUCCESS(status))
- {
- bRet = FALSE;
- goto END;
- }
- // 移动文件指针
- offset.QuadPart += length;
- }
- }
- while (0);
- END:
- if (hSrcFile)
- {
- ZwClose(hSrcFile);
- }
- if (hDestFile)
- {
- ZwClose(hDestFile);
- }
- if (buffer != NULL)
- {
- ExFreePool(buffer);
- }
- return bRet;
- }
复制代码- void ZwDeleteFileFolder(WCHAR *wsFileName)
- {
- NTSTATUS st;
- OBJECT_ATTRIBUTES ObjectAttributes;
- UNICODE_STRING UniFileName;
- //把 WCHAR*转化为 UNICODE_STRING
- RtlInitUnicodeString(&UniFileName, wsFileName);
- //设置包 OBJECT 对象并使用 ZwDeleteFile 删除
- InitializeObjectAttributes(&ObjectAttributes,
- &UniFileName,
- OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
- NULL,
- NULL);
- st=ZwDeleteFile(&ObjectAttributes);
- }
复制代码- typedef struct _FILE_RENAME_INFORMATION
- {
- BOOLEAN ReplaceIfExists;
- HANDLE RootDirectory;
- ULONG FileNameLength;
- WCHAR FileName[1];
- } FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;
- NTSTATUS
- ZwRenameFile
- (
- IN PWSTR SrcFileName, // \??\x:\xxx\...\xxx.xxx
- IN PWSTR DstFileName // \??\x:\xxx\...\xxx.xxx
- )
- {
- #define RN_MAX_PATH 2048
- #define SFLT_POOL_TAG 'fuck'
- HANDLE FileHandle = NULL;
- OBJECT_ATTRIBUTES ObjectAttributes;
- IO_STATUS_BLOCK IoStatus;
- NTSTATUS Status;
- PFILE_RENAME_INFORMATION RenameInfo = NULL;
- UNICODE_STRING ObjectName;
- //设置重命名的信息
- RenameInfo = (PFILE_RENAME_INFORMATION)ExAllocatePoolWithTag(NonPagedPool,
- sizeof(FILE_RENAME_INFORMATION) + RN_MAX_PATH * sizeof(WCHAR), SFLT_POOL_TAG);
- if (RenameInfo == NULL)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- RtlZeroMemory(RenameInfo, sizeof(FILE_RENAME_INFORMATION) + RN_MAX_PATH *
- sizeof(WCHAR));
- RenameInfo->FileNameLength = wcslen(DstFileName) * sizeof(WCHAR);
- wcscpy(RenameInfo->FileName, DstFileName);
- RenameInfo->ReplaceIfExists = 0;
- RenameInfo->RootDirectory = NULL;
- //设置源文件信息并获得句柄
- RtlInitUnicodeString(&ObjectName, SrcFileName);
- InitializeObjectAttributes(&ObjectAttributes,
- &ObjectName,
- OBJ_CASE_INSENSITIVE,
- NULL,
- NULL);
- Status = ZwCreateFile(&FileHandle,
- SYNCHRONIZE | DELETE,
- &ObjectAttributes,
- &IoStatus,
- NULL,
- 0,
- FILE_SHARE_READ,
- FILE_OPEN,
- FILE_SYNCHRONOUS_IO_NONALERT |
- FILE_NO_INTERMEDIATE_BUFFERING,
- NULL,
- 0);
- if (!NT_SUCCESS(Status))
- {
- ExFreePoolWithTag(RenameInfo, SFLT_POOL_TAG);
- return Status;
- }
- //最关键一步,利用 ZwSetInformationFile 来设置文件信息
- Status = ZwSetInformationFile(FileHandle,
- &IoStatus,
- RenameInfo,
- sizeof(FILE_RENAME_INFORMATION) +
- RN_MAX_PATH * sizeof(WCHAR),
- FileRenameInformation);
- if (!NT_SUCCESS(Status))
- {
- ExFreePoolWithTag(RenameInfo, SFLT_POOL_TAG);
- ZwClose(FileHandle);
- return Status;
- }
- ZwClose(FileHandle);
- return Status;
- }
复制代码- //这里传入的是文件句柄不是文件名,大家尝试把这里改成传入文件名
- ULONG64 GetFileSize(HANDLE hfile)
- {
- IO_STATUS_BLOCK iostatus= {0};
- NTSTATUS ntStatus=0;
- FILE_STANDARD_INFORMATION fsi= {0};
- ntStatus=ZwQueryInformationFile(hfile,
- &iostatus,
- &fsi,
- sizeof(FILE_STANDARD_INFORMATION),
- FileStandardInformation);
- if(!NT_SUCCESS(ntStatus))
- return 0;
- return fsi.EndOfFile.QuadPart;
- }
复制代码- NTKERNELAPI NTSTATUS ZwQueryDirectoryFile //最关键的 API
- (
- HANDLE FileHandle,
- HANDLE Event,
- PIO_APC_ROUTINE ApcRoutine,
- PVOID ApcContext,
- PIO_STATUS_BLOCK IoStatusBlock,
- PVOID FileInformation,
- ULONG Length,
- FILE_INFORMATION_CLASS FileInformationClass,
- BOOLEAN ReturnSingleEntry,
- PUNICODE_STRING FileName,
- BOOLEAN RestartScan
- );
- //几个常量
- #define INVALID_HANDLE_VALUE (HANDLE)-1
- #define MAX_PATH2 4096
- #define kmalloc(_s)ExAllocatePoolWithTag(NonPagedPool, _s, 'SYSQ')
- #define kfree(_p) ExFreePool(_p)
- //枚举文件用到的结构体
- typedef struct _FILE_BOTH_DIR_INFORMATION
- {
- ULONG NextEntryOffset;
- 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;
- //山寨版 MyFindFirstFile
- HANDLE MyFindFirstFile(LPSTR lpDirectory,PFILE_BOTH_DIR_INFORMATION pDir,ULONG
- uLength)
- {
- char strFolder[MAX_PATH2]= {0};
- STRING astrFolder;
- UNICODE_STRING ustrFolder;
- OBJECT_ATTRIBUTES oa;
- IO_STATUS_BLOCK ioStatus;
- NTSTATUS ntStatus;
- HANDLE hFind = INVALID_HANDLE_VALUE;
- memset(strFolder,0,MAX_PATH2);
- strcpy(strFolder,"\\??\");
- strcat(strFolder,lpDirectory);
- RtlInitString(&astrFolder,strFolder);
- if (RtlAnsiStringToUnicodeString(&ustrFolder,&astrFolder,TRUE)==0)
- {
- InitializeObjectAttributes(&oa,&ustrFolder,OBJ_CASE_INSENSITIVE,NULL,NULL);
- ntStatus = IoCreateFile(
- &hFind,
- FILE_LIST_DIRECTORY | SYNCHRONIZE | FILE_ANY_ACCESS,
- &oa,
- &ioStatus,
- NULL,
- FILE_ATTRIBUTE_NORMAL,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- FILE_OPEN, //FILE_OPEN
- FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
- FILE_OPEN_FOR_BACKUP_INTENT,
- NULL,
- 0,
- CreateFileTypeNone,
- NULL,
- IO_NO_PARAMETER_CHECKING);
- RtlFreeUnicodeString(&ustrFolder);
- if (ntStatus==0 && hFind!=INVALID_HANDLE_VALUE)
- {
- ntStatus=ZwQueryDirectoryFile(
- hFind, // File Handle
- NULL, // Event
- NULL, // Apc routine
- NULL, // Apc context
- &ioStatus, // IoStatusBlock
- pDir, // FileInformation
- uLength, // Length
- FileBothDirectoryInformation, // FileInformationClass
- TRUE, // ReturnSingleEntry
- NULL, // FileName
- FALSE //RestartScan
- );
- if (ntStatus!=0)
- {
- ZwClose(hFind);
- hFind=INVALID_HANDLE_VALUE;
- }
- }
- }
- return hFind;
- }
- //山寨版 MyFindNextFile
- BOOLEAN MyFindNextFile(HANDLE hFind, PFILE_BOTH_DIR_INFORMATION pDir, ULONG
- uLength)
- {
- IO_STATUS_BLOCK ioStatus;
- NTSTATUS ntStatus;
- ntStatus=ZwQueryDirectoryFile(
- hFind, // File Handle
- NULL, // Event
- NULL, // Apc routine
- NULL, // Apc context
- &ioStatus, // IoStatusBlock
- pDir, // FileInformation
- uLength, // Length
- FileBothDirectoryInformation, // FileInformationClass
- FALSE, // ReturnSingleEntry
- NULL, // FileName
- FALSE //RestartScan
- );
- if (ntStatus==0)
- return TRUE;
- else
- return FALSE;
- }
- //枚举文件夹内容的函数,输入路径,返回目录下的文件和文件夹数目
- ULONG SearchDirectory(LPSTR lpPath)
- {
- ULONG muFileCount=0;
- HANDLE hFind=INVALID_HANDLE_VALUE;
- PFILE_BOTH_DIR_INFORMATION pDir;
- char *strBuffer = NULL,*lpTmp=NULL;
- char strFileName[255*2];
- ULONG uLength=MAX_PATH2*2 + sizeof(FILE_BOTH_DIR_INFORMATION);
- strBuffer = (PCHAR)kmalloc(uLength);
- pDir = (PFILE_BOTH_DIR_INFORMATION)strBuffer;
- hFind=MyFindFirstFile(lpPath,pDir,uLength);
- if (hFind!=INVALID_HANDLE_VALUE)
- {
- kfree(strBuffer);
- uLength=(MAX_PATH2*2 + sizeof(FILE_BOTH_DIR_INFORMATION)) * 0x2000;
- strBuffer = (PCHAR)kmalloc(uLength);
- pDir = (PFILE_BOTH_DIR_INFORMATION)strBuffer;
- if (MyFindNextFile(hFind,pDir,uLength))
- {
- while (TRUE)
- {
- memset(strFileName,0,255*2);
- memcpy(strFileName,pDir->FileName,pDir->FileNameLength);
- if (strcmp(strFileName,"..")!=0 && strcmp(strFileName,".")!=0)
- {
- if (pDir->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- {
- DbgPrint("[目录]%S\n",strFileName);
- }
- else
- {
- DbgPrint("[文件]%S\n",strFileName);
- }
- muFileCount++;
- }
- if (pDir->NextEntryOffset==0) break;
- pDir = (PFILE_BOTH_DIR_INFORMATION)((char
- *)pDir+pDir->NextEntryOffset);
- }
- kfree(strBuffer);
- }
- ZwClose(hFind);
- }
- return muFileCount;
- }
复制代码- void ZwCreateFolder(char *FolderPath)
- {
- NTSTATUS st;
- HANDLE FileHandle;
- OBJECT_ATTRIBUTES ObjectAttributes;
- IO_STATUS_BLOCK IoStatusBlock;
- UNICODE_STRING UniFileName;
- WCHAR wsFileName[2048]= {0};
- CharToWchar(FolderPath,wsFileName);
- RtlInitUnicodeString(&UniFileName, wsFileName);
- InitializeObjectAttributes(&ObjectAttributes,
- &UniFileName,
- OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
- NULL,
- NULL);
- st=IoCreateFile(&FileHandle,
- GENERIC_READ,
- &ObjectAttributes,
- &IoStatusBlock,
- 0,
- FILE_ATTRIBUTE_NORMAL,
- 0,
- FILE_CREATE,
- FILE_DIRECTORY_FILE,
- NULL,
- 0,
- 0,
- NULL,
- IO_NO_PARAMETER_CHECKING);
- if(NT_SUCCESS(st))
- ZwClose(FileHandle);
- }
复制代码
|
|