内核态调用ZwSetInformationFile重命名文件遇0xc0000034错误求助
内核态调用ZwSetInformationFile重命名文件返回STATUS_OBJECT_NAME_NOT_FOUND问题
我尝试在内核态下通过ZwSetInformationFile重命名文件,原文件能成功打开句柄,但调用API始终返回0xc0000034(STATUS_OBJECT_NAME_NOT_FOUND)错误。代码实现如下:
NTSTATUS Files::RenameFile(WCHAR* OriginalName, WCHAR* NewName) { // MSDN说明,调用ZwSetInformationFile时驱动必须处于IRQL PASSIVE_LEVEL级别 if (KeGetCurrentIrql() != PASSIVE_LEVEL) { printf("IRQL invalid\n"); return STATUS_INVALID_LEVEL; } // 打开文件句柄,OriginalName需传入完整路径,示例:"\\DosDevices\\C:\\named_file.txt" // 重命名文件需DELETE权限,这里假设GENERIC_ALL已包含足够权限 auto FileHandle = Files(OriginalName, Files::OpenExisting, GENERIC_ALL, 0); if (FileHandle.CreationStatus != STATUS_SUCCESS) { printf("Failed to open handle to file %ws. ERR: 0x%x\n", OriginalName, FileHandle.CreationStatus); return FileHandle.CreationStatus; } IO_STATUS_BLOCK ioStatusBlock; // MSDN说明,使用FileRenameInformation时,大小需为结构体大小加上新名称的字节数 const auto size = sizeof(FILE_RENAME_INFORMATION) + sizeof(NewName); // 为结构体分配内存 const auto rename_info = static_cast<PFILE_RENAME_INFORMATION>(ExAllocatePool(PagedPool, size)); if(rename_info == nullptr) { printf("Failed allocating rename info structure\n"); FileHandle.Close(); return STATUS_INSUFFICIENT_RESOURCES; } memset(rename_info, 0, size); wcscpy(rename_info->FileName, NewName); rename_info->FileNameLength = sizeof(NewName);// 字节数 rename_info->RootDirectory = nullptr; // MSDN:若文件名是绝对路径则必须为null rename_info->ReplaceIfExists = false; // 若文件已存在则不替换 const auto status = ZwSetInformationFile(FileHandle.hFile, &ioStatusBlock, rename_info, size, FileRenameInformation); // 释放资源 ExFreePool(rename_info); FileHandle.Close(); // ZwSetInformationFile返回0xc0000034(STATUS_OBJECT_NAME_NOT_FOUND)错误 if(status != STATUS_SUCCESS) { printf("0x%x : %ws\n", status, rename_info->FileName); // -> 0xc0000034 : "\\DosDevices\\C:\\renamed_file.txt" return status; } printf("Renamed %ws to %ws\n", OriginalName, NewName); return STATUS_SUCCESS; }
问题根源及修复方案
核心错误在于字符串长度计算逻辑错误:sizeof(NewName)获取的是指针本身的大小(32位系统4字节,64位系统8字节),而非NewName指向的宽字符串实际字节数。这导致分配的内存空间不足,且传递给FileNameLength的长度完全错误,内核无法正确解析新文件名,因此返回STATUS_OBJECT_NAME_NOT_FOUND。
修复步骤:
修正内存分配大小计算
用宽字符串实际长度乘以sizeof(WCHAR)得到字节数,再加上结构体本身大小:ULONG nameBytes = wcslen(NewName) * sizeof(WCHAR); const auto size = sizeof(FILE_RENAME_INFORMATION) + nameBytes;修正FileNameLength的值
FileNameLength需设置为新文件名的实际字节数(不含终止符):rename_info->FileNameLength = nameBytes;替换不安全的字符串拷贝函数
避免wcscpy的缓冲区溢出风险,改用RtlCopyMemory:RtlCopyMemory(rename_info->FileName, NewName, nameBytes);补充文件打开的共享模式
重命名操作需要FILE_SHARE_DELETE权限,打开原文件时需添加该共享模式:auto FileHandle = Files(OriginalName, Files::OpenExisting, GENERIC_ALL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE);
修复后的完整代码片段
NTSTATUS Files::RenameFile(WCHAR* OriginalName, WCHAR* NewName) { if (KeGetCurrentIrql() != PASSIVE_LEVEL) { printf("IRQL invalid\n"); return STATUS_INVALID_LEVEL; } // 添加FILE_SHARE_DELETE确保重命名操作可执行 auto FileHandle = Files(OriginalName, Files::OpenExisting, GENERIC_ALL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE); if (FileHandle.CreationStatus != STATUS_SUCCESS) { printf("Failed to open handle to file %ws. ERR: 0x%x\n", OriginalName, FileHandle.CreationStatus); return FileHandle.CreationStatus; } IO_STATUS_BLOCK ioStatusBlock; // 计算新文件名的实际字节数 ULONG nameBytes = wcslen(NewName) * sizeof(WCHAR); const auto size = sizeof(FILE_RENAME_INFORMATION) + nameBytes; const auto rename_info = static_cast<PFILE_RENAME_INFORMATION>(ExAllocatePool(PagedPool, size)); if(rename_info == nullptr) { printf("Failed allocating rename info structure\n"); FileHandle.Close(); return STATUS_INSUFFICIENT_RESOURCES; } memset(rename_info, 0, size); // 安全拷贝字符串 RtlCopyMemory(rename_info->FileName, NewName, nameBytes); rename_info->FileNameLength = nameBytes; rename_info->RootDirectory = nullptr; rename_info->ReplaceIfExists = false; const auto status = ZwSetInformationFile(FileHandle.hFile, &ioStatusBlock, rename_info, size, FileRenameInformation); ExFreePool(rename_info); FileHandle.Close(); if(status != STATUS_SUCCESS) { printf("0x%x : %ws\n", status, NewName); return status; } printf("Renamed %ws to %ws\n", OriginalName, NewName); return STATUS_SUCCESS; }
内容的提问来源于stack exchange,提问作者Systernarls_dude
相关产品推荐
相关产品推荐

