Reads the machine type field from a Windows .exe file. From this we can determine 32-bit vs 64-bit as well as a couple of other things.
Last active
August 27, 2017 20:16
-
-
Save phansson/3160a3f607fd887a2cdf031896115f5c to your computer and use it in GitHub Desktop.
Windows EXE utils for Java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package org.phansson.pefilereader; | |
import java.io.File; | |
import java.io.FileInputStream; | |
import java.io.IOException; | |
import java.io.InputStream; | |
/** | |
* Utilities for getting information about Windows executable files (.exe). | |
* A Windows executable file adheres to the Windows PE (portable executable) | |
* file format, the specification of which is fully documented by | |
* Microsoft. | |
* | |
* <p> | |
* As of Aug 2017 the PE/COFF specification from Microsoft can be found | |
* at <a href="https://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx"> | |
* this location</a>. (download the file called {@code pecoff.docx}). | |
* | |
* @author Peter Hansson | |
*/ | |
public class WinExeUtils { | |
// In an .exe file the offset location of the PE signature is always | |
// found in a short val at position 60. | |
private static int OFFSET_FOR_PE_SIGNATURE = 0x3c; // decimal 60 | |
// The PE signature is always 4 bytes. It consist of the values | |
// PE\0\0 (the letters 'P' and 'E' followed by two nul bytes). | |
// We know that what we want - the machine type - is the next two | |
// bytes immediately following the PE signature. | |
private static int LENGTH_OF_PE_SIGNATURE = 4; | |
/** | |
* Gets the Windows machine type for which the file argument was compiled. | |
* The file argument is expected to be a Windows executable file (.exe). | |
* | |
* <p> | |
* The method is designed to be fast. It reads sufficient bytes from the | |
* file to be able to determine the machine type, but not more. | |
* | |
* <p> | |
* The method never returns {@code null}. | |
* | |
* @param exeFile | |
* @return the machine type. This may be {@link WinPEMachineType#IMAGE_FILE_MACHINE_UNKNOWN} | |
* if the file is not really an executable file, but some other file. | |
* | |
* @throws IOException if the file cannot be read or doesn't exist | |
*/ | |
public static WinPEMachineType getMachineType(File exeFile) throws IOException { | |
try (InputStream inputStream = new FileInputStream(exeFile)) { | |
// Read position of PE\0\0 from the byte value at position 3C (=60). | |
byte[] buffer = new byte[1024]; | |
int noOfBytesRead = inputStream.read(buffer); | |
if (noOfBytesRead < OFFSET_FOR_PE_SIGNATURE +1) { | |
// err : not enough bytes in file, probably not an .exe file | |
return WinPEMachineType.IMAGE_FILE_MACHINE_UNKNOWN; | |
} | |
byte peOffsetB1 = buffer[OFFSET_FOR_PE_SIGNATURE]; | |
byte peOffsetB2 = buffer[OFFSET_FOR_PE_SIGNATURE+1]; | |
int peOffset = getShort(peOffsetB1, peOffsetB2); | |
if (noOfBytesRead < peOffset + LENGTH_OF_PE_SIGNATURE + 2) { | |
// err : not enough bytes in file, probably not an .exe file | |
return WinPEMachineType.IMAGE_FILE_MACHINE_UNKNOWN; | |
} | |
byte machineTypeB1 = buffer[peOffset + LENGTH_OF_PE_SIGNATURE]; | |
byte machineTypeB2 = buffer[peOffset + LENGTH_OF_PE_SIGNATURE +1]; | |
short machineType = getShort(machineTypeB1, machineTypeB2); | |
WinPEMachineType mType = WinPEMachineType.valueOf(machineType); | |
if (mType == null) { | |
return WinPEMachineType.IMAGE_FILE_MACHINE_UNKNOWN; | |
} else { | |
return mType; | |
} | |
} | |
} | |
/** | |
* Returns {@code true} if the executable file is 64 bit. | |
* | |
* @see #getMachineType(java.io.File) | |
* @param exeFile Windows .exe file | |
* @return | |
* @throws IOException if the file cannot be read or doesn't exist | |
*/ | |
public static boolean is64Bit(File exeFile) throws IOException { | |
return (getMachineType(exeFile).getMachineTypeBitness() == 64); | |
} | |
/** | |
* Returns {@code true} if the executable file is 32 bit. | |
* | |
* @see #getMachineType(java.io.File) | |
* @param exeFile Windows .exe file | |
* @return | |
* @throws IOException if the file cannot be read or doesn't exist | |
*/ | |
public static boolean is32Bit(File exeFile) throws IOException { | |
return (getMachineType(exeFile).getMachineTypeBitness() == 32); | |
} | |
// converts two bytes to a short (little endian) | |
private static short getShort(byte b1, byte b2) { | |
return (short)((b2 << 8) | (b1 & 0xff)); | |
} | |
public static void main(String[] args) throws IOException { | |
WinPEMachineType machineType = getMachineType(new File("C:\\Program Files\\Java\\jdk1.8.0_92\\jre\\bin\\java.exe")); | |
System.out.println("Machine type : " + machineType); | |
machineType = getMachineType(new File("C:\\Program Files (x86)\\Adobe\\Acrobat Reader DC\\Reader\\AcroRd32.exe")); | |
System.out.println("Machine type : " + machineType); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package org.phansson.pefilereader; | |
/** | |
* Windows Machine Type as they are specified in the COFF File header. | |
* The COFF file header can be found in Windows executables (.exe), dynamic | |
* link libraries (.dll) and object files (.obj). | |
* | |
* <p> | |
* See "Microsoft Portable Executable and Common Object File Format Specification" | |
* for more information (can be downloaded from Microsoft). | |
* | |
* @author Peter Hansson | |
*/ | |
public enum WinPEMachineType { | |
IMAGE_FILE_MACHINE_UNKNOWN( (short) 0x0, -1), | |
IMAGE_FILE_MACHINE_AM33( (short) 0x1d3, 32), // Matsushita AM33 | |
IMAGE_FILE_MACHINE_AMD64( (short) 0x8664, 64), // x64 | |
IMAGE_FILE_MACHINE_ARM( (short) 0x1c0, 32), // ARM little endian | |
IMAGE_FILE_MACHINE_ARM64( (short) 0xaa64, 64), // ARM64 little endian | |
IMAGE_FILE_MACHINE_ARMNT( (short) 0x1c4, 32), // ARM Thumb-2 little endian | |
IMAGE_FILE_MACHINE_EBC( (short) 0xebc, -1), // EFI byte code | |
IMAGE_FILE_MACHINE_I386( (short) 0x14c, 32), // Intel 386 or later processors and compatible processors | |
IMAGE_FILE_MACHINE_IA64( (short) 0x200, 64), // Intel Itanium processor family | |
IMAGE_FILE_MACHINE_M32R( (short) 0x9041, 32), // Mitsubishi M32R little endian | |
IMAGE_FILE_MACHINE_MIPS16( (short) 0x266, 16), // MIPS16 | |
IMAGE_FILE_MACHINE_MIPSFPU( (short) 0x366, 32), // MIPS with FPU | |
IMAGE_FILE_MACHINE_MIPSFPU16( (short) 0x466, 16), // MIPS16 with FPU | |
IMAGE_FILE_MACHINE_POWERPC( (short) 0x1f0, 64), // Power PC little endian | |
IMAGE_FILE_MACHINE_POWERPCFP( (short) 0x1f1, 64), // Power PC with floating point support | |
IMAGE_FILE_MACHINE_R4000( (short) 0x166, 64), // MIPS little endian | |
IMAGE_FILE_MACHINE_RISCV32( (short) 0x5032, 32), // RISC-V 32-bit address space | |
IMAGE_FILE_MACHINE_RISCV64( (short) 0x5064, 64), // RISC-V 64-bit address space | |
IMAGE_FILE_MACHINE_RISCV128( (short) 0x5128, 128), // RISC-V 128-bit address space | |
IMAGE_FILE_MACHINE_SH3( (short) 0x1a2, 32), // Hitachi SH3 | |
IMAGE_FILE_MACHINE_SH3DSP( (short) 0x1a3, 32), // Hitachi SH3 DSP | |
IMAGE_FILE_MACHINE_SH4( (short) 0x1a6, 32), // Hitachi SH4 | |
IMAGE_FILE_MACHINE_SH5( (short) 0x1a8, 64), // Hitachi SH5 | |
IMAGE_FILE_MACHINE_THUMB( (short) 0x1c2, 32), // ARM Thumb/Thumb-2 Little-Endian | |
IMAGE_FILE_MACHINE_WCEMIPSV2( (short) 0x169, 32); // MIPS little-endian WCE v2 | |
private final short shortVal; | |
private final int bitness; | |
WinPEMachineType(short shortVal, int bitness) { | |
this.shortVal = shortVal; | |
this.bitness = bitness; | |
} | |
/** | |
* Gets type safe enum from short value | |
* @param shortVal | |
* @return | |
*/ | |
public static WinPEMachineType valueOf(short shortVal) { | |
for (WinPEMachineType p : WinPEMachineType.values()) { | |
if (p.getShortValue() == shortVal) { | |
return p; | |
} | |
} | |
return null; | |
} | |
/** | |
* Gets corresponding short value | |
* @return | |
*/ | |
public short getShortValue() { | |
return shortVal; | |
} | |
/** | |
* Gets the 'bitness' of the platform, e.g. 32-bit, 64-bit, etc. | |
* | |
* @return 32 for a 32-bit platform, and so on. | |
*/ | |
public int getMachineTypeBitness() { | |
return bitness; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment