登录  | 立即注册

游客您好!登录后享受更多精彩

查看: 15|回复: 0

Win64驱动开发教程07.内核里操作文件

[复制链接]

79

主题

2

回帖

104

积分

网站编辑

积分
104
发表于 前天 22:20 | 显示全部楼层 |阅读模式

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 等。如果安装了芯片组驱动,磁盘小端口驱动通常会被替换成主板厂商的驱动。比安装了英特尔 P67HM77 的芯片组驱动后,磁盘小端口驱动就会变成 iaStroV.sys。在磁盘小端口驱动里,无论是读还是写,用的都是 IRP_MJ_SCSI 的分发函数。IRP 被磁盘小端口驱动处理完之后,就要依靠 HAL.DLL 进行端口 IO,此时数据就真的从硬盘里读取了出来。接下来再按照相反的方向把数据返回到调用者。另外,在内核里,文件夹和文件没啥本质的区别。比如 ZwDeleteFile既可以删除文件,也可以删除文件夹。接下来举几个例子,让大家了解内核里读写、删除、重命名和枚举文件,以及获取文件信息。
1.复制文件(包括了读文件、写文件)
  1. BOOLEAN ZwCopyFile
  2. (
  3. IN PUNICODE_STRING ustrDestFile, // \??\c:\1.txt
  4. IN PUNICODE_STRING ustrSrcFile // \??\c:\0.txt
  5. )
  6. {
  7. HANDLE hSrcFile, hDestFile;
  8. PVOID buffer = NULL;
  9. ULONG length = 0;
  10. LARGE_INTEGER offset = {0};
  11. IO_STATUS_BLOCK Io_Status_Block = {0};
  12. OBJECT_ATTRIBUTES obj_attrib;
  13. NTSTATUS status;
  14. BOOLEAN bRet = FALSE;
  15. do
  16. {
  17. // 打开源文件
  18. InitializeObjectAttributes( &obj_attrib,
  19. ustrSrcFile,
  20. OBJ_CASE_INSENSITIVE |
  21. OBJ_KERNEL_HANDLE,
  22. NULL,
  23. NULL);
  24. status = ZwCreateFile( &hSrcFile,
  25. GENERIC_READ,
  26. &obj_attrib,
  27. &Io_Status_Block,
  28. NULL,
  29. FILE_ATTRIBUTE_NORMAL,
  30. FILE_SHARE_READ,
  31. FILE_OPEN,
  32. FILE_NON_DIRECTORY_FILE |
  33. FILE_SYNCHRONOUS_IO_NONALERT,
  34. NULL,
  35. 0 );
  36. if (!NT_SUCCESS(status))
  37. {
  38. bRet = FALSE;
  39. goto END;
  40. }
  41. // 打开目标文件
  42. InitializeObjectAttributes( &obj_attrib,
  43. ustrDestFile,
  44. OBJ_CASE_INSENSITIVE |
  45. OBJ_KERNEL_HANDLE,
  46. NULL,
  47. NULL);
  48. status = ZwCreateFile( &hDestFile,
  49. GENERIC_WRITE,
  50. &obj_attrib,
  51. &Io_Status_Block,
  52. NULL,
  53. FILE_ATTRIBUTE_NORMAL,
  54. FILE_SHARE_READ,
  55. FILE_OPEN_IF,
  56. FILE_NON_DIRECTORY_FILE |
  57. FILE_SYNCHRONOUS_IO_NONALERT,
  58. NULL,
  59. 0 );
  60. if (!NT_SUCCESS(status))
  61. {
  62. bRet = FALSE;
  63. goto END;
  64. }
  65. // 为 buffer 分配 4KB 空间
  66. buffer = ExAllocatePool(NonPagedPool, 1024 * 4);
  67. if (buffer == NULL)
  68. {
  69. bRet = FALSE;
  70. goto END;
  71. }
  72. // 复制文件
  73. while (1)
  74. {
  75. length = 4 * 1024;
  76. // 读取源文件
  77. status = ZwReadFile(hSrcFile,
  78. NULL,
  79. NULL,
  80. NULL,
  81. &Io_Status_Block,
  82. buffer,
  83. length,
  84. &offset,
  85. NULL);
  86. if (!NT_SUCCESS(status))
  87. {
  88. // 如果状态为 STATUS_END_OF_FILE,说明文件已经读取到末尾
  89. if (status == STATUS_END_OF_FILE)
  90. {
  91. bRet = TRUE;
  92. goto END;
  93. }
  94. }
  95. // 获得实际读取的长度
  96. length = (ULONG)Io_Status_Block.Information;
  97. // 写入到目标文件
  98. status = ZwWriteFile( hDestFile,
  99. NULL,
  100. NULL,
  101. NULL,
  102. &Io_Status_Block,
  103. buffer,
  104. length,
  105. &offset,
  106. NULL);
  107. if (!NT_SUCCESS(status))
  108. {
  109. bRet = FALSE;
  110. goto END;
  111. }
  112. // 移动文件指针
  113. offset.QuadPart += length;
  114. }
  115. }
  116. while (0);
  117. END:
  118. if (hSrcFile)
  119. {
  120. ZwClose(hSrcFile);
  121. }
  122. if (hDestFile)
  123. {
  124. ZwClose(hDestFile);
  125. }
  126. if (buffer != NULL)
  127. {
  128. ExFreePool(buffer);
  129. }
  130. return bRet;
  131. }
复制代码
  1. void ZwDeleteFileFolder(WCHAR *wsFileName)
  2. {
  3. NTSTATUS st;
  4. OBJECT_ATTRIBUTES ObjectAttributes;
  5. UNICODE_STRING UniFileName;
  6. //把 WCHAR*转化为 UNICODE_STRING
  7. RtlInitUnicodeString(&UniFileName, wsFileName);
  8. //设置包 OBJECT 对象并使用 ZwDeleteFile 删除
  9. InitializeObjectAttributes(&ObjectAttributes,
  10. &UniFileName,
  11. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  12. NULL,
  13. NULL);
  14. st=ZwDeleteFile(&ObjectAttributes);
  15. }
复制代码
  1. typedef struct _FILE_RENAME_INFORMATION
  2. {
  3. BOOLEAN ReplaceIfExists;
  4. HANDLE RootDirectory;
  5. ULONG FileNameLength;
  6. WCHAR FileName[1];
  7. } FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;
  8. NTSTATUS
  9. ZwRenameFile
  10. (
  11. IN PWSTR SrcFileName, // \??\x:\xxx\...\xxx.xxx
  12. IN PWSTR DstFileName // \??\x:\xxx\...\xxx.xxx
  13. )
  14. {
  15. #define RN_MAX_PATH 2048
  16. #define SFLT_POOL_TAG 'fuck'
  17. HANDLE FileHandle = NULL;
  18. OBJECT_ATTRIBUTES ObjectAttributes;
  19. IO_STATUS_BLOCK IoStatus;
  20. NTSTATUS Status;
  21. PFILE_RENAME_INFORMATION RenameInfo = NULL;
  22. UNICODE_STRING ObjectName;
  23. //设置重命名的信息
  24. RenameInfo = (PFILE_RENAME_INFORMATION)ExAllocatePoolWithTag(NonPagedPool,
  25. sizeof(FILE_RENAME_INFORMATION) + RN_MAX_PATH * sizeof(WCHAR), SFLT_POOL_TAG);
  26. if (RenameInfo == NULL)
  27. {
  28. return STATUS_INSUFFICIENT_RESOURCES;
  29. }
  30. RtlZeroMemory(RenameInfo, sizeof(FILE_RENAME_INFORMATION) + RN_MAX_PATH *
  31. sizeof(WCHAR));
  32. RenameInfo->FileNameLength = wcslen(DstFileName) * sizeof(WCHAR);
  33. wcscpy(RenameInfo->FileName, DstFileName);
  34. RenameInfo->ReplaceIfExists = 0;
  35. RenameInfo->RootDirectory = NULL;
  36. //设置源文件信息并获得句柄
  37. RtlInitUnicodeString(&ObjectName, SrcFileName);
  38. InitializeObjectAttributes(&ObjectAttributes,
  39. &ObjectName,
  40. OBJ_CASE_INSENSITIVE,
  41. NULL,
  42. NULL);
  43. Status = ZwCreateFile(&FileHandle,
  44. SYNCHRONIZE | DELETE,
  45. &ObjectAttributes,
  46. &IoStatus,
  47. NULL,
  48. 0,
  49. FILE_SHARE_READ,
  50. FILE_OPEN,
  51. FILE_SYNCHRONOUS_IO_NONALERT |
  52. FILE_NO_INTERMEDIATE_BUFFERING,
  53. NULL,
  54. 0);
  55. if (!NT_SUCCESS(Status))
  56. {
  57. ExFreePoolWithTag(RenameInfo, SFLT_POOL_TAG);
  58. return Status;
  59. }
  60. //最关键一步,利用 ZwSetInformationFile 来设置文件信息
  61. Status = ZwSetInformationFile(FileHandle,
  62. &IoStatus,
  63. RenameInfo,
  64. sizeof(FILE_RENAME_INFORMATION) +
  65. RN_MAX_PATH * sizeof(WCHAR),
  66. FileRenameInformation);
  67. if (!NT_SUCCESS(Status))
  68. {
  69. ExFreePoolWithTag(RenameInfo, SFLT_POOL_TAG);
  70. ZwClose(FileHandle);
  71. return Status;
  72. }
  73. ZwClose(FileHandle);
  74. return Status;
  75. }
复制代码
  1. //这里传入的是文件句柄不是文件名,大家尝试把这里改成传入文件名
  2. ULONG64 GetFileSize(HANDLE hfile)
  3. {
  4. IO_STATUS_BLOCK iostatus= {0};
  5. NTSTATUS ntStatus=0;
  6. FILE_STANDARD_INFORMATION fsi= {0};
  7. ntStatus=ZwQueryInformationFile(hfile,
  8. &iostatus,
  9. &fsi,
  10. sizeof(FILE_STANDARD_INFORMATION),
  11. FileStandardInformation);
  12. if(!NT_SUCCESS(ntStatus))
  13. return 0;
  14. return fsi.EndOfFile.QuadPart;
  15. }
复制代码
  1. NTKERNELAPI NTSTATUS ZwQueryDirectoryFile //最关键的 API
  2. (
  3. HANDLE FileHandle,
  4. HANDLE Event,
  5. PIO_APC_ROUTINE ApcRoutine,
  6. PVOID ApcContext,
  7. PIO_STATUS_BLOCK IoStatusBlock,
  8. PVOID FileInformation,
  9. ULONG Length,
  10. FILE_INFORMATION_CLASS FileInformationClass,
  11. BOOLEAN ReturnSingleEntry,
  12. PUNICODE_STRING FileName,
  13. BOOLEAN RestartScan
  14. );
  15. //几个常量
  16. #define INVALID_HANDLE_VALUE (HANDLE)-1
  17. #define MAX_PATH2 4096
  18. #define kmalloc(_s)ExAllocatePoolWithTag(NonPagedPool, _s, 'SYSQ')
  19. #define kfree(_p) ExFreePool(_p)
  20. //枚举文件用到的结构体
  21. typedef struct _FILE_BOTH_DIR_INFORMATION
  22. {
  23. ULONG NextEntryOffset;
  24. ULONG FileIndex;
  25. LARGE_INTEGER CreationTime;
  26. LARGE_INTEGER LastAccessTime;
  27. LARGE_INTEGER LastWriteTime;
  28. LARGE_INTEGER ChangeTime;
  29. LARGE_INTEGER EndOfFile;
  30. LARGE_INTEGER AllocationSize;
  31. ULONG FileAttributes;
  32. ULONG FileNameLength;
  33. ULONG EaSize;
  34. CCHAR ShortNameLength;
  35. WCHAR ShortName[12];
  36. WCHAR FileName[1];
  37. } FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;
  38. //山寨版 MyFindFirstFile
  39. HANDLE MyFindFirstFile(LPSTR lpDirectory,PFILE_BOTH_DIR_INFORMATION pDir,ULONG
  40. uLength)
  41. {
  42. char strFolder[MAX_PATH2]= {0};
  43. STRING astrFolder;
  44. UNICODE_STRING ustrFolder;
  45. OBJECT_ATTRIBUTES oa;
  46. IO_STATUS_BLOCK ioStatus;
  47. NTSTATUS ntStatus;
  48. HANDLE hFind = INVALID_HANDLE_VALUE;
  49. memset(strFolder,0,MAX_PATH2);
  50. strcpy(strFolder,"\\??\");
  51. strcat(strFolder,lpDirectory);
  52. RtlInitString(&astrFolder,strFolder);
  53. if (RtlAnsiStringToUnicodeString(&ustrFolder,&astrFolder,TRUE)==0)
  54. {
  55. InitializeObjectAttributes(&oa,&ustrFolder,OBJ_CASE_INSENSITIVE,NULL,NULL);
  56. ntStatus = IoCreateFile(
  57. &hFind,
  58. FILE_LIST_DIRECTORY | SYNCHRONIZE | FILE_ANY_ACCESS,
  59. &oa,
  60. &ioStatus,
  61. NULL,
  62. FILE_ATTRIBUTE_NORMAL,
  63. FILE_SHARE_READ | FILE_SHARE_WRITE,
  64. FILE_OPEN, //FILE_OPEN
  65. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
  66. FILE_OPEN_FOR_BACKUP_INTENT,
  67. NULL,
  68. 0,
  69. CreateFileTypeNone,
  70. NULL,
  71. IO_NO_PARAMETER_CHECKING);
  72. RtlFreeUnicodeString(&ustrFolder);
  73. if (ntStatus==0 && hFind!=INVALID_HANDLE_VALUE)
  74. {
  75. ntStatus=ZwQueryDirectoryFile(
  76. hFind, // File Handle
  77. NULL, // Event
  78. NULL, // Apc routine
  79. NULL, // Apc context
  80. &ioStatus, // IoStatusBlock
  81. pDir, // FileInformation
  82. uLength, // Length
  83. FileBothDirectoryInformation, // FileInformationClass
  84. TRUE, // ReturnSingleEntry
  85. NULL, // FileName
  86. FALSE //RestartScan
  87. );
  88. if (ntStatus!=0)
  89. {
  90. ZwClose(hFind);
  91. hFind=INVALID_HANDLE_VALUE;
  92. }
  93. }
  94. }
  95. return hFind;
  96. }
  97. //山寨版 MyFindNextFile
  98. BOOLEAN MyFindNextFile(HANDLE hFind, PFILE_BOTH_DIR_INFORMATION pDir, ULONG
  99. uLength)
  100. {
  101. IO_STATUS_BLOCK ioStatus;
  102. NTSTATUS ntStatus;
  103. ntStatus=ZwQueryDirectoryFile(
  104. hFind, // File Handle
  105. NULL, // Event
  106. NULL, // Apc routine
  107. NULL, // Apc context
  108. &ioStatus, // IoStatusBlock
  109. pDir, // FileInformation
  110. uLength, // Length
  111. FileBothDirectoryInformation, // FileInformationClass
  112. FALSE, // ReturnSingleEntry
  113. NULL, // FileName
  114. FALSE //RestartScan
  115. );
  116. if (ntStatus==0)
  117. return TRUE;
  118. else
  119. return FALSE;
  120. }
  121. //枚举文件夹内容的函数,输入路径,返回目录下的文件和文件夹数目
  122. ULONG SearchDirectory(LPSTR lpPath)
  123. {
  124. ULONG muFileCount=0;
  125. HANDLE hFind=INVALID_HANDLE_VALUE;
  126. PFILE_BOTH_DIR_INFORMATION pDir;
  127. char *strBuffer = NULL,*lpTmp=NULL;
  128. char strFileName[255*2];
  129. ULONG uLength=MAX_PATH2*2 + sizeof(FILE_BOTH_DIR_INFORMATION);
  130. strBuffer = (PCHAR)kmalloc(uLength);
  131. pDir = (PFILE_BOTH_DIR_INFORMATION)strBuffer;
  132. hFind=MyFindFirstFile(lpPath,pDir,uLength);
  133. if (hFind!=INVALID_HANDLE_VALUE)
  134. {
  135. kfree(strBuffer);
  136. uLength=(MAX_PATH2*2 + sizeof(FILE_BOTH_DIR_INFORMATION)) * 0x2000;
  137. strBuffer = (PCHAR)kmalloc(uLength);
  138. pDir = (PFILE_BOTH_DIR_INFORMATION)strBuffer;
  139. if (MyFindNextFile(hFind,pDir,uLength))
  140. {
  141. while (TRUE)
  142. {
  143. memset(strFileName,0,255*2);
  144. memcpy(strFileName,pDir->FileName,pDir->FileNameLength);
  145. if (strcmp(strFileName,"..")!=0 && strcmp(strFileName,".")!=0)
  146. {
  147. if (pDir->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  148. {
  149. DbgPrint("[目录]%S\n",strFileName);
  150. }
  151. else
  152. {
  153. DbgPrint("[文件]%S\n",strFileName);
  154. }
  155. muFileCount++;
  156. }
  157. if (pDir->NextEntryOffset==0) break;
  158. pDir = (PFILE_BOTH_DIR_INFORMATION)((char
  159. *)pDir+pDir->NextEntryOffset);
  160. }
  161. kfree(strBuffer);
  162. }
  163. ZwClose(hFind);
  164. }
  165. return muFileCount;
  166. }

复制代码
  1. void ZwCreateFolder(char *FolderPath)
  2. {
  3. NTSTATUS st;
  4. HANDLE FileHandle;
  5. OBJECT_ATTRIBUTES ObjectAttributes;
  6. IO_STATUS_BLOCK IoStatusBlock;
  7. UNICODE_STRING UniFileName;
  8. WCHAR wsFileName[2048]= {0};
  9. CharToWchar(FolderPath,wsFileName);
  10. RtlInitUnicodeString(&UniFileName, wsFileName);
  11. InitializeObjectAttributes(&ObjectAttributes,
  12. &UniFileName,
  13. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  14. NULL,
  15. NULL);
  16. st=IoCreateFile(&FileHandle,
  17. GENERIC_READ,
  18. &ObjectAttributes,
  19. &IoStatusBlock,
  20. 0,
  21. FILE_ATTRIBUTE_NORMAL,
  22. 0,
  23. FILE_CREATE,
  24. FILE_DIRECTORY_FILE,
  25. NULL,
  26. 0,
  27. 0,
  28. NULL,
  29. IO_NO_PARAMETER_CHECKING);
  30. if(NT_SUCCESS(st))
  31. ZwClose(FileHandle);
  32. }
复制代码


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|断点社区 |网站地图

GMT+8, 2025-1-24 19:19 , Processed in 0.069369 second(s), 26 queries .

Powered by XiunoBBS

Copyright © 2001-2025, 断点社区.

快速回复 返回顶部 返回列表