Skip to content

Instantly share code, notes, and snippets.

@little-apps
Created October 10, 2015 03:32
Show Gist options
  • Save little-apps/3632a156cee5936d2441 to your computer and use it in GitHub Desktop.
Save little-apps/3632a156cee5936d2441 to your computer and use it in GitHub Desktop.
This example loads the first 512 bytes of a NTFS partition using C#. You will need administrator privileges to use this program.
/*
This example loads the first 512 bytes of a NTFS partition using C#. You will need administrator privileges to use this program.
Author: Little Apps (https://www.little-apps.com)
License: GNU Lesser General Public License v3
*/
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Microsoft.Win32.SafeHandles;
namespace TestConsole
{
class Program
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern SafeFileHandle CreateFile(
[MarshalAs(UnmanagedType.LPTStr)] string filename,
[MarshalAs(UnmanagedType.U4)] FileAccess access,
[MarshalAs(UnmanagedType.U4)] FileShare share,
IntPtr securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero
[MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
[MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes,
IntPtr templateFile);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool ReadFile(SafeFileHandle hFile, [Out] IntPtr lpBuffer, uint nNumberOfBytesToRead,
out uint lpNumberOfBytesRead, [In] ref NativeOverlapped lpOverlapped);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool GetVolumePathName(string lpszFileName, [Out] StringBuilder lpszVolumePathName,
uint cchBufferLength);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool GetVolumeNameForVolumeMountPoint(string lpszVolumeMountPoint,
[Out] StringBuilder lpszVolumeName, uint cchBufferLength);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct NtfsBootSector
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] jmpInstruction;
[MarshalAs(UnmanagedType.U8, SizeConst = 8)]
public ulong oemId;
[MarshalAs(UnmanagedType.U2)]
public short bytesPerSector;
[MarshalAs(UnmanagedType.U1)]
public byte sectorsPerCluster;
[MarshalAs(UnmanagedType.U2)]
public short reservedSectors;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] alwaysZero1;
[MarshalAs(UnmanagedType.U2)]
public short notUsed1;
[MarshalAs(UnmanagedType.U1)]
public byte mediaDescriptor;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] alwaysZero2;
[MarshalAs(UnmanagedType.U2)]
public short sectorsPerTrack;
[MarshalAs(UnmanagedType.U2)]
public short numberOfHeads;
[MarshalAs(UnmanagedType.U4)]
public uint hiddenSectors;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] alwaysZero3;
[MarshalAs(UnmanagedType.U4)]
public uint ntfsSignature;
[MarshalAs(UnmanagedType.U8)]
public ulong totalSectors;
[MarshalAs(UnmanagedType.U8)]
public ulong lcnMFT;
[MarshalAs(UnmanagedType.U8)]
public ulong lcnMFTMirr;
[MarshalAs(UnmanagedType.U1)]
public byte clustersPerMFTRecord;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] notUsed6;
[MarshalAs(UnmanagedType.U1)]
public byte clustersPerIndexBuffer;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] notUsed7;
[MarshalAs(UnmanagedType.U8)]
public ulong volumeSerialNumber;
[MarshalAs(UnmanagedType.U4)]
public uint ntfsChecksum;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 426)]
public byte[] bootStrapCode;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] signature;
}
static void Main(string[] args)
{
const int bufferSize = 512;
uint bytesRead;
Console.Write("Enter path without trailing slash (ie: C:): ");
var path = Console.In.ReadLine().Trim();
if (string.IsNullOrEmpty(path))
{
Console.WriteLine("No path entered. Exiting...");
return;
}
var volumeName = GetVolumeNameFromPath(path);
if (string.IsNullOrEmpty(volumeName))
return;
Console.WriteLine($"Opening volume name ({volumeName})...");
var fileHandle = CreateFile(volumeName, FileAccess.Read, FileShare.Read | FileShare.Write, IntPtr.Zero,
FileMode.Open, 0, IntPtr.Zero);
if (fileHandle.IsInvalid)
{
var errorCode = Marshal.GetLastWin32Error();
Console.WriteLine($"Unable to open drive (code {errorCode}). Exiting...");
return;
}
var overlapped = new NativeOverlapped();
var bufferPtr = Marshal.AllocHGlobal(bufferSize);
if (!ReadFile(fileHandle, bufferPtr, bufferSize, out bytesRead, ref overlapped))
{
var errorCode = Marshal.GetLastWin32Error();
Console.WriteLine($"There was an error reading the NTFS boot sector (code: {errorCode}). Exiting...");
return;
}
if (bytesRead == 0 || bytesRead != bufferSize)
{
Console.WriteLine($"Only {bytesRead} bytes out of {bufferSize} bytes were read. Exiting...");
return;
}
var ntfsBootSector = (NtfsBootSector) Marshal.PtrToStructure(bufferPtr, typeof (NtfsBootSector));
if (ntfsBootSector.oemId != 0x202020205346544E)
{
Console.WriteLine("This drive is not NTFS. Exiting...");
return;
}
Console.WriteLine("Got NTFS boot sector!");
}
static string GetVolumeNameFromPath(string path)
{
var mountPoint = new StringBuilder(path.Length);
var volumePathName = GetVolumePathName(path, mountPoint, (uint)mountPoint.Capacity) ? mountPoint.ToString() : string.Copy(path);
/* Make two versions of the MountPoint, one with a trailing backslash and one without. */
var mountPointSlash = $"{volumePathName}\\";
string volumeNameSlash;
try
{
volumeNameSlash = GetVolumeName(mountPointSlash);
}
catch (Win32Exception ex)
{
if (mountPointSlash.Length > 52 - 1 - 4)
{
/* "Cannot find volume name for mountpoint '%s': %s" */
var errorMsg = $"[{ex.NativeErrorCode}] {ex.Message}";
Console.WriteLine("Cannot find volume name for mountpoint '{0}': {1}", mountPoint, errorMsg);
return string.Empty;
}
volumeNameSlash = $"\\\\.\\{mountPointSlash}";
}
return volumeNameSlash.TrimEnd('\\');
}
internal static string GetVolumeName(string mountPoint)
{
const int maxVolumeNameLength = 512;
var sb = new StringBuilder(maxVolumeNameLength);
if (!GetVolumeNameForVolumeMountPoint(mountPoint, sb, maxVolumeNameLength))
throw new Win32Exception(Marshal.GetLastWin32Error());
return sb.ToString();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment