0

这是对我正在尝试做的事情的简短解释:

  • 读取 U 盘的 VolumeSerialNumber
  • 增加 VolumeSerialNumber
  • 将其写回闪存驱动器。

一般来说,它适用于使用 FAT 或 FAT32 作为文件系统的 USB 驱动器,但我无法让它与文件系统 exFAT 一起使用。正如文件系统规范(https://docs.microsoft.com/en-us/windows/win32/fileio/exfat-specification)中所述,我已经做了一些“特殊处理”,这对于 exFAT 来说似乎是必要的:

  • 在主引导扇区和备份引导扇区中将 VolumeFlag/VolumeDirty 设置为 true
  • 在主引导扇区和备份引导扇区中读取、递增和写回序列号
  • 重新计算并写回对应的主备校验和扇区中的BootChecksum
  • 将两个扇区的 VolumeDirty 标志设置为 false。

尝试写入备份扇区时,我遇到了一个普遍问题。当我在调用 WriteFile() 之后调用 ReadFile() 时,我总是会取回旧值。SetFilePointer() 似乎是正确的,因为我从 ReadFile() 获得了预期的值/范围,但在调用 WriteFile() 后值没有改变。

这只发生在备份扇区中。在主要部门内写作似乎有效。但由于主扇区和备份扇区的值不同,Windows 提示我再次格式化 USB 驱动器。

我正在使用 C#/.Net 框架。这是一个代码片段,可能是为了更好地理解(不完整)。

      [System.Runtime.InteropServices.DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int SetFilePointer(
    IntPtr hFile,
    int lDistanceToMove,
    ref int lpDistanceToMoveHigh,
    uint dwMoveMethod);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteFile(IntPtr hFile, byte[] lpBuffer,
   uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten,
   [In] ref System.Threading.NativeOverlapped lpOverlapped);


[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadFile(IntPtr hFile, byte[] lpBuffer,
   uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);

[System.Runtime.InteropServices.DllImport("Kernel32.dll", SetLastError = true)]
private extern static IntPtr CreateFile(
    String filename,
    UInt32 desiredAccess,
    UInt32 shareMode,
    IntPtr attributes,
    UInt32 creationDisposition,
    UInt32 flagsAndAttributes,
    IntPtr templateFile);

CloseHandle(...)
....

//example:
IntPtr exFatFileHandle = CreateFile(...);
//Set volume dirty flag...

///Starting with MainBoot
        int tempOut = 0;
        if (SetFilePointer(exFatFileHandle, 0, ref tempOut, 0) == -1)
        {
          return false;
        }

        byte[] bufferMainBoot = new byte[512];
        uint read;

        //reading first sector
        if (!ReadFile(exFatFileHandle, bufferMainBoot , 512, out read, IntPtr.Zero)) 
        {
          return false;
        }

        uint serial = BitConverter.ToUInt32(bufferMainBoot , 100); //get Serial at postion 100 (0x64) and icrement++
        serial++;
        byte[] bytesSerial = BitConverter.GetBytes(serial); //return serial as 4 bytes
         bytesSerial.CopyTo(bufferMainBoot , 100); //change values in sector buffer

        if (SetFilePointer(exFatFileHandle, 0, ref newtmp, 0) == -1) //jump to zero, maybe unnecessary..
        {
          return false;
        }

        if (!WriteFile(exFatFileHandle, bufferMainBoot , 512, out _, ref over)) //write back first sector with changed serial  
        {
          return false;
        }

//Now the same for Backup Boot with different offset at read and write
        int newtmp = 0;
        if (SetFilePointer(exFatFileHandle, 0, ref newtmp, 0) == -1) //jump to zero at first, maybe unnecessary..
        {
          return false;
        }
        if (SetFilePointer(exFatFileHandle, 0x1800, ref newtmp, 0) == -1)//jump to sector 12 (Backup Boot Sector)
        {
          return false;
        }

        byte[] bufferBackupBoot = new byte[512];
        uint read;

        //reading first sector
        if (!ReadFile(exFatFileHandle, bufferBackupBoot , 512, out read, IntPtr.Zero)) 
        {
          return false;
        }

        uint serial = BitConverter.ToUInt32(bufferBackupBoot , 100); //get Serial at postion 100 (0x64) and icrement++
        serial++;
        byte[] bytesSerial = BitConverter.GetBytes(serial); //return serial as 4 byte value
        bytesSerial.CopyTo(bufferBackupBoot , 100); //change values in sector buffer

        if (SetFilePointer(exFatFileHandle, 0, ref newtmp, 0) == -1) //jump to zero at first, maybe unnecessary..
        {
          return false;
        }
        if (SetFilePointer(exFatFileHandle, 0x1800, ref newtmp, 0) == -1)//jump to sector 12 (Backup Boot Sector)
        {
          return false;
        }
        if (!WriteFile(exFatFileHandle, bufferBackupBoot , 512, out _, ref over)) //write back first sector with changed serial  
        {
          return false;
        }

//Same procedure as for calculating and writing Checksum to sector
// 0x1600, sector 11 (checksum sector of MainBoot) and 
// 0x2E00, sector 23 (checksum sector of Backup Boot)
//Considering first 11 sectors for calculating the 32-Bit repeating checksum, should be right according to exFat specs. 

//set volumeDirty back to false...
//CloseHandle(...)

感谢您提前提供任何帮助或建议。

编辑 添加了 CreateFile、ReadFile、WriteFile、SetFilePointer 的调用。

4

0 回答 0