Monday, June 23, 2014

Determining if a file is an executable (.exe) pro-grammatically.

Ever look at hex dump of a exe file and wonder why it starts with MZ?

ffset:0(0x0)  size:131072( 0x20000 ) dump by http://pedump.me/ 
00000000:  4d 5a 90 00 03 00 00 00  04 00 00 00 ff ff 00 00  |MZ..............|
00000010:  b8 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00  |........@.......|
00000020:  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000030:  00 00 00 00 00 00 00 00  00 00 00 00 e8 00 00 00  |................|
00000040:  0e 1f ba 0e 00 b4 09 cd  21 b8 01 4c cd 21 54 68  |........!..L.!Th|
00000050:  69 73 20 70 72 6f 67 72  61 6d 20 63 61 6e 6e 6f  |is program canno|
00000060:  74 20 62 65 20 72 75 6e  20 69 6e 20 44 4f 53 20  |t be run in DOS |
00000070:  6d 6f 64 65 2e 0d 0d 0a  24 00 00 00 00 00 00 00  |mode....$.......|



Well here's you trivial fact of the day...


In ASCII representation, 0x5A4D is MZ, the initials of Mark Zbikowski, one of the original architects of MS-DOS.

And guess what this is how we determine if this file is an executable, we just check for MZ at the beginning of it.


Why would you do this, well if you create a firewall rule to scan zip files you might want to scan if contains renamed zip files, by checking the "MZ"-ness.

 Here's the code

IMAGE_FILE_MACHINE extensive machine type enum list

A modest enumeration list of Machine Types with better descriptions. This came from my search to be able to determine an application architecture build type of a file. See Determining if App Executable is 32-bit or 64-bit discussion and code here.


  1. //OVERLOADED _AMD64 = 0x8664, means x64 app, http://msdn.microsoft.com/en-us/library/windows/desktop/ms680313(v=vs.85).aspx
              OR _EMT64 
    = 0x8664, named IA-32e (later renamed EM64T, 
  2. then yet again renamed to Intel 64 by Intel to stave of AMD)       
  3. //            _I386 = 0x14c,           means x32 app
  4. public enum MachineType : ushort
  5. {
  6.    IMAGE_FILE_MACHINE_UNKNOWN = 0x0,        
  7.    IMAGE_FILE_MACHINE_ALPHA = 0x184,       //Digital Equipment Corporation (DEC) Alpha (32-bit)
  8.    IMAGE_FILE_MACHINE_AM33 = 0x1d3,        //Matsushita AM33, now MN103 (32-bit) part of Panasonic Corporation
  9.    IMAGE_FILE_MACHINE_AMD64 = 0x8664,      //AMD (64-bit) - was Advanced Micro Devices, now means x64  - OVERLOADED _AMD64 = 0x8664 - http://msdn.microsoft.com/en-us/library/windows/desktop/ms680313(v=vs.85).aspx  
  10.    IMAGE_FILE_MACHINE_ARM = 0x1c0,         //ARM little endian (32-bit), ARM Holdings, later versions 6+ used in iPhone, Microsoft Nokia N900
  11.    IMAGE_FILE_MACHINE_ARMV7 = 0x1c4,       //ARMv7 or IMAGE_FILE_MACHINE_ARMNT (or higher) Thumb mode only (32 bit).
  12.    IMAGE_FILE_MACHINE_ARM64 = 0xaa64,      //ARM8+ (64-bit)
  13.    IMAGE_FILE_MACHINE_EBC = 0xebc,         //EFI byte code (32-bit), now (U)EFI or (Unified) Extensible Firmware Interface
  14.    IMAGE_FILE_MACHINE_I386 = 0x14c,        //Intel 386 or later processors and compatible processors (32-bit)
  15.    IMAGE_FILE_MACHINE_I860 = 0x14d,        //Intel i860 (aka 80860) (32-bit) was a RISC microprocessor design introduced by Intel in 1989, this was depricated in 90's
  16.    IMAGE_FILE_MACHINE_IA64 = 0x200,        //Intel Itanium architecture processor family, (64-bit)
  17.    IMAGE_FILE_MACHINE_M68K = 0x268,        //Motorola 68000 Series (32-bit) CISC microprocessors
  18.    IMAGE_FILE_MACHINE_M32R = 0x9041,       //Mitsubishi M32R little endian (32-bit) now owned by Renesas Electronics Corporation
  19.    IMAGE_FILE_MACHINE_MIPS16 = 0x266,      //MIPS16 (16-bit instruction codes, 8to32bit bus)- Microprocessor without Interlocked Pipeline Stages Architecture
  20.    IMAGE_FILE_MACHINE_MIPSFPU = 0x366,     //MIPS with FPU, MIPS Technologies (32-bit)
  21.    IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466,   //MIPS16 with FPU (Floating Point Unit aka a math co-processesor)(16-bit instruction codes, 8to32bit bus)
  22.    IMAGE_FILE_MACHINE_POWERPC = 0x1f0,     //Power PC little endian, Performance Optimization With Enhanced RISC – Performance Computing (32-bit) one of the first
  23.    IMAGE_FILE_MACHINE_POWERPCFP = 0x1f1,   //Power PC with floating point support (FPU) (32-bit), designed by AIM Alliance (Apple, IBM, and Motorola)
  24.    IMAGE_FILE_MACHINE_POWERPCBE = 0x01F2,  //Power PC Big Endian (64?-bits)
  25.    IMAGE_FILE_MACHINE_R3000 = 0x0162,      //R3000 (32-bit) RISC processor
  26.    IMAGE_FILE_MACHINE_R4000 = 0x166,       //R4000 MIPS (64-bit) - claims to be first true 64-bit processor
  27.    IMAGE_FILE_MACHINE_R10000 = 0x0168,     //R10000 MIPS IV is a (64-bit) architecture, but the R10000 did not implement the entire physical or virtual address to reduce cost. Instead, it has a 40-bit physical address and a 44-bit virtual address, thus it is capable of addressing 1 TB of physical memory and 16 TB of virtual memory. These comments by metadataconsulting.ca
  28.    IMAGE_FILE_MACHINE_SH3 = 0x1a2,         //Hitachi SH-3 (32-bit) - SuperH processor (SH3) core family
  29.    IMAGE_FILE_MACHINE_SH3DSP = 0x1a3,      //Hitachi SH-3 DSP (32-bit)
  30.    IMAGE_FILE_MACHINE_SH4 = 0x1a6,         //Hitachi SH-4 (32-bit)
  31.    IMAGE_FILE_MACHINE_SH5 = 0x1a8,         //Hitachi SH-5, (64-bit) core with a 128-bit vector FPU (64 32-bit registers) and an integer unit which includes the SIMD support and 63 64-bit registers.
  32.    IMAGE_FILE_MACHINE_TRICORE = 0x0520,    //Infineon AUDO (Automotive unified processor) (32-bit) - Tricore architecture a unified RISC/MCU/DSP microcontroller core
  33.    IMAGE_FILE_MACHINE_THUMB = 0x1c2,       //ARM or Thumb (interworking), (32-bit) core instruction set, used in Nintendo Gameboy Advance
  34.    IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169,   //MIPS Windows Compact Edition v2
  35.    IMAGE_FILE_MACHINE_ALPHA64 = 0x284      //DEC Alpha AXP (64-bit) or IMAGE_FILE_MACHINE_AXP64
  36. }


Determining if App Executable is 32-bit or 64-bit

Need to find out if your application executable is 32-bit or 64-bit reliably pro-grammatically in C#

My first attempt was to use the GetBinaryType() - using DLL Import
but reading comment in the MSDN Library reference indicates it is not reliable solution. 

So how can we examine a file to determine "bitness"? 

Again we head back to the source in a issue of February 2002 issue of MSDN Magazine "
Win32 Portable Executable File Format"

The format of an operating system's executable file is in many ways a mirror of the operating system. Although studying an executable file format isn't usually high on most programmers' list of things to do, a great deal of knowledge can be gleaned this way. In this article, I'll give a tour of the Portable Executable (PE) file format that Microsoft has designed for use by all their Win32®-based systems: Windows NT®, Win32s™, and Windows® 95. 

PE File Structure

      Now let's dig into the actual format of PE files. I'll start from the beginning of the file, and describe the data structures that are present in every PE file. Afterwards, I'll describe the more specialized data structures (such as imports or resources) that reside within a PE's sections. All of the data structures that I'll discuss below are defined in WINNT.H, unless otherwise noted.
      In many cases, there are matching 32 and 64-bit data structures—for example, IMAGE_NT_HEADERS32 and IMAGE_NT_HEADERS64.

The IMAGE_NT_HEADERS Header

      The IMAGE_NT_HEADERS structure is the primary location where specifics of the PE file are stored. Its offset is given by the e_lfanew field in the IMAGE_DOS_HEADER at the beginning of the file. There are actually two versions of the IMAGE_NT_HEADER structure, one for 32-bit executables and the other for 64-bit versions. The differences are so minor that I'll consider them to be the same for the purposes of this discussion. The only correct, Microsoft-approved way of differentiating between the two formats is via the value of the Magic field in the IMAGE_OPTIONAL_HEADER (described shortly).

An IMAGE_NT_HEADER is comprised of three fields:

 
 typedef struct _IMAGE_NT_HEADERS {
      DWORD Signature;
     IMAGE_FILE_HEADER FileHeader;
     IMAGE_OPTIONAL_HEADER32 OptionalHeader;
  } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

In a valid PE file, the Signature field is set to the value 0x00004550, which in ASCII is "PE00". A #define, IMAGE_NT_SIGNATURE, is defined for this value. The second field, a struct of type IMAGE_FILE_HEADER, predates PE files.


The PE File IMAGE_FILE_HEADER referenced in the above article as Figure 5 is quoted below.Figure 5 IMAGE_OPTIONAL_HEADER 

SizeStructure MemberDescription
WORDMagicA signature WORD, identifying what type of header this is. The two most common values are IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b and IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b.


To code use

http://www.pinvoke.net/default.aspx/Structures.IMAGE_OPTIONAL_HEADER32


 public enum MachineType : ushort
    {
        Native = 0,
        I386 = 0x014c,
        Itanium = 0x0200,
        x64 = 0x8664
    }
    public enum MagicType : ushort
    {
        IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b,
        IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b
    }
    public enum SubSystemType : ushort
    {
        IMAGE_SUBSYSTEM_UNKNOWN = 0,
        IMAGE_SUBSYSTEM_NATIVE = 1,
        IMAGE_SUBSYSTEM_WINDOWS_GUI = 2,
        IMAGE_SUBSYSTEM_WINDOWS_CUI = 3,
        IMAGE_SUBSYSTEM_POSIX_CUI = 7,
        IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9,
        IMAGE_SUBSYSTEM_EFI_APPLICATION = 10,
        IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11,
        IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12,
        IMAGE_SUBSYSTEM_EFI_ROM = 13,
        IMAGE_SUBSYSTEM_XBOX = 14

    }
    public enum DllCharacteristicsType : ushort
    {
        RES_0 = 0x0001,
        RES_1 = 0x0002,
        RES_2 = 0x0004,
        RES_3 = 0x0008,
        IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = 0x0040,
        IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY = 0x0080,
        IMAGE_DLL_CHARACTERISTICS_NX_COMPAT = 0x0100,
        IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200,
        IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400,
        IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800,
        RES_4 = 0x1000,
        IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000,
        IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000
    }

    [StructLayout(LayoutKind.Explicit)]
    public struct IMAGE_OPTIONAL_HEADER32
    {
        [FieldOffset(0)]
        public MagicType Magic;

        [FieldOffset(2)]
        public byte MajorLinkerVersion;

        [FieldOffset(3)]
        public byte MinorLinkerVersion;

        [FieldOffset(4)]
        public uint SizeOfCode;

        [FieldOffset(8)]
        public uint SizeOfInitializedData;

        [FieldOffset(12)]
        public uint SizeOfUninitializedData;

        [FieldOffset(16)]
        public uint AddressOfEntryPoint;

        [FieldOffset(20)]
        public uint BaseOfCode;

        // PE32 contains this additional field
        [FieldOffset(24)]
        public uint BaseOfData;

        [FieldOffset(28)]
        public uint ImageBase;

        [FieldOffset(32)]
        public uint SectionAlignment;

        [FieldOffset(36)]
        public uint FileAlignment;

        [FieldOffset(40)]
        public ushort MajorOperatingSystemVersion;

        [FieldOffset(42)]
        public ushort MinorOperatingSystemVersion;

        [FieldOffset(44)]
        public ushort MajorImageVersion;

        [FieldOffset(46)]
        public ushort MinorImageVersion;

        [FieldOffset(48)]
        public ushort MajorSubsystemVersion;

        [FieldOffset(50)]
        public ushort MinorSubsystemVersion;

        [FieldOffset(52)]
        public uint Win32VersionValue;

        [FieldOffset(56)]
        public uint SizeOfImage;

        [FieldOffset(60)]
        public uint SizeOfHeaders;

        [FieldOffset(64)]
        public uint CheckSum;

        [FieldOffset(68)]
        public SubSystemType Subsystem;

        [FieldOffset(70)]
        public DllCharacteristicsType DllCharacteristics;

        [FieldOffset(72)]
        public uint SizeOfStackReserve;

        [FieldOffset(76)]
        public uint SizeOfStackCommit;

        [FieldOffset(80)]
        public uint SizeOfHeapReserve;

        [FieldOffset(84)]
        public uint SizeOfHeapCommit;

        [FieldOffset(88)]
        public uint LoaderFlags;

        [FieldOffset(92)]
        public uint NumberOfRvaAndSizes;

        [FieldOffset(96)]
        public IMAGE_DATA_DIRECTORY ExportTable;

        [FieldOffset(104)]
        public IMAGE_DATA_DIRECTORY ImportTable;

        [FieldOffset(112)]
        public IMAGE_DATA_DIRECTORY ResourceTable;

        [FieldOffset(120)]
        public IMAGE_DATA_DIRECTORY ExceptionTable;

        [FieldOffset(128)]
        public IMAGE_DATA_DIRECTORY CertificateTable;

        [FieldOffset(136)]
        public IMAGE_DATA_DIRECTORY BaseRelocationTable;

        [FieldOffset(144)]
        public IMAGE_DATA_DIRECTORY Debug;

        [FieldOffset(152)]
        public IMAGE_DATA_DIRECTORY Architecture;

        [FieldOffset(160)]
        public IMAGE_DATA_DIRECTORY GlobalPtr;

        [FieldOffset(168)]
        public IMAGE_DATA_DIRECTORY TLSTable;

        [FieldOffset(176)]
        public IMAGE_DATA_DIRECTORY LoadConfigTable;

        [FieldOffset(184)]
        public IMAGE_DATA_DIRECTORY BoundImport;

        [FieldOffset(192)]
        public IMAGE_DATA_DIRECTORY IAT;

        [FieldOffset(200)]
        public IMAGE_DATA_DIRECTORY DelayImportDescriptor;

        [FieldOffset(208)]
        public IMAGE_DATA_DIRECTORY CLRRuntimeHeader;

        [FieldOffset(216)]
        public IMAGE_DATA_DIRECTORY Reserved;
    }
    [StructLayout(LayoutKind.Explicit)]
    public struct IMAGE_OPTIONAL_HEADER64
    {
        [FieldOffset(0)]
        public MagicType Magic;

        [FieldOffset(2)]
        public byte MajorLinkerVersion;

        [FieldOffset(3)]
        public byte MinorLinkerVersion;

        [FieldOffset(4)]
        public uint SizeOfCode;

        [FieldOffset(8)]
        public uint SizeOfInitializedData;

        [FieldOffset(12)]
        public uint SizeOfUninitializedData;

        [FieldOffset(16)]
        public uint AddressOfEntryPoint;

        [FieldOffset(20)]
        public uint BaseOfCode;

        [FieldOffset(24)]
        public ulong ImageBase;

        [FieldOffset(32)]
        public uint SectionAlignment;

        [FieldOffset(36)]
        public uint FileAlignment;

        [FieldOffset(40)]
        public ushort MajorOperatingSystemVersion;

        [FieldOffset(42)]
        public ushort MinorOperatingSystemVersion;

        [FieldOffset(44)]
        public ushort MajorImageVersion;

        [FieldOffset(46)]
        public ushort MinorImageVersion;

        [FieldOffset(48)]
        public ushort MajorSubsystemVersion;

        [FieldOffset(50)]
        public ushort MinorSubsystemVersion;

        [FieldOffset(52)]
        public uint Win32VersionValue;

        [FieldOffset(56)]
        public uint SizeOfImage;

        [FieldOffset(60)]
        public uint SizeOfHeaders;

        [FieldOffset(64)]
        public uint CheckSum;

        [FieldOffset(68)]
        public SubSystemType Subsystem;

        [FieldOffset(70)]
        public DllCharacteristicsType DllCharacteristics;

        [FieldOffset(72)]
        public ulong SizeOfStackReserve;

        [FieldOffset(80)]
        public ulong SizeOfStackCommit;

        [FieldOffset(88)]
        public ulong SizeOfHeapReserve;

        [FieldOffset(96)]
        public ulong SizeOfHeapCommit;

        [FieldOffset(104)]
        public uint LoaderFlags;

        [FieldOffset(108)]
        public uint NumberOfRvaAndSizes;

        [FieldOffset(112)]
        public IMAGE_DATA_DIRECTORY ExportTable;

        [FieldOffset(120)]
        public IMAGE_DATA_DIRECTORY ImportTable;

        [FieldOffset(128)]
        public IMAGE_DATA_DIRECTORY ResourceTable;

        [FieldOffset(136)]
        public IMAGE_DATA_DIRECTORY ExceptionTable;

        [FieldOffset(144)]
        public IMAGE_DATA_DIRECTORY CertificateTable;

        [FieldOffset(152)]
        public IMAGE_DATA_DIRECTORY BaseRelocationTable;

        [FieldOffset(160)]
        public IMAGE_DATA_DIRECTORY Debug;

        [FieldOffset(168)]
        public IMAGE_DATA_DIRECTORY Architecture;

        [FieldOffset(176)]
        public IMAGE_DATA_DIRECTORY GlobalPtr;

        [FieldOffset(184)]
        public IMAGE_DATA_DIRECTORY TLSTable;

        [FieldOffset(192)]
        public IMAGE_DATA_DIRECTORY LoadConfigTable;

        [FieldOffset(200)]
        public IMAGE_DATA_DIRECTORY BoundImport;

        [FieldOffset(208)]
        public IMAGE_DATA_DIRECTORY IAT;

        [FieldOffset(216)]
        public IMAGE_DATA_DIRECTORY DelayImportDescriptor;

        [FieldOffset(224)]
        public IMAGE_DATA_DIRECTORY CLRRuntimeHeader;

        [FieldOffset(232)]
        public IMAGE_DATA_DIRECTORY Reserved;
    }

The unreliable way.....
using System;
using System.IO; 

public enum MachineType {Unknown = 0, 
                          x86 = 0x014c, 
                          i64 = 0x0200, 
                          x64 = 0x8664 }  

public string GetAppCompiledMachineType(string fileName)
{
            const int PE_POINTER_OFFSET = 60;            
            const int MACHINE_OFFSET = 4;
            byte[] data = new byte[4096];

            using (Stream s = new FileStream(fileName, FileMode.Open, FileAccess.Read)) {
                s.Read(data, 0, 4096);
            }

            // dos header is 64 bytes, last element, long (4 bytes) is the address of the PE header
            int PE_HEADER_ADDR = BitConverter.ToInt32(data, PE_POINTER_OFFSET);
            int machineUint = BitConverter.ToUInt16(data, PE_HEADER_ADDR + MACHINE_OFFSET);
            return ((MachineType)machineUint).ToString();
}