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, } }