Why can't I run a Vista executable on Windows XP?
Posted: (EET/GMT+2)
Windows Vista contains many nice .EXE files, and it is tempting to copy those EXE files to your Windows XP box and to try run them there. Well, it turns out very quickly that this just won't work, because you will get a rather blunt error message in Windows XP saying:
C:\Tests\Calc.exe is not a valid Win32 application.
But why is this error message displayed? It is displayed by the OS application loader, and each PE file (Portable Executable) has a header which tells the OS the minimum OS version on which the application will run. In Vista, the version is 6.0, and on Windows XP 5.1, and so on. If the version stamped in the EXE file is larger than the current OS version, the application won't run.
Now then, how would you check an EXE file's minimum version? By parsing the PE header, or more precisely the IMAGE_OPTIONAL_HEADER header and its MajorOperatingSystemVersion and MinorOperatingSystemVersion fields. Here's a quick and dirty C# code to return these fields given an EXE filename:
private Version GetPEFileMinimumOSVersion(string filename)
{
FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
const int BUFFER_SIZE = 100;
const int WORD_SIZE = 2; // sizeof(short) on 32-bit
byte[] peHeader = new byte[BUFFER_SIZE];
try
{
// read IMAGE_DOS_HEADER
const int DOS_HEADER_LFANEW = 0x3C;
byte[] peOffsetRVA = new byte[WORD_SIZE];
fs.Seek(DOS_HEADER_LFANEW, SeekOrigin.Begin);
fs.Read(peOffsetRVA, 0, WORD_SIZE);
int peOffset = (peOffsetRVA[0] + (peOffsetRVA[1] << 8));
// read IMAGE_NT_HEADERS
fs.Seek(peOffset, SeekOrigin.Begin);
fs.Read(peHeader, 0, BUFFER_SIZE);
string header = Encoding.ASCII.GetString(peHeader, 0, 2);
if (header != "PE")
{
throw new Exception("The EXE file \"" + filename +
"\" does not seem to be a valid " +
"Win32 PE executable file.");
}
}
finally
{
fs.Close();
}
// parse IMAGE_OPTIONAL_HEADER fields
const int MAJOR_VERSION_OFFSET = 0x40;
int pos = MAJOR_VERSION_OFFSET;
int major = (peHeader[pos] + (peHeader[pos + 1] << 8));
pos += WORD_SIZE;
int minor = (peHeader[pos] + (peHeader[pos + 1] << 8));
return new Version(major, minor);
}
private void button1_Click(object sender, EventArgs e)
{
string filename = @"C:\Windows\System32\calc.exe";
Version minimumVersion = GetPEFileMinimumOSVersion(filename);
MessageBox.Show(minimumVersion.ToString());
}
I won't go through the gory details of the PE (and MS-DOS) file headers here, but I can instead point you to Matt Pietrek's two-part article on MSDN from 2002. Happy hacking!