How to find if a native DLL file is compiled as x64 or x86?
C#.NetWinapi64 BitX86 64C# Problem Overview
I want to determine if a native assembly is complied as x64 or x86 from a managed code application (C#).
I think it must be somewhere in the PE header since the OS loader needs to know this information, but I couldn't find it. Of course I prefer to do it in managed code, but if it necessary, I can use native C++.
C# Solutions
Solution 1 - C#
You can use DUMPBIN too. Use the /headers
or /all
flag and its the first file header listed.
dumpbin /headers cv210.dll
###64-bit
Microsoft (R) COFF/PE Dumper Version 10.00.30319.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file cv210.dll
PE signature found
File Type: DLL
FILE HEADER VALUES
8664 machine (x64)
6 number of sections
4BBAB813 time date stamp Tue Apr 06 12:26:59 2010
0 file pointer to symbol table
0 number of symbols
F0 size of optional header
2022 characteristics
Executable
Application can handle large (>2GB) addresses
DLL
###32-bit
Microsoft (R) COFF/PE Dumper Version 10.00.30319.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file acrdlg.dll
PE signature found
File Type: DLL
FILE HEADER VALUES
14C machine (x86)
5 number of sections
467AFDD2 time date stamp Fri Jun 22 06:38:10 2007
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
2306 characteristics
Executable
Line numbers stripped
32 bit word machine
Debug information stripped
DLL
'find' can make life slightly easier:
dumpbin /headers cv210.dll |find "machine"
8664 machine (x64)
Solution 2 - C#
There is an easy way to do this with CorFlags. Open the Visual Studio Command Prompt and type "corflags [your assembly]". You'll get something like this:
> c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC>corflags > "C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Data.dll" > > Microsoft (R) .NET Framework CorFlags > Conversion Tool. Version 3.5.21022.8 > Copyright (c) Microsoft Corporation. > All rights reserved. > > Version : v2.0.50727 > CLR Header: 2.5 > PE : PE32 > CorFlags : 24 > ILONLY : 0 > 32BIT : 0 > Signed : 1
You're looking at PE and 32BIT specifically.
-
Any CPU:
PE: PE32
32BIT: 0 -
x86:
PE: PE32
32BIT: 1 -
x64:
PE: PE32+
32BIT: 0
Solution 3 - C#
This trick works and requires only Notepad.
Open the dll file using a text editor (like Notepad) and find the first occurrence of the string PE
. The following character defines if the dll is 32 or 64 bits.
32 bits:
PE L
64 bits:
PE d†
Solution 4 - C#
The Magic
field of the IMAGE_OPTIONAL_HEADER
(though there is nothing optional about the header in Windows executable images (DLL/EXE files)) will tell you the architecture of the PE.
Here's an example of grabbing the architecture from a file.
public static ushort GetImageArchitecture(string filepath) {
using (var stream = new System.IO.FileStream(filepath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
using (var reader = new System.IO.BinaryReader(stream)) {
//check the MZ signature to ensure it's a valid Portable Executable image
if (reader.ReadUInt16() != 23117)
throw new BadImageFormatException("Not a valid Portable Executable image", filepath);
// seek to, and read, e_lfanew then advance the stream to there (start of NT header)
stream.Seek(0x3A, System.IO.SeekOrigin.Current);
stream.Seek(reader.ReadUInt32(), System.IO.SeekOrigin.Begin);
// Ensure the NT header is valid by checking the "PE\0\0" signature
if (reader.ReadUInt32() != 17744)
throw new BadImageFormatException("Not a valid Portable Executable image", filepath);
// seek past the file header, then read the magic number from the optional header
stream.Seek(20, System.IO.SeekOrigin.Current);
return reader.ReadUInt16();
}
}
The only two architecture constants at the moment are:
0x10b - PE32
0x20b - PE32+
Cheers
UPDATE
It's been a while since I posted this answer, yet I still see that it gets a few upvotes now and again so I figured it was worth updating. I wrote a way to get the architecture of a Portable Executable
image, which also checks to see if it was compiled as AnyCPU
. Unfortunately the answer is in C++, but it shouldn't be too hard to port to C# if you have a few minutes to look up the structures in WinNT.h
. If people are interested I'll write a port in C#, but unless people actually want it I wont spend much time stressing about it.
#include <Windows.h>
#define MKPTR(p1,p2) ((DWORD_PTR)(p1) + (DWORD_PTR)(p2))
typedef enum _pe_architecture {
PE_ARCHITECTURE_UNKNOWN = 0x0000,
PE_ARCHITECTURE_ANYCPU = 0x0001,
PE_ARCHITECTURE_X86 = 0x010B,
PE_ARCHITECTURE_x64 = 0x020B
} PE_ARCHITECTURE;
LPVOID GetOffsetFromRva(IMAGE_DOS_HEADER *pDos, IMAGE_NT_HEADERS *pNt, DWORD rva) {
IMAGE_SECTION_HEADER *pSecHd = IMAGE_FIRST_SECTION(pNt);
for(unsigned long i = 0; i < pNt->FileHeader.NumberOfSections; ++i, ++pSecHd) {
// Lookup which section contains this RVA so we can translate the VA to a file offset
if (rva >= pSecHd->VirtualAddress && rva < (pSecHd->VirtualAddress + pSecHd->Misc.VirtualSize)) {
DWORD delta = pSecHd->VirtualAddress - pSecHd->PointerToRawData;
return (LPVOID)MKPTR(pDos, rva - delta);
}
}
return NULL;
}
PE_ARCHITECTURE GetImageArchitecture(void *pImageBase) {
// Parse and validate the DOS header
IMAGE_DOS_HEADER *pDosHd = (IMAGE_DOS_HEADER*)pImageBase;
if (IsBadReadPtr(pDosHd, sizeof(pDosHd->e_magic)) || pDosHd->e_magic != IMAGE_DOS_SIGNATURE)
return PE_ARCHITECTURE_UNKNOWN;
// Parse and validate the NT header
IMAGE_NT_HEADERS *pNtHd = (IMAGE_NT_HEADERS*)MKPTR(pDosHd, pDosHd->e_lfanew);
if (IsBadReadPtr(pNtHd, sizeof(pNtHd->Signature)) || pNtHd->Signature != IMAGE_NT_SIGNATURE)
return PE_ARCHITECTURE_UNKNOWN;
// First, naive, check based on the 'Magic' number in the Optional Header.
PE_ARCHITECTURE architecture = (PE_ARCHITECTURE)pNtHd->OptionalHeader.Magic;
// If the architecture is x86, there is still a possibility that the image is 'AnyCPU'
if (architecture == PE_ARCHITECTURE_X86) {
IMAGE_DATA_DIRECTORY comDirectory = pNtHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
if (comDirectory.Size) {
IMAGE_COR20_HEADER *pClrHd = (IMAGE_COR20_HEADER*)GetOffsetFromRva(pDosHd, pNtHd, comDirectory.VirtualAddress);
// Check to see if the CLR header contains the 32BITONLY flag, if not then the image is actually AnyCpu
if ((pClrHd->Flags & COMIMAGE_FLAGS_32BITREQUIRED) == 0)
architecture = PE_ARCHITECTURE_ANYCPU;
}
}
return architecture;
}
The function accepts a pointer to an in-memory PE image (so you can choose your poison on how to get it their; memory-mapping or reading the whole thing into memory...whatever).
Solution 5 - C#
For an unmanaged DLL file, you need to first check if it is a 16-bit DLL file (hopefully not).
Then check the IMAGE\_FILE_HEADER.Machine
field.
Someone else took the time to work this out already, so I will just repeat here:
> To distinguish between a 32-bit and 64-bit PE file, you should check > IMAGE_FILE_HEADER.Machine field. Based on the Microsoft PE and COFF > specification below, I have listed out > all the possible values for this field: > http://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/pecoff_v8.doc > > IMAGE_FILE_MACHINE_UNKNOWN 0x0 The contents of this field are assumed to be applicable to any machine type > > IMAGE_FILE_MACHINE_AM33 0x1d3 Matsushita AM33
> IMAGE_FILE_MACHINE_AMD64 0x8664 x64
> IMAGE_FILE_MACHINE_ARM 0x1c0 ARM little endian
> IMAGE_FILE_MACHINE_EBC 0xebc EFI byte code
> IMAGE_FILE_MACHINE_I386 0x14c Intel 386 or later processors and compatible processors
> IMAGE_FILE_MACHINE_IA64 0x200 Intel Itanium processor family
> IMAGE_FILE_MACHINE_M32R 0x9041 Mitsubishi M32R little endian
> IMAGE_FILE_MACHINE_MIPS16 0x266 MIPS16
> IMAGE_FILE_MACHINE_MIPSFPU 0x366 MIPS with FPU
> IMAGE_FILE_MACHINE_MIPSFPU16 0x466 MIPS16 with FPU
> IMAGE_FILE_MACHINE_POWERPC 0x1f0 Power PC little endian
> IMAGE_FILE_MACHINE_POWERPCFP 0x1f1 Power PC with floating point support
> IMAGE_FILE_MACHINE_R4000 0x166 MIPS little endian
> IMAGE_FILE_MACHINE_SH3 0x1a2 Hitachi SH3
> IMAGE_FILE_MACHINE_SH3DSP 0x1a3 Hitachi SH3 DSP
> IMAGE_FILE_MACHINE_SH4 0x1a6 Hitachi SH4
> IMAGE_FILE_MACHINE_SH5 0x1a8 Hitachi SH5
> IMAGE_FILE_MACHINE_THUMB 0x1c2 Thumb
> IMAGE_FILE_MACHINE_WCEMIPSV2 0x169 MIPS little-endian WCE v2
> Yes, you may check > IMAGE_FILE_MACHINE_AMD64|IMAGE_FILE_MACHINE_IA64 for 64bit and IMAGE_FILE_MACHINE_I386 for 32bit.
Solution 6 - C#
You can find a C# sample implementation here for the IMAGE_FILE_HEADER
solution
Solution 7 - C#
64-bit binaries are stored in PE32+ format. Try reading http://www.masm32.com/board/index.php?action=dlattach;topic=6687.0;id=3486
Solution 8 - C#
Open the dll with a hex editor, like HxD
If the there is a "dt" on the 9th line it is 64bit.
If there is an "L." on the 9th line it is 32bit.
Solution 9 - C#
I rewrote c++ solution in first answer in powershell script. Script can determine this types of .exe and .dll files:
#Description C# compiler switch PE type machine corflags
#MSIL /platform:anycpu (default) PE32 x86 ILONLY
#MSIL 32 bit pref /platform:anycpu32bitpreferred PE32 x86 ILONLY | 32BITREQUIRED | 32BITPREFERRED
#x86 managed /platform:x86 PE32 x86 ILONLY | 32BITREQUIRED
#x86 mixed n/a PE32 x86 32BITREQUIRED
#x64 managed /platform:x64 PE32+ x64 ILONLY
#x64 mixed n/a PE32+ x64
#ARM managed /platform:arm PE32 ARM ILONLY
#ARM mixed n/a PE32 ARM
this solution has some advantages over corflags.exe and loading assembly via Assembly.Load in C# - you will never get BadImageFormatException or message about invalid header.
function GetActualAddressFromRVA($st, $sec, $numOfSec, $dwRVA)
{
[System.UInt32] $dwRet = 0;
for($j = 0; $j -lt $numOfSec; $j++)
{
$nextSectionOffset = $sec + 40*$j;
$VirtualSizeOffset = 8;
$VirtualAddressOffset = 12;
$SizeOfRawDataOffset = 16;
$PointerToRawDataOffset = 20;
$Null = @(
$curr_offset = $st.BaseStream.Seek($nextSectionOffset + $VirtualSizeOffset, [System.IO.SeekOrigin]::Begin);
[System.UInt32] $VirtualSize = $b.ReadUInt32();
[System.UInt32] $VirtualAddress = $b.ReadUInt32();
[System.UInt32] $SizeOfRawData = $b.ReadUInt32();
[System.UInt32] $PointerToRawData = $b.ReadUInt32();
if ($dwRVA -ge $VirtualAddress -and $dwRVA -lt ($VirtualAddress + $VirtualSize)) {
$delta = $VirtualAddress - $PointerToRawData;
$dwRet = $dwRVA - $delta;
return $dwRet;
}
);
}
return $dwRet;
}
function Get-Bitness2([System.String]$path, $showLog = $false)
{
$Obj = @{};
$Obj.Result = '';
$Obj.Error = $false;
$Obj.Log = @(Split-Path -Path $path -Leaf -Resolve);
$b = new-object System.IO.BinaryReader([System.IO.File]::Open($path,[System.IO.FileMode]::Open,[System.IO.FileAccess]::Read, [System.IO.FileShare]::Read));
$curr_offset = $b.BaseStream.Seek(0x3c, [System.IO.SeekOrigin]::Begin)
[System.Int32] $peOffset = $b.ReadInt32();
$Obj.Log += 'peOffset ' + "{0:X0}" -f $peOffset;
$curr_offset = $b.BaseStream.Seek($peOffset, [System.IO.SeekOrigin]::Begin);
[System.UInt32] $peHead = $b.ReadUInt32();
if ($peHead -ne 0x00004550) {
$Obj.Error = $true;
$Obj.Result = 'Bad Image Format';
$Obj.Log += 'cannot determine file type (not x64/x86/ARM) - exit with error';
};
if ($Obj.Error)
{
$b.Close();
Write-Host ($Obj.Log | Format-List | Out-String);
return $false;
};
[System.UInt16] $machineType = $b.ReadUInt16();
$Obj.Log += 'machineType ' + "{0:X0}" -f $machineType;
[System.UInt16] $numOfSections = $b.ReadUInt16();
$Obj.Log += 'numOfSections ' + "{0:X0}" -f $numOfSections;
if (($machineType -eq 0x8664) -or ($machineType -eq 0x200)) { $Obj.Log += 'machineType: x64'; }
elseif ($machineType -eq 0x14c) { $Obj.Log += 'machineType: x86'; }
elseif ($machineType -eq 0x1c0) { $Obj.Log += 'machineType: ARM'; }
else{
$Obj.Error = $true;
$Obj.Log += 'cannot determine file type (not x64/x86/ARM) - exit with error';
};
if ($Obj.Error) {
$b.Close();
Write-Output ($Obj.Log | Format-List | Out-String);
return $false;
};
$curr_offset = $b.BaseStream.Seek($peOffset+20, [System.IO.SeekOrigin]::Begin);
[System.UInt16] $sizeOfPeHeader = $b.ReadUInt16();
$coffOffset = $peOffset + 24;#PE header size is 24 bytes
$Obj.Log += 'coffOffset ' + "{0:X0}" -f $coffOffset;
$curr_offset = $b.BaseStream.Seek($coffOffset, [System.IO.SeekOrigin]::Begin);#+24 byte magic number
[System.UInt16] $pe32 = $b.ReadUInt16();
$clr20headerOffset = 0;
$flag32bit = $false;
$Obj.Log += 'pe32 magic number: ' + "{0:X0}" -f $pe32;
$Obj.Log += 'size of optional header ' + ("{0:D0}" -f $sizeOfPeHeader) + " bytes";
#COMIMAGE_FLAGS_ILONLY =0x00000001,
#COMIMAGE_FLAGS_32BITREQUIRED =0x00000002,
#COMIMAGE_FLAGS_IL_LIBRARY =0x00000004,
#COMIMAGE_FLAGS_STRONGNAMESIGNED =0x00000008,
#COMIMAGE_FLAGS_NATIVE_ENTRYPOINT =0x00000010,
#COMIMAGE_FLAGS_TRACKDEBUGDATA =0x00010000,
#COMIMAGE_FLAGS_32BITPREFERRED =0x00020000,
$COMIMAGE_FLAGS_ILONLY = 0x00000001;
$COMIMAGE_FLAGS_32BITREQUIRED = 0x00000002;
$COMIMAGE_FLAGS_32BITPREFERRED = 0x00020000;
$offset = 96;
if ($pe32 -eq 0x20b) {
$offset = 112;#size of COFF header is bigger for pe32+
}
$clr20dirHeaderOffset = $coffOffset + $offset + 14*8;#clr directory header offset + start of section number 15 (each section is 8 byte long);
$Obj.Log += 'clr20dirHeaderOffset ' + "{0:X0}" -f $clr20dirHeaderOffset;
$curr_offset = $b.BaseStream.Seek($clr20dirHeaderOffset, [System.IO.SeekOrigin]::Begin);
[System.UInt32] $clr20VirtualAddress = $b.ReadUInt32();
[System.UInt32] $clr20Size = $b.ReadUInt32();
$Obj.Log += 'clr20VirtualAddress ' + "{0:X0}" -f $clr20VirtualAddress;
$Obj.Log += 'clr20SectionSize ' + ("{0:D0}" -f $clr20Size) + " bytes";
if ($clr20Size -eq 0) {
if ($machineType -eq 0x1c0) { $Obj.Result = 'ARM native'; }
elseif ($pe32 -eq 0x10b) { $Obj.Result = '32-bit native'; }
elseif($pe32 -eq 0x20b) { $Obj.Result = '64-bit native'; }
$b.Close();
if ($Obj.Result -eq '') {
$Obj.Error = $true;
$Obj.Log += 'Unknown type of file';
}
else {
if ($showLog) { Write-Output ($Obj.Log | Format-List | Out-String); };
return $Obj.Result;
}
};
if ($Obj.Error) {
$b.Close();
Write-Host ($Obj.Log | Format-List | Out-String);
return $false;
};
[System.UInt32]$sectionsOffset = $coffOffset + $sizeOfPeHeader;
$Obj.Log += 'sectionsOffset ' + "{0:X0}" -f $sectionsOffset;
$realOffset = GetActualAddressFromRVA $b $sectionsOffset $numOfSections $clr20VirtualAddress;
$Obj.Log += 'real IMAGE_COR20_HEADER offset ' + "{0:X0}" -f $realOffset;
if ($realOffset -eq 0) {
$Obj.Error = $true;
$Obj.Log += 'cannot find COR20 header - exit with error';
$b.Close();
return $false;
};
if ($Obj.Error) {
$b.Close();
Write-Host ($Obj.Log | Format-List | Out-String);
return $false;
};
$curr_offset = $b.BaseStream.Seek($realOffset + 4, [System.IO.SeekOrigin]::Begin);
[System.UInt16] $majorVer = $b.ReadUInt16();
[System.UInt16] $minorVer = $b.ReadUInt16();
$Obj.Log += 'IMAGE_COR20_HEADER version ' + ("{0:D0}" -f $majorVer) + "." + ("{0:D0}" -f $minorVer);
$flagsOffset = 16;#+16 bytes - flags field
$curr_offset = $b.BaseStream.Seek($realOffset + $flagsOffset, [System.IO.SeekOrigin]::Begin);
[System.UInt32] $flag32bit = $b.ReadUInt32();
$Obj.Log += 'CorFlags: ' + ("{0:X0}" -f $flag32bit);
#Description C# compiler switch PE type machine corflags
#MSIL /platform:anycpu (default) PE32 x86 ILONLY
#MSIL 32 bit pref /platform:anycpu32bitpreferred PE32 x86 ILONLY | 32BITREQUIRED | 32BITPREFERRED
#x86 managed /platform:x86 PE32 x86 ILONLY | 32BITREQUIRED
#x86 mixed n/a PE32 x86 32BITREQUIRED
#x64 managed /platform:x64 PE32+ x64 ILONLY
#x64 mixed n/a PE32+ x64
#ARM managed /platform:arm PE32 ARM ILONLY
#ARM mixed n/a PE32 ARM
$isILOnly = ($flag32bit -band $COMIMAGE_FLAGS_ILONLY) -eq $COMIMAGE_FLAGS_ILONLY;
$Obj.Log += 'ILONLY: ' + $isILOnly;
if ($machineType -eq 0x1c0) {#if ARM
if ($isILOnly) { $Obj.Result = 'ARM managed'; }
else { $Obj.Result = 'ARM mixed'; }
}
elseif ($pe32 -eq 0x10b) {#pe32
$is32bitRequired = ($flag32bit -band $COMIMAGE_FLAGS_32BITREQUIRED) -eq $COMIMAGE_FLAGS_32BITREQUIRED;
$is32bitPreffered = ($flag32bit -band $COMIMAGE_FLAGS_32BITPREFERRED) -eq $COMIMAGE_FLAGS_32BITPREFERRED;
$Obj.Log += '32BIT: ' + $is32bitRequired;
$Obj.Log += '32BIT PREFFERED: ' + $is32bitPreffered
if ($is32bitRequired -and $isILOnly -and $is32bitPreffered) { $Obj.Result = 'AnyCpu 32bit-preffered'; }
elseif ($is32bitRequired -and $isILOnly -and !$is32bitPreffered){ $Obj.Result = 'x86 managed'; }
elseif (!$is32bitRequired -and !$isILOnly -and $is32bitPreffered) { $Obj.Result = 'x86 mixed'; }
elseif ($isILOnly) { $Obj.Result = 'AnyCpu'; }
}
elseif ($pe32 -eq 0x20b) {#pe32+
if ($isILOnly) { $Obj.Result = 'x64 managed'; }
else { $Obj.Result = 'x64 mixed'; }
}
$b.Close();
if ($showLog) { Write-Host ($Obj.Log | Format-List | Out-String); }
if ($Obj.Result -eq ''){ return 'Unknown type of file';};
$flags = '';
if ($isILOnly) {$flags += 'ILONLY';}
if ($is32bitRequired) {
if ($flags -ne '') {$flags += ' | ';}
$flags += '32BITREQUIRED';
}
if ($is32bitPreffered) {
if ($flags -ne '') {$flags += ' | ';}
$flags += '32BITPREFERRED';
}
if ($flags -ne '') {$flags = ' (' + $flags +')';}
return $Obj.Result + $flags;
}
usage example:
#$filePath = "C:\Windows\SysWOW64\regedit.exe";#32 bit native on 64bit windows
$filePath = "C:\Windows\regedit.exe";#64 bit native on 64bit windows | should be 32 bit native on 32bit windows
Get-Bitness2 $filePath $true;
you can omit second parameter if you don't need to see details
Solution 10 - C#
A quick and probably dirty way to do it is described here: https://superuser.com/a/889267. You open the DLL in an editor and check the first characters after the "PE" sequence.
Solution 11 - C#
Because of third-party tool always installing in %Program files (x86)%
(even if x64 installation!) and requiring appropriate x32|x64 fortran runtime to be first listed on the %path%
to run correctly, I gathered c++ and powershell solutions into matlab to return:
- Kind:
Executable|Library|Other
- CodeType:
Native|Mixed|Managed
- Platform:
x32|x64|AnyCpu|x32Preferred|Other
It should be easy to adapt to other languages once having raw PE structures in memory.
function [simplifiedInfo] = GetPortableExecutableSimplifiedInfo(filename)
%[
% Checking arguments
if (nargin <1), error('MATLAB:minrhs', 'Not enough input argments.'); end
% Initializing simplified info
simplifiedInfo.Kind = 'Other';
simplifiedInfo.CodeType = 'Other';
simplifiedInfo.Platform = 'Other';
% Obtaining raw info
[rawInfo, PEConstants] = GetPortableExecutableRawInfo(filename);
% Determining 'Kind' of PE
if (isfield(rawInfo, 'PEOptionalHeader') && (rawInfo.COFFHeader.Characteristics.IMAGE_FILE_EXECUTABLE_IMAGE))
if (rawInfo.COFFHeader.Characteristics.IMAGE_FILE_DLL)
simplifiedInfo.Kind = 'Library';
else
simplifiedInfo.Kind = 'Executable';
end
else
% No optional header or no IMAGE_FILE_EXECUTABLE_IMAGE flag ...
% Maybe just .obj or other thing
simplifiedInfo.Kind = 'Other';
end
% Determining 'CodeType'
% NB: 'COR20Header' is present for MSIL code, but not for native code
if (isfield(rawInfo, 'COR20Header'))
if (rawInfo.COR20Header.Flags.COMIMAGE_FLAGS_ILONLY)
simplifiedInfo.CodeType = 'Managed';
else
simplifiedInfo.CodeType = 'Mixed';
end
else
simplifiedInfo.CodeType = 'Native';
end
% Determining platform
if (rawInfo.COFFHeader.Machine == PEConstants.IMAGE_FILE_MACHINE_AMD64)
simplifiedInfo.Platform = 'x64';
elseif (rawInfo.COFFHeader.Machine == PEConstants.IMAGE_FILE_MACHINE_I386)
if (isfield(rawInfo, 'COR20Header'))
% PE contains MSIL code, need more checks
if (rawInfo.COR20Header.Flags.COMIMAGE_FLAGS_32BITREQUIRED)
if (rawInfo.COR20Header.Flags.COMIMAGE_FLAGS_32BITPREFERRED)
simplifiedInfo.Platform = 'x32Preferred';
else
simplifiedInfo.Platform = 'x32';
end
else
simplifiedInfo.Platform = 'AnyCpu';
end
else
% This is native code so ...
simplifiedInfo.Platform = 'x32';
end
else
% ARM, ...
simplifiedInfo.Platform = 'Other';
end
%]
end
Source code for internal GetPortableExecutableRawInfo
function can be obtained here.
Solution 12 - C#
Apparently you can find it in the header of the portable executable. The corflags.exe utility is able to show you whether or not it targets x64. Hopefully this helps you find more information about it.