gpt4 book ai didi

C# WriteFile() 在 USB 驱动器的扇区 242 处停止写入

转载 作者:太空狗 更新时间:2023-10-29 18:36:04 32 4
gpt4 key购买 nike

我写了下面的代码来将 0xFF 写入我的 USB 存储设备上的所有字节。出于某种原因,WriteFile() 调用在扇区 242 处开始出错。我在两个单独的 USB 存储设备上完成了此操作,然后在十六进制编辑器中检查了这些设备。扇区 242 似乎是 FAT16 格式设备上文件分配表的开始,也是 NTFS 设备上引导区的开始。我敢肯定它在这些确切位置出错并非巧合,但我不知道如何改变这种行为。 WriteFile 失败时我收到的 HRESULT 是 -2147024891,即 E_ACCESSDENIED。有谁知道可能导致问题的原因是什么?

注意:如果您要在本地系统上运行此代码,请务必小心,因为我已经为我的 USB 设备硬编码了物理设备 ID。请确保使用您尝试写入的设备更新 deviceId 变量。你不想破坏你的硬盘。

    public enum EMoveMethod : uint
{
Begin = 0,
Current = 1,
End = 2
}

[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint SetFilePointer([In] SafeFileHandle hFile, [In] long lDistanceToMove, [Out] out int lpDistanceToMoveHigh, [In] EMoveMethod dwMoveMethod);

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);

[DllImport("kernel32", SetLastError = true)]
internal extern static int ReadFile(SafeFileHandle handle, byte[] bytes, int numBytesToRead, out int numBytesRead, IntPtr overlapped_MustBeZero);

[DllImport("kernel32.dll", SetLastError = true)]
internal extern static int WriteFile(SafeFileHandle handle, byte[] bytes, int numBytesToWrite, out int numBytesWritten, IntPtr overlapped_MustBeZero);

[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
private static extern bool DeviceIoControl(SafeFileHandle hDevice, uint dwIoControlCode, byte[] lpInBuffer, int nInBufferSize, byte[] lpOutBuffer, int nOutBufferSize, out int lpBytesReturned, IntPtr lpOverlapped);

[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
private static extern bool CloseHandle(SafeFileHandle handle);

public void wipeDisk()
{
const uint OPEN_EXISTING = 3;
const uint GENERIC_WRITE = (0x40000000);
const uint FSCTL_LOCK_VOLUME = 0x00090018;
const uint FSCTL_UNLOCK_VOLUME = 0x0009001c;
const uint FSCTL_DISMOUNT_VOLUME = 0x00090020;

bool success = false;
int intOut;
string deviceId = @"\\.\PHYSICALDRIVE2";
long DiskSize = 2056320000;

SafeFileHandle diskHandle = CreateFile(deviceId, GENERIC_WRITE, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
if (diskHandle.IsInvalid)
{
Console.WriteLine(deviceId + " open error.");
return;
}

Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": opened.");

success = DeviceIoControl(diskHandle, FSCTL_LOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
if (!success)
{
Console.WriteLine(deviceId + " lock error.");
CloseHandle(diskHandle);
return;
}

Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": locked.");

success = DeviceIoControl(diskHandle, FSCTL_DISMOUNT_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
if (!success)
{
Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": dismount error.");
DeviceIoControl(diskHandle, FSCTL_UNLOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
CloseHandle(diskHandle);
return;
}

Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": unmounted.");

int numBytesPerSector = 512;
long numTotalSectors = DiskSize / 512;

byte[] junkBytes = new byte[512];
for (int x = 0; x < 512; x++)
{
junkBytes[x] = 0xFF;
}

for (long sectorNum = 0; sectorNum < numTotalSectors; sectorNum++)
{
int numBytesWritten = 0;
int moveToHigh;

uint rvalsfp = SetFilePointer(diskHandle, sectorNum * numBytesPerSector, out moveToHigh, EMoveMethod.Begin);

Console.WriteLine("File pointer set " + Marshal.GetHRForLastWin32Error().ToString() + ": " + (sectorNum * numBytesPerSector).ToString());

int rval = WriteFile(diskHandle, junkBytes, junkBytes.Length, out numBytesWritten, IntPtr.Zero);

if (numBytesWritten != junkBytes.Length)
{
Console.WriteLine("Write error on track " + sectorNum.ToString() + " from " + (sectorNum * numBytesPerSector).ToString() + "-" + moveToHigh.ToString() + " " + Marshal.GetHRForLastWin32Error().ToString() + ": Only " + numBytesWritten.ToString() + "/" + junkBytes.Length.ToString() + " bytes written.");
break;
}
else
{
Console.WriteLine("Write success " + Marshal.GetHRForLastWin32Error().ToString() + ": " + numBytesWritten.ToString() + "/" + junkBytes.Length.ToString() + " bytes written.");
}
}

success = DeviceIoControl(diskHandle, FSCTL_UNLOCK_VOLUME, null, 0, null, 0, out intOut, IntPtr.Zero);
if (success)
{
Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": unlocked.");
}
else
{
Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": unlock error: " + Marshal.GetHRForLastWin32Error().ToString());
}

success = CloseHandle(diskHandle);
if (success)
{
Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": handle closed.");
}
else
{
Console.WriteLine(deviceId + " " + Marshal.GetHRForLastWin32Error().ToString() + ": close handle error: " + Marshal.GetHRForLastWin32Error().ToString());
}
}

编辑/更新

在使用第三方工具对 USB 设备进行低级别删除后,我能够成功实现此功能。驱动器完全清零后,我能够成功写入设备。似乎 Windows 在识别出有效的 fat 或 ntfs 文件系统以及使用

    const uint FSCTL_LOCK_VOLUME = 0x00090018;
const uint FSCTL_DISMOUNT_VOLUME = 0x00090020;

DeviceIoControl 配对似乎不会覆盖设备上的锁定窗口。

有谁知道如何在具有有效文件系统的驱动器上使用 DeviceIoControl 在 Windows 中成功锁定可移动 USB 设备?

我已经使用了几个第三方工具来完成我想做的事情,并且它们都能成功运行。我知道这是可能的,但我阅读的所有 MSDN 文档都没有帮助解决问题。

编辑/更新 2

这取自https://web.archive.org/web/20130507212546/http://msdn.microsoft.com/en-us/library/ff551353.aspx

The application needs to lock the volume, dismount the volume, or both, before it can issue DASD I/O. This is new to Windows Vista and was done to address potentially malicious techniques.

  1. The file system will block all write operations to reserved sections of the disk. In this case, those reserved sections include the MBR and the two FAT areas. To block these areas, you need to lock the volume by sending FSCTL_LOCK_VOLUME. You must issue this structure on the same volume handle that performs the actual write operations. This request can fail if there are open file handles. In this case, the application can force a dismount of the file system by issuing FSCTL_DISMOUNT_VOLUME. However, the volume is not actually dismounted until the file handle is closed. Until then, the application can continue to issue DASD I/O by using the same file handle that is currently open.

  2. There is an extended region beyond the volume space that is known to the file system where write operations will be blocked. To allow write operations to this region, you must issue FSCTL_ALLOW_EXTENDED_DASD_IO on the volume handle.

You can use the Win32 API routine DeviceIoControl to issue all the previous FSCTSs.

我相信这正是我们在上面的代码中实现的,但它似乎没有正常工作。我们正在获取句柄并正在锁定和卸载设备,因此我们应该能够正确地写入 protected 区域?

编辑/更新 3

好的,这是当前打开磁盘和卷的顺序。锁定、卸载等方法按照我们认为错误的顺序工作。

SafeFileHandle volumeHandle = CreateFile("\\.\E:",...);
LockVolume(volumeHandle);
DismountVolume(volumeHandle);
SafeFileHandle diskHandle = CreateFile("\\.\PHYSICALDRIVE1"...);
WriteStuff(diskHandle);
//Fails...
UnlockVolume(volumeHandle);
CloseVolume(volumeHandle);
CloseDisk(diskHandle);

我仍然得到相同的结果,它只在磁盘被丢弃时有效。

最佳答案

diskdrive 之间存在混淆。

如果你想完全访问一个磁盘(你正在使用\\.\PHYSICALDRIVE),你必须锁定所有挂载的卷,它们基​​本上是物理磁盘的所有分区(即驱动器)

不是在 CreateFile("\\.\PHYSICALDRIVE"...) 返回的句柄上使用 FSCTL_LOCK_VOLUME,而是获取每个已安装卷的句柄(这是一个驱动器,而不是物理磁盘)使用 string.Replace("\\\\.\\{0}:", DriveLetter) 模式。

您可以使用 IOCTL_DISK_GET_DRIVE_LAYOUT 获取给定物理磁盘的已安装卷列表(最终,您需要一个字母列表)。


编辑:

来自 MSDN :

A write on a disk handle will succeed if one of the following conditions is true:

The sectors to be written to do not fall within a volume's extents.

The sectors to be written to fall within a mounted volume, but you have explicitly locked or dismounted the volume by using FSCTL_LOCK_VOLUME or FSCTL_DISMOUNT_VOLUME.

The sectors to be written to fall within a volume that has no mounted file system other than RAW.

所以基本上,您应该做的是:

  • 获取每个卷的句柄
  • 在每个卷上使用FSCTL_LOCK_VOLUME FSCTL_DISMOUNT_VOLUME。如果卷中没有文件正在使用(即任何进程都没有打开任何文件的句柄),FSCTL_LOCK_VOLUME 就足够了
  • 获取物理磁盘的句柄
  • 写入物理磁盘
  • 关闭两个 handle 。关闭音量句柄将释放锁定。

还要确保您正在使用管理员权限(提升的进程)运行您的应用程序。

关于C# WriteFile() 在 USB 驱动器的扇区 242 处停止写入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12081343/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com