登录  | 立即注册

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

查看: 216|回复: 1

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

[复制链接]

89

主题

2

回帖

36

积分

网站编辑

积分
36
发表于 2025-1-22 22:20:02 | 显示全部楼层 |阅读模式

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.复制文件(包括了读文件、写文件)
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);
}

0

主题

203

回帖

170

积分

注册会员

积分
170
发表于 2025-2-20 16:13:12 | 显示全部楼层
好好学习 ,天天向上1
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-4-11 18:24 , Processed in 0.098938 second(s), 23 queries , Yac On.

Powered by XiunoBBS

Copyright © 2001-2025, 断点社区.

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