Users can upload vhd files to my server. I would like to validate the files that they upload and ensure that they are actually a valid vhd file rather than a jpeg rebranded with a .vhd file extension or etc. Is there a way to do this?
-
I'm not really familiar with .vhd files, but perhaps you could just open it in some sort of reader and verify that the internals of the file meet specs? Microsoft has the specs here: https://www.microsoft.com/en-us/download/details.aspx?id=23850 (*disclaimer:* I did not look into this beyond finding that link) – Broots Waymb Jan 21 '19 at 17:56
-
There is an ascii header in images that you can see with NotePad or read using BinaryReader. – jdweng Jan 21 '19 at 18:14
-
Edits made: See Edit 6. – Gnbrkm41 Jan 22 '19 at 16:00
1 Answers
https://www.garykessler.net/library/file_sigs.html (Ctrl + F, then type VHD)
It appears that the first 8 bytes of VHD files are as follows: 63 6F 6E 65 63 74 69 78
(conectix
in ASCII.)
As suggested by @jdweng in the comments section, you might be able to use BinaryReader to read the first 8 bytes and compare it with the value above it to determine whether the file is VHD file.
Edit: Does not work, Looking for other solutions.
Edit 2: It actually appears that the text conectix
does exist in the file, however it's not at the beginning of the file; the text is located at [the end of the file] - 0x200
'th byte. Going to test it now. FYI, the file is generated using Disk management tool on Windows 10.
Edit 3:
private static bool IsVhd(string path)
{
byte[] vhdHeader = { 0x63, 0x6F, 0x6E, 0x65, 0x63, 0x74, 0x69, 0x78 };
byte[] header;
FileInfo file = new FileInfo(path);
long length = file.Length;
using (BinaryReader br = new BinaryReader(file.OpenRead()))
{
br.BaseStream.Position = length - 0x200; //Where the "conectix" is located at
header = br.ReadBytes(8);
}
return vhdHeader.SequenceEqual(header);
}
I believe this would do.
Edit 4:
private static bool IsVhd(string path)
{
Span<byte> vhdHeader = stackalloc byte[] { 0x63, 0x6F, 0x6E, 0x65, 0x63, 0x74, 0x69, 0x78 };
Span<byte> header = stackalloc byte[8];
FileInfo file = new FileInfo(path);
long length = file.Length;
using (BinaryReader br = new BinaryReader(file.OpenRead()))
{
br.BaseStream.Position = length - 0x200; //Where the "conectix" is located at
br.Read(header);
}
return vhdHeader.SequenceEqual(header);
}
NonLess-allocating version, in case you're using .NET Core. (Requires C# 7.3)
Edit 5:
private static bool IsVhd(string path)
{
Span<byte> vhdHeader = stackalloc byte[] { 0x63, 0x6F, 0x6E, 0x65, 0x63, 0x74, 0x69, 0x78 };
Span<byte> header = stackalloc byte[8];
FileInfo file = new FileInfo(path);
long length = file.Length;
using (BinaryReader br = new BinaryReader(file.OpenRead()))
{
br.BaseStream.Position = length - 0x200; //Where the "conectix" is located at
for (int i = 0; i < 8; i++)
header[i] = br.ReadByte();
}
return vhdHeader.SequenceEqual(header);
}
Same, but for .NET Frameworks (Ideally version 4.7.1 due to optimisation; Also requires System.Memory
NuGet package. C# 7.3)
Edit 6: According to the specs, it seems that the "hard disk footer" is located at the last 512(511 if created prior MS Virtual PC 2004) bytes.
Note: Versions previous to Microsoft Virtual PC 2004 create disk images that have a 511-byte disk footer. So the hard disk footer can exist in the last 511 or 512 bytes of the file that holds the hard disk image.
Hard Disk Footer Field Descriptions
The following provides detailed definitions of the hard disk footer fields.
Cookie
Cookies are used to uniquely identify the original creator of the hard disk image. The values are case-sensitive.
Microsoft uses the “conectix” string to identify this file as a hard disk image created by Microsoft Virtual Server, Virtual PC, and predecessor products. The cookie is stored as an eight-character ASCII string with the “c” in the first byte, the “o” in the second byte, and so on.
The previous codes I've written would not work if the file size is less than 512 bytes. I fixed it so it would now deal with files with 511 bytes footer as well. Additionally, I added some comments to help maintaining.
/// <summary>
/// Determines whether the file indicated by the given path is a valid Virtual Hard Disk (.vhd) file.
/// </summary>
/// <param name="path">The path to the .vhd file to check.</param>
/// <returns>Whether the file is a valid vhd file or not.</returns>
//https://www.microsoft.com/en-us/download/details.aspx?id=23850
//See 'Hard Disk Footer Format'
//ASCII string "conectix" (63 6F 6E 65 63 74 69 78) is stored at the last 512 (511 if created on legacy platforms) bytes of the file
private static bool IsVhd(string path)
{
if (path is null) throw new ArgumentNullException(nameof(path));
Span<byte> vhdFooterCookie = stackalloc byte[] { 0x63, 0x6F, 0x6E, 0x65, 0x63, 0x74, 0x69, 0x78 };
Span<byte> cookie = stackalloc byte[9];
FileInfo file = new FileInfo(path);
long length = file.Length;
if (length < 511) return false; //Cannot be smaller than 512 bytes
using (BinaryReader br = new BinaryReader(file.OpenRead()))
{
br.BaseStream.Position = length - 0x200; //Where the footer starts from
#if NETCOREAPP
br.Read(cookie);
#else
for (int i = 0; i < 9; i++)
cookie[i] = br.ReadByte();
#endif
}
//SequenceEqual returns false if length is not equal, therefore we slice it to match
return vhdFooterCookie.SequenceEqual(cookie.Slice(0, 8))
|| vhdFooterCookie.SequenceEqual(cookie.Slice(1)); //If created on legacy platform
}
There are some conditional compiling bits, but I believe you could delete unnecessary bits to match your need.

- 238
- 3
- 9
-
This seems to work for me as well. I will use this unless someone can think of something better. – Edgar Arakelyan Jan 21 '19 at 21:46
-
@Edgar Arakelyan Actually I just noticed that any files smaller than 0.5KB would cause problems. I do not know if legitimate .vhd files can be smaller than 0.5KB, but if that's not the case you could add a logic checking if the file size is less than 512 bytes and return false. I'll elaborate on that in a few minutes. – Gnbrkm41 Jan 22 '19 at 15:07
-
I don't believe you can create a vhd that is smaller than 1 mb. At least the window's disk manager tool will not allow you too. – Edgar Arakelyan Jan 22 '19 at 18:59
-
You are free to change that :) I thought I should change that as well, but I couldn't confirm whether that's true for every VHD files or if it's only for the files generated on recent Windows OSes. – Gnbrkm41 Jan 22 '19 at 19:06