Here's an example from my blog using C# and as lectricpharaoh brings up, it uses Win32 API calls to function since the .NET framework classes available do not support such behaviour, seemingly by design. Anyway here it is, almost guaranteed to break your system with even slight changes...
....
public static unsafe byte[] ReadSector(char drive, long startingsector, int numberofsectors)
{
IntPtr handle;
byte[] buffer;
int bytesread = 0;
//create a handle to the device
handle = CreateFile(
"\\\\.\\" + drive + ":", FileAccess.Read, FileShare.ReadWrite, 0, FileMode.Open, 0, 0);
if (handle == IntPtr.Zero)
return null;
//setting the pointer to point to the start of the sector to read
SetFilePointer(handle, (startingsector * 512), 0, 0);
//allocate buffer length in a managed context
buffer = new byte[512 * numberofsectors];
fixed (byte* p = buffer)
{
//attempt to read file contents into buffer
if (!ReadFile(handle, p, 512 * numberofsectors, &bytesread, 0))
{
CloseHandle(handle);
return null;
}
}
CloseHandle(handle);
return buffer;
}
....