读文件头数据判断 PE 文件格式和类型

时间:2019-05-11 09:52来源:计算机教程
namespace X.Reflection{ using System; using System.IO; public static partial class ReflectionX { public static PeType GetPeType(this string filepath) { using (var fs = File.OpenRead(filepath)) using (var br = new BinaryReader(fs)) { try { i
namespace X.Reflection
{
    using System;
    using System.IO;
    public static partial class ReflectionX
    {
        public static PeType GetPeType(this string filepath)
        {
            using (var fs = File.OpenRead(filepath))
            using (var br = new BinaryReader(fs))
            {
                try
                {
                    if (IMAGE_DOS_SIGNATURE != br.ReadInt16()) return PeType.NotExecutable;

                    fs.Seek(offset__IMAGE_DOS_HEADER__e_lfanew, SeekOrigin.Begin);
                    var offsetNH = br.ReadUInt32();
                    if (offsetNH > fs.Length || 0 != offsetNH % 2 || 0 == offsetNH) return PeType.MsDosExecutable;
                    if (offsetNH   4   sizeof__IMAGE_FILE_HEADER   2 >= fs.Length) return PeType.OptionalHeaderMagicExceedFileLength;

                    fs.Seek(offsetNH, SeekOrigin.Begin);
                    switch (br.ReadInt16())
                    {
                        case IMAGE_NT_SIGNATURE_LOWORD:
                            if (IMAGE_NT_SIGNATURE_HIWORD == br.ReadInt16()) break;
                            return PeType.MsDosExecutable;

                        case IMAGE_OS2_SIGNATURE: return PeType.Windows16BitExecutable;
                        case IMAGE_VXD_SIGNATURE: return PeType.Windows16BitVirtualDeviceDriver;
                        default: return PeType.MsDosExecutable;
                    }

                    //fs.Seek //紧跟前面的 pimNH64->Signature,所以不用 fs.Seek
                    //var machine = br.ReadUInt16();
                    fs.Seek(offsetNH   offset__IMAGE_NT_HEADERS__FileHeader__Characteristics, SeekOrigin.Begin);
                    var characteristics = br.ReadUInt16();
                    //var is32bit = IMAGE_FILE_32BIT_MACHINE & characteristics;
                    var dllfile = IMAGE_FILE_DLL & characteristics;
                    //fs.Seek //紧跟前面的 pimNH64->OptionalHeader.Magic,所以不用 fs.Seek
                    var magic = br.ReadUInt16();

                    //get RVA
                    uint rvaCH;
                    switch (magic)
                    {
                        case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
                            //if (IMAGE_FILE_MACHINE_I386 != machine)
                            //    throw new BadImageFormatException(
                            //        $"幻数值与目标机器类型不一致: IMAGE_NT_HEADERS.OptionalHeader.Magic({magic:X4})/IMAGE_NT_HEADERS.FileHeader.Machine({machine:X4})",
                            //        filepath);
                            if (offsetNH   offset__IMAGE_NT_HEADERS__OptionalHeader   sizeof__IMAGE_OPTIONAL_HEADER32 > fs.Length)
                                return PeType.OptionalHeader32ExceedFileLength;
                            fs.Seek(offsetNH   offset__IMAGE_NT_HEADERS32__OptionalHeader__DataDirectory__14__VirtualAddress, SeekOrigin.Begin);
                            rvaCH = br.ReadUInt32();
                            break;

                        case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
                            //if (IMAGE_FILE_MACHINE_AMD64 != machine)
                            //    throw new BadImageFormatException(
                            //        $"幻数值与目标机器类型不一致: IMAGE_NT_HEADERS.OptionalHeader.Magic({magic:X4})/IMAGE_NT_HEADERS.FileHeader.Machine({machine:X4})",
                            //        filepath);
                            if (offsetNH   offset__IMAGE_NT_HEADERS__OptionalHeader   sizeof__IMAGE_OPTIONAL_HEADER64 > fs.Length)
                                return PeType.OptionalHeader64ExceedFileLength;
                            fs.Seek(offsetNH   offset__IMAGE_NT_HEADERS64__OptionalHeader__DataDirectory__14__VirtualAddress, SeekOrigin.Begin);
                            rvaCH = br.ReadUInt32();
                            break;

                        default:
                            //throw new BadImageFormatException(
                            //    //$"预料之外的幻数值: IMAGE_NT_HEADERS.OptionalHeader.Magic({magic:X4})/IMAGE_NT_HEADERS.FileHeader.Machine({machine:X4})",
                            //    $"预料之外的幻数值: IMAGE_NT_HEADERS.OptionalHeader.Magic({magic:X4})",
                            //    filepath);
                            return PeType.OptionalHeaderMagicNot3264;
                    }

                    fs.Seek(offsetNH   offset__IMAGE_NT_HEADERS__OptionalHeader__Subsystem, SeekOrigin.Begin);
                    var subSystem = br.ReadInt16();

                    PeType pt;
                    if (0 != rvaCH)
                    {
                        //translate RVA to file offset
                        uint offsetCH = 0;
                        fs.Seek(offsetNH   offset__IMAGE_NT_HEADERS__FileHeader__SizeOfOptionalHeader, SeekOrigin.Begin);
                        uint offsetSH = offsetNH   offset__IMAGE_NT_HEADERS__OptionalHeader   br.ReadUInt16();
                        fs.Seek(offsetNH   offset__IMAGE_NT_HEADERS__FileHeader__NumberOfSections, SeekOrigin.Begin);
                        var numberOfSections = br.ReadUInt16();
                        while (numberOfSections-- > 0)
                        {
                            if (offsetSH   sizeof__IMAGE_SECTION_HEADER > fs.Length) return PeType.SectionHeaderExceedFileLength;
                            fs.Seek(offsetSH   offset__IMAGE_SECTION_HEADER__VirtualAddress, SeekOrigin.Begin);
                            var VirtualAddress = br.ReadUInt32();
                            var SizeOfRawData = br.ReadUInt32();
                            if (VirtualAddress <= rvaCH && rvaCH < VirtualAddress   SizeOfRawData)
                            {
                                offsetCH = br.ReadUInt32()   rvaCH - VirtualAddress;
                                break;
                            }
                            offsetSH  = sizeof__IMAGE_SECTION_HEADER;
                        }
                        if (offsetCH   sizeof__IMAGE_COR20_HEADER > fs.Length) return PeType.Cor20HeaderExceedFileLength;
                        fs.Seek(offsetCH   offset__IMAGE_COR20_HEADER__Flags, SeekOrigin.Begin);
                        uint chFlags = br.ReadUInt32();

                        if (0 != (COMIMAGE_FLAGS_ILONLY & chFlags))
                        {
                            if (0 != (COMIMAGE_FLAGS_32BITREQUIRED & chFlags)) //X86
                            {
                                pt = (PeType)PeTypeBitness.X86 | ((0 != (COMIMAGE_FLAGS_32BITPREFERRED & chFlags))
                                    ? (PeType)PeTypePlatform.AnyCPU //AnyCPU32
                                    : (PeType)PeTypePlatform.ILOnly //ILOnly32
                                    );
                            }
                            else //X64
                            {
                                pt = (PeType)PeTypeBitness.X64;
                                switch (magic)
                                {
                                    case IMAGE_NT_OPTIONAL_HDR32_MAGIC: pt |= (PeType)PeTypePlatform.AnyCPU; break; //AnyCPU64
                                    case IMAGE_NT_OPTIONAL_HDR64_MAGIC: pt |= (PeType)PeTypePlatform.ILOnly; break; //ILOnly64
                                }
                            }
                        }
                        else //Mixed
                        {
                            pt = (PeType)PeTypePlatform.Mixing;
                            switch (magic)
                            {
                                case IMAGE_NT_OPTIONAL_HDR32_MAGIC: pt |= (PeType)PeTypeBitness.X86; break; //Mixed32
                                case IMAGE_NT_OPTIONAL_HDR64_MAGIC: pt |= (PeType)PeTypeBitness.X64; break; //Mixed64
                            }
                        }

                        //file ext & subsystem
                        if (0 == dllfile)
                        {
                            pt |= (PeType)PeTypeExt.Exe;
                            switch (subSystem)
                            {
                                case IMAGE_SUBSYSTEM_WINDOWS_GUI: pt |= (PeType)PeTypeSubSystem.WindowsGui; break;
                                case IMAGE_SUBSYSTEM_WINDOWS_CUI: pt |= (PeType)PeTypeSubSystem.ConsoleCui; break;
                            }
                        }
                        else
                        {
                            pt |= (PeType)PeTypeExt.Dll;
                        }
                    }
                    else //Native
                    {
                        pt = (PeType)PeTypePlatform.Native;
                        switch (magic)
                        {
                            case IMAGE_NT_OPTIONAL_HDR32_MAGIC: pt |= (PeType)PeTypeBitness.X86; break; //Native32
                            case IMAGE_NT_OPTIONAL_HDR64_MAGIC: pt |= (PeType)PeTypeBitness.X64; break; //Native64
                        }

                        //file ext & subsystem
                        if (IMAGE_SUBSYSTEM_NATIVE == subSystem)
                        {
                            pt |= (PeType)PeTypeExt.Drv;
                        }
                        else if (0 == dllfile)
                        {
                            pt |= (PeType)PeTypeExt.Exe;
                            switch (subSystem)
                            {
                                case IMAGE_SUBSYSTEM_WINDOWS_GUI: pt |= (PeType)PeTypeSubSystem.WindowsGui; break;
                                case IMAGE_SUBSYSTEM_WINDOWS_CUI: pt |= (PeType)PeTypeSubSystem.ConsoleCui; break;
                            }
                        }
                        else
                        {
                            pt |= (PeType)PeTypeExt.Dll;
                        }
                    }
                    return pt;
                }
                catch (Exception ex)
                {
                    return PeType.ErrorOccurred;
                }
            }
        }

        private const int offset__IMAGE_DOS_HEADER__e_lfanew = 60;
        private const int offset__IMAGE_NT_HEADERS__FileHeader__NumberOfSections = 4   2;
        private const int offset__IMAGE_NT_HEADERS__FileHeader__SizeOfOptionalHeader = 4   16;
        private const int offset__IMAGE_NT_HEADERS__FileHeader__Characteristics = 4   18;
        private const int offset__IMAGE_NT_HEADERS__OptionalHeader = 4   sizeof__IMAGE_FILE_HEADER;
        private const int offset__IMAGE_NT_HEADERS__OptionalHeader__Subsystem = offset__IMAGE_NT_HEADERS__OptionalHeader   4 * 17;
        private const int offset__IMAGE_NT_HEADERS32__OptionalHeader__DataDirectory__14__VirtualAddress = offset__IMAGE_NT_HEADERS__OptionalHeader   96   8 * 14;
        private const int offset__IMAGE_NT_HEADERS64__OptionalHeader__DataDirectory__14__VirtualAddress = offset__IMAGE_NT_HEADERS__OptionalHeader   112   8 * 14;
        private const int offset__IMAGE_SECTION_HEADER__VirtualAddress = 8   4;
        private const int offset__IMAGE_COR20_HEADER__Flags = 4   2   2   8;

        private const int sizeof__IMAGE_FILE_HEADER = 20;
        private const int sizeof__IMAGE_OPTIONAL_HEADER32 = 96   8 * 16;
        private const int sizeof__IMAGE_OPTIONAL_HEADER64 = 112   8 * 16;
        private const int sizeof__IMAGE_SECTION_HEADER = 40;
        private const int sizeof__IMAGE_COR20_HEADER = 72;

        private const int IMAGE_DOS_SIGNATURE = 0x5A4D;
        private const int IMAGE_OS2_SIGNATURE = 0x454E;
        private const int IMAGE_VXD_SIGNATURE = 0x454C;
        private const int IMAGE_NT_SIGNATURE_LOWORD = 0x4550;
        private const int IMAGE_NT_SIGNATURE_HIWORD = 0x0000;
        private const int IMAGE_FILE_MACHINE_I386 = 0x014C;
        private const int IMAGE_FILE_MACHINE_AMD64 = 0x8664;
        private const int IMAGE_FILE_32BIT_MACHINE = 0x0100;
        private const int IMAGE_FILE_DLL = 0x2000;
        private const int IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10B;
        private const int IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20B;

        //private const int IMAGE_SUBSYSTEM_UNKNOWN = 0; // Unknown subsystem.
        private const int IMAGE_SUBSYSTEM_NATIVE = 1; // Image doesn't require a subsystem.
        private const int IMAGE_SUBSYSTEM_WINDOWS_GUI = 2; // Image runs in the Windows GUI subsystem.
        private const int IMAGE_SUBSYSTEM_WINDOWS_CUI = 3; // Image runs in the Windows character subsystem.
        //private const int IMAGE_SUBSYSTEM_OS2_CUI = 5; // image runs in the OS/2 character subsystem.
        //private const int IMAGE_SUBSYSTEM_POSIX_CUI = 7; // image runs in the Posix character subsystem.
        //private const int IMAGE_SUBSYSTEM_NATIVE_WINDOWS = 8; // image is a native Win9x driver.
        //private const int IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9; // Image runs in the Windows CE subsystem.
        //private const int IMAGE_SUBSYSTEM_EFI_APPLICATION = 10; //
        //private const int IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11; //
        //private const int IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12; //
        //private const int IMAGE_SUBSYSTEM_EFI_ROM = 13;
        //private const int IMAGE_SUBSYSTEM_XBOX = 14;
        //private const int IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION = 16;
        //private const int IMAGE_SUBSYSTEM_XBOX_CODE_CATALOG = 17;

        private const int COMIMAGE_FLAGS_ILONLY = 0x00000001;
        private const int COMIMAGE_FLAGS_32BITREQUIRED = 0x00000002;
        //private const int COMIMAGE_FLAGS_IL_LIBRARY = 0x00000004;
        //private const int COMIMAGE_FLAGS_STRONGNAMESIGNED = 0x00000008;
        //private const int COMIMAGE_FLAGS_NATIVE_ENTRYPOINT = 0x00000010;
        //private const int COMIMAGE_FLAGS_TRACKDEBUGDATA = 0x00010000;
        private const int COMIMAGE_FLAGS_32BITPREFERRED = 0x00020000;
    }
    [Flags]
    public enum PeTypePlatform
    {
        AnyCPU = 0x0001,
        ILOnly = 0x0002,
        Native = 0x0004,
        Mixing = 0x0008,

        Unknow = 0x0000,
        BitMask = 0x00FF,
        BitMastDotNet = 0x0007,
    }
    [Flags]
    public enum PeTypeBitness
    {
        X64 = 0x0100,
        X86 = 0x0200,

        NoBit = 0x0000,
        BitMask = 0x0F00,
    }
    [Flags]
    public enum PeTypeExt
    {
        Exe = 0x1000,
        Dll = 0x2000,
        Drv = 0x3000,

        NoExt = 0x0000,
        BitMask = 0xF000,
    }
    [Flags]
    public enum PeTypeSubSystem
    {
        //DeviceDrv = 0x1_0000,
        WindowsGui = 0x2_0000,
        ConsoleCui = 0x3_0000,
        //Win9xDrv = 0x8_0000,

        Unknow = 0x0_0000,
        BitMask = 0xF_0000,
    }
    [Flags]
    public enum PeType
    {
        AnyCPU32BitExeWindowsGui = PeTypePlatform.AnyCPU | PeTypeBitness.X86 | PeTypeExt.Exe | PeTypeSubSystem.WindowsGui,
        AnyCPU64BitExeWindowsGui = PeTypePlatform.AnyCPU | PeTypeBitness.X64 | PeTypeExt.Exe | PeTypeSubSystem.WindowsGui,
        ILOnly32BitExeWindowsGui = PeTypePlatform.ILOnly | PeTypeBitness.X86 | PeTypeExt.Exe | PeTypeSubSystem.WindowsGui,
        ILOnly64BitExeWindowsGui = PeTypePlatform.ILOnly | PeTypeBitness.X64 | PeTypeExt.Exe | PeTypeSubSystem.WindowsGui,
        Native32BitExeWindowsGui = PeTypePlatform.Native | PeTypeBitness.X86 | PeTypeExt.Exe | PeTypeSubSystem.WindowsGui,
        Native64BitExeWindowsGui = PeTypePlatform.Native | PeTypeBitness.X64 | PeTypeExt.Exe | PeTypeSubSystem.WindowsGui,
        Mixing32BitExeWindowsGui = PeTypePlatform.Mixing | PeTypeBitness.X86 | PeTypeExt.Exe | PeTypeSubSystem.WindowsGui,
        Mixing64BitExeWindowsGui = PeTypePlatform.Mixing | PeTypeBitness.X64 | PeTypeExt.Exe | PeTypeSubSystem.WindowsGui,

        AnyCPU32BitExeConsoleCui = PeTypePlatform.AnyCPU | PeTypeBitness.X86 | PeTypeExt.Exe | PeTypeSubSystem.ConsoleCui,
        AnyCPU64BitExeConsoleCui = PeTypePlatform.AnyCPU | PeTypeBitness.X64 | PeTypeExt.Exe | PeTypeSubSystem.ConsoleCui,
        ILOnly32BitExeConsoleCui = PeTypePlatform.ILOnly | PeTypeBitness.X86 | PeTypeExt.Exe | PeTypeSubSystem.ConsoleCui,
        ILOnly64BitExeConsoleCui = PeTypePlatform.ILOnly | PeTypeBitness.X64 | PeTypeExt.Exe | PeTypeSubSystem.ConsoleCui,
        Native32BitExeConsoleCui = PeTypePlatform.Native | PeTypeBitness.X86 | PeTypeExt.Exe | PeTypeSubSystem.ConsoleCui,
        Native64BitExeConsoleCui = PeTypePlatform.Native | PeTypeBitness.X64 | PeTypeExt.Exe | PeTypeSubSystem.ConsoleCui,
        Mixing32BitExeConsoleCui = PeTypePlatform.Mixing | PeTypeBitness.X86 | PeTypeExt.Exe | PeTypeSubSystem.ConsoleCui,
        Mixing64BitExeConsoleCui = PeTypePlatform.Mixing | PeTypeBitness.X64 | PeTypeExt.Exe | PeTypeSubSystem.ConsoleCui,

        AnyCPU32BitExe = PeTypePlatform.AnyCPU | PeTypeBitness.X86 | PeTypeExt.Exe,
        AnyCPU64BitExe = PeTypePlatform.AnyCPU | PeTypeBitness.X64 | PeTypeExt.Exe,
        ILOnly32BitExe = PeTypePlatform.ILOnly | PeTypeBitness.X86 | PeTypeExt.Exe,
        ILOnly64BitExe = PeTypePlatform.ILOnly | PeTypeBitness.X64 | PeTypeExt.Exe,
        Native32BitExe = PeTypePlatform.Native | PeTypeBitness.X86 | PeTypeExt.Exe,
        Native64BitExe = PeTypePlatform.Native | PeTypeBitness.X64 | PeTypeExt.Exe,
        Mixing32BitExe = PeTypePlatform.Mixing | PeTypeBitness.X86 | PeTypeExt.Exe,
        Mixing64BitExe = PeTypePlatform.Mixing | PeTypeBitness.X64 | PeTypeExt.Exe,

        AnyCPU32BitDll = PeTypePlatform.AnyCPU | PeTypeBitness.X86 | PeTypeExt.Dll,
        AnyCPU64BitDll = PeTypePlatform.AnyCPU | PeTypeBitness.X64 | PeTypeExt.Dll,
        ILOnly32BitDll = PeTypePlatform.ILOnly | PeTypeBitness.X86 | PeTypeExt.Dll,
        ILOnly64BitDll = PeTypePlatform.ILOnly | PeTypeBitness.X64 | PeTypeExt.Dll,
        Native32BitDll = PeTypePlatform.Native | PeTypeBitness.X86 | PeTypeExt.Dll,
        Native64BitDll = PeTypePlatform.Native | PeTypeBitness.X64 | PeTypeExt.Dll,
        Mixing32BitDll = PeTypePlatform.Mixing | PeTypeBitness.X86 | PeTypeExt.Dll,
        Mixing64BitDll = PeTypePlatform.Mixing | PeTypeBitness.X64 | PeTypeExt.Dll,

        AnyCPU32BitDrv = PeTypePlatform.AnyCPU | PeTypeBitness.X86 | PeTypeExt.Drv,
        AnyCPU64BitDrv = PeTypePlatform.AnyCPU | PeTypeBitness.X64 | PeTypeExt.Drv,
        ILOnly32BitDrv = PeTypePlatform.ILOnly | PeTypeBitness.X86 | PeTypeExt.Drv,
        ILOnly64BitDrv = PeTypePlatform.ILOnly | PeTypeBitness.X64 | PeTypeExt.Drv,
        Native32BitDrv = PeTypePlatform.Native | PeTypeBitness.X86 | PeTypeExt.Drv,
        Native64BitDrv = PeTypePlatform.Native | PeTypeBitness.X64 | PeTypeExt.Drv,
        Mixing32BitDrv = PeTypePlatform.Mixing | PeTypeBitness.X86 | PeTypeExt.Drv,
        Mixing64BitDrv = PeTypePlatform.Mixing | PeTypeBitness.X64 | PeTypeExt.Drv,

        MsDosExecutable,
        Windows16BitExecutable,
        Windows16BitVirtualDeviceDriver,

        Unknow = PeTypePlatform.Unknow | PeTypeBitness.NoBit | PeTypeExt.NoExt,

        ErrorOccurred = int.MinValue,
        NotExecutable,
        OptionalHeaderMagicNot3264,
        OptionalHeaderMagicExceedFileLength,
        OptionalHeader32ExceedFileLength,
        OptionalHeader64ExceedFileLength,
        SectionHeaderExceedFileLength,
        Cor20HeaderExceedFileLength,
    }
}

 

编辑:计算机教程 本文来源:读文件头数据判断 PE 文件格式和类型

关键词: