How to check if Windows executable is 64-bit reading only its binary. Without executing it and not using any tools like the SDK tool dumpbin.exe
with the /headers
option.
4 Answers
Executable type is indicated by PE header, download documentation.
The first word (two bytes) of PE header indicates target machine, here is a list of possible values:
0x0000 - The contents of this field are assumed to be applicable to any machine type
0x01d3 - Matsushita AM33
0x8664 - x64
0x01c0 - ARM little endian
0x01c4 - ARMv7 (or higher) Thumb mode only
0xaa64 - ARMv8 in 64-bit mode
0x0ebc - EFI byte code
0x014c - Intel 386 or later processors and compatible processors
0x0200 - Intel Itanium processor family
0x9041 - Mitsubishi M32R little endian
0x0266 - MIPS16
0x0366 - MIPS with FPU
0x0466 - MIPS16 with FPU
0x01f0 - Power PC little endian
0x01f1 - Power PC with floating point support
0x0166 - MIPS little endian
0x01a2 - Hitachi SH3
0x01a3 - Hitachi SH3 DSP
0x01a6 - Hitachi SH4
0x01a8 - Hitachi SH5
0x01c2 - ARM or Thumb (“interworking”)
0x0169 - MIPS little-endian WCE v2
So to check if it is 64-bit, we need to look for:
0x8664 - x64
0xaa64 - ARMv8 in 64-bit mode
0x0200 - Intel Itanium processor family
And as Bob mentioned, here is a list of some more machine types (see 11 pg.), however it is not very likely to find them.
-
6Don't forget
0x0200
(Itanium). That would be IA-64, as opposed to x86-64 (AMD64). There's a couple more "64-bit" machine types possible, but you're very unlikely to find them in the wild (0x0284
is the 64-bit Alpha AXP, from the 1999 documentation, and not supported by Windows after NT4/2000RC).– BobCommented Aug 8, 2014 at 10:55 -
For a visual reference, image showing the location of the PE header with 0x8664 (highlighted): i.imgur.com/yHvcgdn.png (notepad++ hex-editor plugin)– zamnutsCommented Aug 8, 2014 at 14:47
-
1To quickly find the target machine value: Take the DWORD at offset 0x3C. Add four to this value. That is the offset of the
Machine
WORD. (Both are little endian) Commented Aug 25, 2014 at 21:45 -
Where do you find
0xaa64 - ARMv8 in 64-bit mode
? I have not such#define
inwinnt.h
.– SerGCommented Feb 12, 2015 at 14:34
It's easier to check Optional Header magic number.
For a valid exe, only two values are possible:
0x10B => PE32 => 32 bit
0x20B => PE32+ => 64 bit
-
Might be worth mentioning the offset to find it at (0x18 bytes from the NT Header which starts at the "PE" magic).– JordanCommented Aug 6, 2019 at 23:02
Here's a fun, quick little trick if in a Windows environment and you're checking for an x86 or x64 binary:
- Right-click on the application.
- Click
Properties
. - Click the
Compatibility
tab. - In the
Compatibility mode
section, check theRun this program in compatibility mode for:
box. - If you see
Windows 95
as an option from the drop-down, then it's a 32-bit application. If you do not, then it's a 64-bit application.
dumping the contents of ST3's answer into a powershell snippet in a ready to use format
if($args.Count -eq 0) { "provide a file name or path to file";exit }
if((test-path -path $args) -ne $true) { "file doesnt seem to exist" ; exit }
$fs = New-Object IO.Filestream($args , [Io.FileMode]::Open)
$br = New-Object IO.BinaryReader($fs)
if($br.Readchar()-ne'M'){"no mz";exit};if($br.Readchar()-ne'Z'){"no mz";exit}
$fs.Seek(0x3c,[IO.SeekOrigin]::Begin) | Out-Null
$elfaw_new = $br.ReadUInt32();
$peheader=$fs.Seek($elfaw_new,[IO.SeekOrigin]::Begin)
if($br.Readchar()-ne'P'){"no pe";exit};if($br.Readchar()-ne'E'){"no pe";exit}
$mctypeoff = $fs.seek($peheader+4,[IO.SeekOrigin]::Begin)
$mctype= $br.ReadUInt16()
switch($mctype) {
0x0000 { "{0:x4} {1}" -f $mctype , "Unknown machine type"}
0x01d3 { "{0:x4} {1}" -f $mctype , "Matsushita AM33"}
0x8664 { "{0:x4} {1}" -f $mctype , "x64"}
0x01c0 { "{0:x4} {1}" -f $mctype , "ARM little endian"}
0x01c4 { "{0:x4} {1}" -f $mctype , "ARMv7 (or higher) Thumb mode only"}
0xaa64 { "{0:x4} {1}" -f $mctype , "ARMv8 in 64-bit mode"}
0x0ebc { "{0:x4} {1}" -f $mctype , "EFI byte code"}
0x014c { "{0:x4} {1}" -f $mctype , "Intel 386 or later family processors"}
0x0200 { "{0:x4} {1}" -f $mctype , "Intel Itanium processor family"}
0x9041 { "{0:x4} {1}" -f $mctype , "Mitsubishi M32R little endian"}
0x0266 { "{0:x4} {1}" -f $mctype , "MIPS16"}
0x0366 { "{0:x4} {1}" -f $mctype , "MIPS with FPU"}
0x0466 { "{0:x4} {1}" -f $mctype , "MIPS16 with FPU"}
0x01f0 { "{0:x4} {1}" -f $mctype , "Power PC little endian"}
0x01f1 { "{0:x4} {1}" -f $mctype , "Power PC with floating point support"}
0x0166 { "{0:x4} {1}" -f $mctype , "MIPS little endian"}
0x01a2 { "{0:x4} {1}" -f $mctype , "Hitachi SH3"}
0x01a3 { "{0:x4} {1}" -f $mctype , "Hitachi SH3 DSP"}
0x01a6 { "{0:x4} {1}" -f $mctype , "Hitachi SH4"}
0x01a8 { "{0:x4} {1}" -f $mctype , "Hitachi SH5"}
0x01c2 { "{0:x4} {1}" -f $mctype , "ARM or Thumb (`“interworking`”)"}
0x0169 { "{0:x4} {1}" -f $mctype , "MIPS little-endian WCE v2"}
};$fs.close()
usage as follows
:\>powershell -f binstreamtest.ps1
provide a file name or path to file
:\>powershell -f binstreamtest.ps1 1
file doesnt seem to exist
:\>powershell -f binstreamtest.ps1 shell32.dll
014c Intel 386 or later family processors
:\>powershell -f binstreamtest.ps1 c:\WINDOWS\system32\ntkrnlpa.exe
014c Intel 386 or later family processors
:\>powershell -f binstreamtest.ps1 xxx\test32.exe
014c Intel 386 or later family processors
:\>powershell -f binstreamtest.ps1 xxx\test64.exe
8664 x64
-
Note
exit
will actually kill the parent terminal, if you replace it withreturn
, it will work. In Powershell,return
is really more for control-flow, because values are implicitly outputted . The only time it doesn't, is when writing aclass
Commented Aug 20, 2022 at 1:40