C# How to get capability HardwareDisabled property for hardware device - c#

I am trying to tell if a hardware device (specifically multitouch digitizer) is disabled.
I can successfully enable/disable the device using the DisableHardware class from here.
I have found the DEVICE_CAPABILITIES struct with property HardwareDisabled. But if I call SetupDiGetDeviceRegistryPropertyW, to return SPDRP_CAPABILITIES, I am unable to convert the returned value (DWORD) to useful uint.
I believe my conversion is wrong from byte[] => uint, I always get 128.
private static bool IsDeviceHardwareDisabeld(IntPtr info, SP_DEVINFO_DATA devdata)
{
Trace.WriteLine("IsDeviceHardwareDisabeld");
uint SPDRP_CAPABILITIES = 0x0000000F;
uint CM_DEVCAP_HARDWAREDISABLED = 16384u;
uint propId = SPDRP_CAPABILITIES;
uint proptype, outsize;
IntPtr buffer = IntPtr.Zero;
try
{
uint buflen = 512;
buffer = Marshal.AllocHGlobal((int)buflen);
outsize = 0;
SetupDiGetDeviceRegistryPropertyW(
info,
ref devdata,
propId,
out proptype,
buffer,
buflen,
ref outsize);
Trace.WriteLine("OUTSIZE: " + outsize.ToString()); // 4
byte[] lbuffer = new byte[outsize];
Marshal.Copy(buffer, lbuffer, 0, (int)outsize);
int errcode = Marshal.GetLastWin32Error();
if (errcode == ERROR_INVALID_DATA) throw new Exception("ERROR_INVALID_DATA");
CheckError("SetupDiGetDeviceRegistryPropertyW", errcode);
uint capabilities = BitConverter.ToUInt32(lbuffer, 0); // always 128
uint bitwise = capabilities & CM_DEVCAP_HARDWAREDISABLED; // always 0
bool isHardwareDisabled = bitwise > 0;
Trace.WriteLine("HARDWAREDISABLED: " + isHardwareDisabled.ToString());
return isHardwareDisabled;
}
finally
{
if (buffer != IntPtr.Zero)
Marshal.FreeHGlobal(buffer);
}
}
My conversion always returns 128 for value of DEVICE_CAPABILITIES.

Related

Using DeviceIoControl from C# code always returns empty output buffer

I have a driver, which I want to use from my C# client app. The issue here is that my output buffer is always empty (0). When I use this driver from C code - everything works like a charm, so I think the issue is in my client C# code.
Extern is defined as below:
[DllImport(kernel, EntryPoint = "DeviceIoControl", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DeviceIoControl(
SafeFileHandle hDevice,
UInt32 dwIoControlCode,
IntPtr lpInBuffer,
UInt32 nInBufferSize,
IntPtr lpOutBuffer,
UInt32 nOutBufferSize,
ref UInt32 lpBytesReturned,
[In] ref NativeOverlapped lpOverlapped);
And I am using it as:
public static T ReadVirtualMemory<T>(SafeFileHandle driverHandle, int offset) where T : unmanaged
{
var inBuffer = (object)new T();
var nInBufferSize = Marshal.SizeOf(typeof(T));
var outBuffer = (object)new T();
var nOutBufferSize = Marshal.SizeOf(typeof(T));
var data = new KERNEL_READ_REQUEST
{
Address = (ulong)offset,
Size = (ulong)nInBufferSize,
pBuffer = (IntPtr)inBuffer
};
IntPtr lpInBuffer = IntPtr.Zero;
IntPtr lpOutBuffer = IntPtr.Zero;
nInBufferSize = Marshal.SizeOf(data);
lpInBuffer = Marshal.AllocHGlobal(nInBufferSize);
Marshal.StructureToPtr(data, lpInBuffer, true);
lpOutBuffer = Marshal.AllocHGlobal(nOutBufferSize);
Marshal.StructureToPtr(outBuffer, lpOutBuffer, true);
UInt32 lpBytesReturned = 0;
NativeOverlapped lpOverlapped = new NativeOverlapped();
Kernel32.DeviceIoControl(
driverHandle,
(uint)DriverMethod.ReadMemory,
lpInBuffer,
(uint)nInBufferSize,
lpOutBuffer,
(uint)nOutBufferSize,
ref lpBytesReturned,
ref lpOverlapped);
outBuffer = (T)Marshal.PtrToStructure(lpOutBuffer, typeof(T));
return lpBytesReturned == nOutBufferSize ? (T)outBuffer : default;
}
I am not sure why, bytes returned = 8, though it should be 4. And as I've said - out buffer is empty.
Drver's code:
PKERNEL_READ_REQUEST readRequest = (PKERNEL_READ_REQUEST)pIrp->AssociatedIrp.SystemBuffer;
PEPROCESS process;
if (NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, &process)))
{
DebugMessage("ReadRequest requested\n");
KernelReadVirtualMemory(process, readRequest->Address, readRequest->pBuffer, readRequest->Size);
byteIo = sizeof(PKERNEL_READ_REQUEST);
status = STATUS_SUCCESS;
}
and
NTSTATUS NTAPI MmCopyVirtualMemory
(
PEPROCESS SourceProcess,
PVOID SourceAddress,
PEPROCESS TargetProcess,
PVOID TargetAddress,
SIZE_T BufferSize,
KPROCESSOR_MODE PreviousMode,
PSIZE_T ReturnSize
);
NTSTATUS KernelReadVirtualMemory(PEPROCESS process, PVOID sourceAddress, PVOID targetAddress, SIZE_T size)
{
PSIZE_T bytes;
return MmCopyVirtualMemory(process, sourceAddress, PsGetCurrentProcess(), targetAddress, size, KernelMode, &bytes);
}
Probably this is smth about structure alignment, but I am not sure (In C client app sizeof structure is 18 bytes, in C# 32 bytes).
Please advise
First - I had to compile in x64.
Second - had to allocate memory for pBuffer
Below is a working example
var nInBufferSize = Marshal.SizeOf(typeof(T));
var inBuffer = Marshal.AllocHGlobal(nInBufferSize);
var data = new KERNEL_READ_REQUEST
{
Address = offset,
Size = nInBufferSize,
pBuffer = inBuffer
};
var requestSize = Marshal.SizeOf(data);
var requestBuffer = Marshal.AllocHGlobal(requestSize);
Marshal.StructureToPtr(data, requestBuffer, true);
uint bytesReturned = 0;
var overlapped = new NativeOverlapped();
Kernel32.DeviceIoControl(
driverHandle,
(uint)DriverMethod.ReadMemory,
requestBuffer,
(uint)requestSize,
requestBuffer,
(uint)requestSize,
ref bytesReturned,
ref overlapped);
var result = Marshal.PtrToStructure(data.pBuffer, typeof(T));
return (T?)result ?? default;

C# Reading process memory returning wrong values

i'm trying to read some values from process memory with multiple pointers/offsets
on my console .Net App but i'm getting the wrong last 3 values, i don't know what i'm doing wrong I've been checking the code and trying different ways for hours but still the same results.
I'm reading these values from a 64-bit process
Here's a preview from my app and cheat engine at the same time (cheat engine contains the correct values).
Here is my code for reading these pointers :
Memory.OpenProcess(Data.Core.ProcessID);
Data.Core.GameBase = (uint)Memory.BaseAddress("Game.dll");
uint Num0 = Memory.ReadInt((int)Data.Core.GameBase +
(int)Data.Core.Offsets.Animation);
uint Num1 = Memory.ReadInt((int)Num0 + (int)Data.Core.Offsets.P1);
uint Num2 = Memory.ReadInt((int)Num1 + (int)Data.Core.Offsets.P2);
uint Num3 = Memory.ReadInt((int)Num2 + (int)Data.Core.Offsets.P3);
uint Num4 = Memory.ReadInt((int)Num3 + (int)Data.Core.Offsets.P4);
uint Num5 = Memory.ReadInt((int)Num4 + (int)Data.Core.Offsets.P5);
ReadInt function :
public uint ReadInt(int iMemoryAddress)
{
byte[] bBuffer = new byte[4];
IntPtr lpNumberOfBytesRead;
if (Mapi.ReadProcessMemory(this._hReadProcess, (IntPtr) iMemoryAddress,
bBuffer, 4U, out lpNumberOfBytesRead) == 0)
return 0;
return BitConverter.ToUInt32(bBuffer, 0);
}
also :
public uint ReadInt(int Address)
{
OpenProcessMemory();
int BytesRead = 0;
byte[] Data = new byte[4];
ReadProcessMemory((int)PHandle, Address, Data, 4, ref BytesRead);
CloseProcessMemory();
return BitConverter.ToUInt32(Data, 0);
}
Offsets enum :
public enum Offsets : uint
{
Animation = 0x1494198,
P1 = 0x68,
P2 = 0x70,
P3 = 0x28,
P4 = 0x378,
P5 = 0x522,
}
win api :
[DllImport("kernel32.dll")]
public static extern int ReadProcessMemory(IntPtr hProcess, IntPtr
lpBaseAddress, [In, Out] byte[] bBuffer, uint size, out IntPtr
lpNumberOfBytesRead);
I've tried to add pointers and offsets using IntPtr / uint / int / Int32 for each Pointer+Offset but still the same weird values at the end.
I think i can't do more than this obviously..
If the target process is x64, then you need to also compile for x64 and you should use IntPtr for all pointers, offsets and addresses to ensure they are the correct length to accept 64 bit addresses.
For walking pointer chains you should use this function which de-references each pointer and then adds the offset for you.
public static IntPtr FindDMAAddy(IntPtr hProc, IntPtr ptr, int[] offsets)
{
var buffer = new byte[IntPtr.Size];
foreach (int i in offsets)
{
ReadProcessMemory(hProc, ptr, buffer, buffer.Length, out var read);
ptr = (IntPtr.Size == 4)
? IntPtr.Add(new IntPtr(BitConverter.ToInt32(buffer, 0)), i)
: ptr = IntPtr.Add(new IntPtr(BitConverter.ToInt64(buffer, 0)), i);
}
return ptr;
}
var ammoAddr = FindDMAAddy(hProc, (IntPtr)(modBase + 0x10f4f4), new int[] { 0x374, 0x14, 0 });

How to find allocated (independent) memory section from another process?

I mean how To find a section was allocated by another program in another process fastly, and it's size is (8 Bytes) so when i use this code :
public static uint FindSignature(IntPtr hProcess, byte[] sigBuffer)
{
byte[] lpBuffer = new byte[524288];
uint lpNumberOfBytesRead = 0;
uint CurAddr = 0x00000000;
bool Result = false;
Result = ReadProcessMemory(hProcess, CurAddr, lpBuffer, 524288, out lpNumberOfBytesRead);
while (CurAddr + 524288 <= 0x7FFFFFFF)
{
if (Result != false)
{
int Index = ByteSearch(lpBuffer, sigBuffer);
if (Index != -1)
{
return (uint)(CurAddr + Index);
}
}
CurAddr += (uint)(524288 - sigBuffer.Length);
Result = ReadProcessMemory(hProcess, CurAddr, lpBuffer, 524288, out lpNumberOfBytesRead);
}
return 0;
}
I can't find it because i read 512 KB at the same time so it returns false.
And thanks.

WriteFile returning error code 87

I am working on a program that is writing to an HID device and am getting the error 87, Invalid parameter on the WriteFile function. I got the functions from Jan Axelson's USB Complete so I'm not sure why I am getting the error.
I am using this to find my device:
private void USBInit()
{
IntPtr deviceInfoSet;
Int32 memberIndex = 0;
SP_DEVICE_INTERFACE_DATA MyDeviceInterfaceData = new SP_DEVICE_INTERFACE_DATA();
Int32 bufferSize = 0;
IntPtr detailDataBuffer;
Boolean success = false;
deviceFound = false;
HidD_GetHidGuid(ref hidGuid); // Get the GUID
deviceInfoSet = SetupDiGetClassDevs // Get pointer to a device info set
(ref hidGuid,
IntPtr.Zero,
IntPtr.Zero,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
do
{
MyDeviceInterfaceData.cbSize = Marshal.SizeOf(MyDeviceInterfaceData); // Identify Device Interface
success = SetupDiEnumDeviceInterfaces
(deviceInfoSet,
IntPtr.Zero,
ref hidGuid,
memberIndex,
ref MyDeviceInterfaceData);
success = SetupDiGetDeviceInterfaceDetail // Request Structure with Device Path Name
(deviceInfoSet,
ref MyDeviceInterfaceData,
IntPtr.Zero,
0,
ref bufferSize,
IntPtr.Zero);
detailDataBuffer = Marshal.AllocHGlobal(bufferSize);
Marshal.WriteInt32(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8);
success = SetupDiGetDeviceInterfaceDetail
(deviceInfoSet,
ref MyDeviceInterfaceData,
detailDataBuffer,
bufferSize,
ref bufferSize,
IntPtr.Zero);
IntPtr pDevicePathName = new IntPtr(detailDataBuffer.ToInt32() + 4);
devicePathName = Marshal.PtrToStringAuto(pDevicePathName);
Marshal.FreeHGlobal(detailDataBuffer);
/* Request Communications Handle */
deviceHandle = CreateFile
(devicePathName,
(GENERIC_WRITE | GENERIC_READ),
FILE_SHARE_READ | FILE_SHARE_WRITE,
IntPtr.Zero,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
0);
/* Get Vendor ID and Product ID */
DeviceAttributes.Size = Marshal.SizeOf(DeviceAttributes);
success = HidD_GetAttributes(deviceHandle, ref DeviceAttributes);
// Compare Vendor ID and Product ID.
if ((DeviceAttributes.VendorID == myVendorID) && (DeviceAttributes.ProductID == myProductID))
{
MessageBoxResult res = System.Windows.MessageBox.Show("Device Found", "K-IX", MessageBoxButton.OK);
deviceFound = true;
/* Get pointer to capabilities */
success = HidD_GetPreparsedData(deviceHandle, ref preparsedData);
/* Get Device Capabilities */
Int32 result = 0;
result = HidP_GetCaps(preparsedData, ref Capabilities);
return;
}
else
{
// Not my device
memberIndex++;
deviceHandle.Close();
if (memberIndex == 128)
{ break; }
}
} while (!deviceFound);
}
And this is the code I am using to try to send to the device:
private void SendUSB()
{
Int32 numberOfBytesWritten = 0;
Byte[] outputReportBuffer = null;
Boolean success;
Boolean success2;
// Set size of the Output report buffer.
Array.Resize(ref outputReportBuffer, Capabilities.InputReportByteLength);
// Store Report ID in first byte of header.
outputReportBuffer[0] = 0;
// Store report data following the Report ID.
outputReportBuffer[1] = 0x01;
//outputReportBuffer[2] = 0x02;
// outputReportBuffer[3] = 0x03;
// Send Report
success = WriteFile
(deviceHandle,
outputReportBuffer,
outputReportBuffer.Length,
ref numberOfBytesWritten,
IntPtr.Zero);
if (!success)
{
Int32 lastError = Marshal.GetLastWin32Error();
}
success2 = HidD_FreePreparsedData(preparsedData);
}
I have verified that my report length expected for the device is 2, but am not sure where to go from here as USB and HID programming are new for me.
You specified FILE_FLAG_OVERLAPPED in the CreateFile() call but pass a null for the lpOverlapped argument in the WriteFile() call. That's not legal.
Remove the FILE_FLAG_OVERLAPPED option.

Programatically change FAT32 volume serial number

How do I programatically change Volume Serial of a Fat32 partition from C#. I found this example, but it is written with C++ which I don't read well. Could someone please answer a C# code snippet?
Update:
I can see the C++ function from above example which I think it's possible to direct port to C#
void CVolumeSerialDlg::ChangeSerialNumber(DWORD Drive, const DWORD newSerial)
{
const max_pbsi = 3;
struct partial_boot_sector_info
{
LPSTR Fs; // file system name
DWORD FsOffs; // offset of file system name in the boot sector
DWORD SerialOffs; // offset of the serialnumber in the boot sector
};
partial_boot_sector_info pbsi[max_pbsi] =
{
{"FAT32", 0x52, 0x43},
{"FAT", 0x36, 0x27},
{"NTFS", 0x03, 0x48}
};
TCHAR szDrive[12];
char Sector[512];
DWORD i;
sprintf(szDrive, "%c:\\", Drive & 0xFF);
if (!disk.Open(szDrive))
{
ShowErrorString("Could not open disk!");
return;
}
// read sector
if (!disk.ReadSector(0, Sector))
{
ShowErrorString("Could not read sector!");
return;
}
// try to search for a valid boot sector
for (i=0;i<max_pbsi;i++)
{
if (strncmp(pbsi[i].Fs, Sector+pbsi[i].FsOffs, strlen(pbsi[i].Fs)) == 0)
{
// we found a valid signature
break;
}
}
if (i >= max_pbsi)
{
MessageBox(_T("Cannot change serial number of this file system!"),
_T("Error"), MB_ICONERROR);
return;
}
// patch serial number
*(PDWORD)(Sector+pbsi[i].SerialOffs) = newSerial;
// write boot sector
if (!disk.WriteSector(0, Sector))
{
ShowErrorString("Could not write sector!");
return;
}
ShowErrorString("Volume serial number changed successfully!\r"
"You might want to restart your system for changes to take effect!");
}
No guarantees, be careful.
void ChangeSerialNumber(char volume, uint newSerial)
{
var fsInfo = new[]
{
new { Name = "FAT32", NameOffs = 0x52, SerialOffs = 0x43 },
new { Name = "FAT", NameOffs = 0x36, SerialOffs = 0x27 },
new { Name = "NTFS", NameOffs = 0x03, SerialOffs = 0x48 }
};
using (var disk = new Disk(volume))
{
var sector = new byte[512];
disk.ReadSector(0, sector);
var fs = fsInfo.FirstOrDefault(
f => Strncmp(f.Name, sector, f.NameOffs)
);
if (fs == null) throw new NotSupportedException("This file system is not supported");
var s = newSerial;
for (int i = 0; i < 4; ++i, s >>= 8) sector[fs.SerialOffs + i] = (byte)(s & 0xFF);
disk.WriteSector(0, sector);
}
}
bool Strncmp(string str, byte[] data, int offset)
{
for(int i = 0; i < str.Length; ++i)
{
if (data[i + offset] != (byte)str[i]) return false;
}
return true;
}
class Disk : IDisposable
{
private SafeFileHandle handle;
public Disk(char volume)
{
var ptr = CreateFile(
String.Format("\\\\.\\{0}:", volume),
FileAccess.ReadWrite,
FileShare.ReadWrite,
IntPtr.Zero,
FileMode.Open,
0,
IntPtr.Zero
);
handle = new SafeFileHandle(ptr, true);
if (handle.IsInvalid) Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
public void ReadSector(uint sector, byte[] buffer)
{
if (buffer == null) throw new ArgumentNullException("buffer");
if (SetFilePointer(handle, sector, IntPtr.Zero, EMoveMethod.Begin) == INVALID_SET_FILE_POINTER) Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
uint read;
if (!ReadFile(handle, buffer, buffer.Length, out read, IntPtr.Zero)) Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
if (read != buffer.Length) throw new IOException();
}
public void WriteSector(uint sector, byte[] buffer)
{
if (buffer == null) throw new ArgumentNullException("buffer");
if (SetFilePointer(handle, sector, IntPtr.Zero, EMoveMethod.Begin) == INVALID_SET_FILE_POINTER) Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
uint written;
if (!WriteFile(handle, buffer, buffer.Length, out written, IntPtr.Zero)) Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
if (written != buffer.Length) throw new IOException();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (handle != null) handle.Dispose();
}
}
enum EMoveMethod : uint
{
Begin = 0,
Current = 1,
End = 2
}
const uint INVALID_SET_FILE_POINTER = 0xFFFFFFFF;
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr CreateFile(
string fileName,
[MarshalAs(UnmanagedType.U4)] FileAccess fileAccess,
[MarshalAs(UnmanagedType.U4)] FileShare fileShare,
IntPtr securityAttributes,
[MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
int flags,
IntPtr template);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint SetFilePointer(
[In] SafeFileHandle hFile,
[In] uint lDistanceToMove,
[In] IntPtr lpDistanceToMoveHigh,
[In] EMoveMethod dwMoveMethod);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadFile(SafeFileHandle hFile, [Out] byte[] lpBuffer,
int nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);
[DllImport("kernel32.dll")]
static extern bool WriteFile(SafeFileHandle hFile, [In] byte[] lpBuffer,
int nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten,
[In] IntPtr lpOverlapped);
}
Use e.g. ChangeSerialNumber('D', 0x12345678);
Here is a small example for reading and writing the serial number of a
FAT32 volume. To keep the sample small all error handling has been omitted.
Please note that direct access to the sectors of a volume
may lead to data loss or corruption. So be careful in using the
example below (it is not an example suitable for production usage).
No guarantee!
In the example below I use the Win32 API GetDiskFreeSpace (using .Net interop) to get
the bytes per sector for the FAT32 volume.
To open the fat volume, I use the Win32 API CreateFile because the FileStream class
does not support opening disk partitions directly.
static uint GenericRead = 0x80000000;
static uint GenericWrite = 0x40000000;
static uint OpenExisting = 3;
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr SecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool GetDiskFreeSpace(string lpRootPathName, out uint lpSectorsPerCluster, out uint lpBytesPerSector, out uint lpNumberOfFreeClusters, out uint lpTotalNumberOfClusters);
static void ReadAndSetSerialNumber()
{
const string driveLetter = "e:"; // Drive with FAT32 file system.
uint sectorsPerCluster;
uint bytesPerSector;
uint numberOfFreeClusters;
uint totalNumberOfClusters;
GetDiskFreeSpace(String.Format(#"{0}\", driveLetter), out sectorsPerCluster, out bytesPerSector,
out numberOfFreeClusters, out totalNumberOfClusters);
Console.Out.WriteLine("Info for drive {0}", driveLetter);
Console.Out.WriteLine("Bytes per sector: {0}", bytesPerSector);
const int fatSerialOffset = 0x43;
const int fatIdOffset = 0x52;
const string fatFileSystemId = "FAT32";
using (SafeFileHandle sfh = CreateFile(String.Format("\\\\.\\{0}", driveLetter), GenericRead | GenericWrite,
(uint)FileShare.ReadWrite, IntPtr.Zero, OpenExisting, 0, IntPtr.Zero))
{
using (FileStream fs = new FileStream(sfh, FileAccess.ReadWrite))
{
byte[] firstSector = new byte[bytesPerSector];
fs.Read(firstSector, 0, (int)bytesPerSector);
if (Encoding.ASCII.GetString(firstSector, fatIdOffset, fatFileSystemId.Length) == fatFileSystemId)
{
Console.Out.WriteLine("FAT32 file system found...");
uint serial = BitConverter.ToUInt32(firstSector, fatSerialOffset);
Console.Out.WriteLine("Read serial number: {0:X4}-{1:X4}", serial >> 16, serial & 0xFFFF);
// Write new serial number.
byte[] newserial = BitConverter.GetBytes((uint)10000123);
Array.Copy(newserial, 0, firstSector, fatSerialOffset, newserial.Length);
fs.Seek(0, SeekOrigin.Begin);
fs.Write(firstSector, 0, (int)bytesPerSector);
}
}
}
}
Furthermore you could use the .Net Framework's DriveInfo class to enumerate the
available drives on your computer.
Hope, this helps.

Categories