Parent Directory
|
Revision Log
|
Patch
--- trunk/Win32/Sojaner.MemoryScanner/PEReader.cs 2012/06/05 10:27:16 293 +++ trunk/Win32/Sojaner.MemoryScanner/PEReader.cs 2012/06/05 18:39:06 319 @@ -1,4 +1,5 @@ -using System; +#define ENABLE_LOGGING +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,611 +7,523 @@ using RomCheater.Logging; using System.Runtime.InteropServices; using System.Diagnostics; +using System.ComponentModel; namespace Sojaner.MemoryScanner { public class PEReader { - public PEReader(FileInfo fi) : this(fi.FullName) { } - public PEReader(string filename) + // Code (C) Sergey utilized from: http://www.sergeyakopov.com/2010/11/03/reading-pe-format-using-data-marshalling-in-net/ + #region Structs + + [Flags] + public enum MachineTypeFlags { - Exception ErrorInfo = null; - try - { - this.Read(filename, out ErrorInfo); - } - catch (Exception ex) - { - logger.Error.WriteLine("PEReader: Failed to read process: {0}", filename); - if (ErrorInfo != null) - { - //logger.Error.WriteLine(ErrorInfo.GetBaseException().ToString()); - throw ErrorInfo; - } - else - { - //logger.Error.WriteLine(ex.GetBaseException().ToString()); - throw ex; - } - } + x86 = 0x14C, + Alpha = 0x184, + ARM = 0x1C0, + MIPS16R3000 = 0x162, + MIPS16R4000 = 0x166, + MIPS16R10000 = 0x168, + PowerPCLE = 0x1F0, + PowerPCBE = 0x1F2, + Itanium = 0x200, + MIPS16 = 0x266, + Alpha64 = 0x284, + MIPSFPU = 0x366, + MIPSFPU16 = 0x466, + x64 = 0x8664, } - #region marshalling - private void Read(string filename, out Exception ErrorInfo) + [TypeConverter(typeof(ExpandableObjectConverter))] + [StructLayout(LayoutKind.Sequential)] + public struct IMAGE_DOS_HEADER { - ErrorInfo = null; - try - { - logger.Debug.WriteLine("Reading Exe: {0}", filename); + public UInt16 _e_magic; + public UInt16 _e_cblp; + public UInt16 _e_cp; + public UInt16 _e_crlc; + public UInt16 _e_cparhdr; + public UInt16 _e_minalloc; + public UInt16 _e_maxalloc; + public UInt16 _e_ss; + public UInt16 _e_sp; + public UInt16 _e_csum; + public UInt16 _e_ip; + public UInt16 _e_cs; + public UInt16 _e_lfarlc; + public UInt16 _e_ovno; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public UInt16[] _e_res1; + public UInt16 _e_oemid; + public UInt16 _e_oeminfo; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public UInt16[] _e_res2; + public UInt32 _e_lfanew; - using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - try - { - byte[] data = new byte[] { }; - GCHandle pinnedPacket = new GCHandle(); - int size = 0; - BinaryReader br = new BinaryReader(fs); - - #region IMAGE_DOS_HEADER - size = Marshal.SizeOf(typeof(IMAGE_DOS_HEADER)); - data = br.ReadBytes(size); - pinnedPacket = GCHandle.Alloc(data, GCHandleType.Pinned); - IMAGE_DOS_HEADER DOS_HEADER = (IMAGE_DOS_HEADER)Marshal.PtrToStructure(pinnedPacket.AddrOfPinnedObject(), typeof(IMAGE_DOS_HEADER)); - pinnedPacket.Free(); - #endregion - - // skip the old dos stub - br.BaseStream.Seek(DOS_HEADER.e_lfanew, SeekOrigin.Begin); - - #region IMAGE_NT_HEADERS - size = Marshal.SizeOf(typeof(IMAGE_NT_HEADERS)); - data = br.ReadBytes(size); - pinnedPacket = GCHandle.Alloc(data, GCHandleType.Pinned); - IMAGE_NT_HEADERS NT_HEADER = (IMAGE_NT_HEADERS)Marshal.PtrToStructure(pinnedPacket.AddrOfPinnedObject(), typeof(IMAGE_NT_HEADERS)); - pinnedPacket.Free(); - #endregion - - StringBuilder section_header_string_builder = new StringBuilder(); - List<IMAGE_SECTION_HEADER> section_headers = new List<IMAGE_SECTION_HEADER>(); - section_header_string_builder.AppendFormat("Section headers:{0}", System.Environment.NewLine); - for (int i = 0; i < NT_HEADER.FileHeader.NumberOfSections; i++) - { - size = Marshal.SizeOf(typeof(IMAGE_SECTION_HEADER)); - data = br.ReadBytes(size); - pinnedPacket = GCHandle.Alloc(data, GCHandleType.Pinned); - IMAGE_SECTION_HEADER SECTION_HEADER = (IMAGE_SECTION_HEADER)Marshal.PtrToStructure(pinnedPacket.AddrOfPinnedObject(), typeof(IMAGE_SECTION_HEADER)); - section_headers.Add(SECTION_HEADER); - pinnedPacket.Free(); - section_header_string_builder.AppendFormat("Section Header: {0}{1}", new string(SECTION_HEADER.Name).Replace("\0",""), System.Environment.NewLine); - - } - logger.VerboseDebug.WriteLine(section_header_string_builder.ToString()); - br.Close(); - } - catch (Exception ex) - { - ErrorInfo = ex; - } - } - } - catch (Exception ex) + public string e_magic { get { return string.Format("0x{0:x4}", _e_magic); } } + public string e_cblp { get { return string.Format("0x{0:x4}", _e_cblp); } } + public string e_cp { get { return string.Format("0x{0:x4}", _e_cp); } } + public string e_crlc { get { return string.Format("0x{0:x4}", _e_crlc); } } + public string e_cparhdr { get { return string.Format("0x{0:x4}", _e_cparhdr); } } + public string e_minalloc { get { return string.Format("0x{0:x4}", _e_minalloc); } } + public string e_maxalloc { get { return string.Format("0x{0:x4}", _e_maxalloc); } } + public string e_ss { get { return string.Format("0x{0:x4}", _e_ss); } } + public string e_sp { get { return string.Format("0x{0:x4}", _e_sp); } } + public string e_csum { get { return string.Format("0x{0:x4}", _e_csum); } } + public string e_ip { get { return string.Format("0x{0:x4}", _e_ip); } } + public string e_cs { get { return string.Format("0x{0:x4}", _e_cs); } } + public string e_lfarlc { get { return string.Format("0x{0:x4}", _e_lfarlc); } } + public string e_ovno { get { return string.Format("0x{0:x4}", _e_ovno); } } + public ushort[] e_res1 { get { return _e_res1; } } + public string e_oemid { get { return string.Format("0x{0:x4}", _e_oemid); } } + public string e_oeminfo { get { return string.Format("0x{0:x4}", _e_oeminfo); } } + public ushort[] e_res2 { get { return _e_res2; } } + public string e_lfanew { get { return string.Format("0x{0:x8}", _e_lfanew); } } + + public override string ToString() { - ErrorInfo = ex; + return Encoding.UTF8.GetString(BitConverter.GetBytes(_e_magic)); } } - #endregion - - #region header support - #region IMAGE_DATA_DIRECTORY + [TypeConverter(typeof(ExpandableObjectConverter))] [StructLayout(LayoutKind.Sequential)] - public struct IMAGE_DATA_DIRECTORY + public struct IMAGE_NT_HEADERS { - public UInt32 VirtualAddress; - public UInt32 Size; - public bool HasAddress { get { return (VirtualAddress != 0); } } - public bool HasSize { get { return (Size > 0); } } + public UInt32 _Signature; + public IMAGE_FILE_HEADER _FileHeader; + public IMAGE_OPTIONAL_HEADER32 _OptionalHeader32; + public IMAGE_OPTIONAL_HEADER64 _OptionalHeader64; + + public string Signature { get { return string.Format("0x{0:x8}", _Signature); } } + public IMAGE_FILE_HEADER FileHeader { get { return _FileHeader; } } + public IMAGE_OPTIONAL_HEADER32 OptionalHeader32 { get { return _OptionalHeader32;} } + public IMAGE_OPTIONAL_HEADER64 OptionalHeader64 { get { return _OptionalHeader64;} } + + public override string ToString() + { + return Encoding.UTF8.GetString(BitConverter.GetBytes(_Signature)); + } } - #endregion - #region IMAGE_FILE_HEADER + [TypeConverter(typeof(ExpandableObjectConverter))] [StructLayout(LayoutKind.Sequential)] public struct IMAGE_FILE_HEADER { - public MachineType Machine; - public UInt16 NumberOfSections; - public UInt32 TimeDateStamp; - public UInt32 PointerToSymbolTable; - public UInt32 NumberOfSymbols; - public UInt16 SizeOfOptionalHeader; - public DllCharacteristicsType Characteristics; - } - #endregion - #region IMAGE_DOS_HEADER - [StructLayout(LayoutKind.Sequential)] - public struct IMAGE_DOS_HEADER - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public char[] e_magic; // Magic number - public UInt16 e_cblp; // Bytes on last page of file - public UInt16 e_cp; // Pages in file - public UInt16 e_crlc; // Relocations - public UInt16 e_cparhdr; // Size of header in paragraphs - public UInt16 e_minalloc; // Minimum extra paragraphs needed - public UInt16 e_maxalloc; // Maximum extra paragraphs needed - public UInt16 e_ss; // Initial (relative) SS value - public UInt16 e_sp; // Initial SP value - public UInt16 e_csum; // Checksum - public UInt16 e_ip; // Initial IP value - public UInt16 e_cs; // Initial (relative) CS value - public UInt16 e_lfarlc; // File address of relocation table - public UInt16 e_ovno; // Overlay number - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public UInt16[] e_res1; // Reserved words - public UInt16 e_oemid; // OEM identifier (for e_oeminfo) - public UInt16 e_oeminfo; // OEM information; e_oemid specific - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] - public UInt16[] e_res2; // Reserved words - public Int32 e_lfanew; // File address of new exe header - private string _e_magic + public UInt16 _MachineType; + public UInt16 _NumberOfSections; + public UInt32 _TimeDateStamp; + public UInt32 _PointerToSymbolTable; + public UInt32 _NumberOfSymbols; + public UInt16 _SizeOfOptionalHeader; + public UInt16 _Characteristics; + + + public string MachineType { get { return ((MachineTypeFlags)_MachineType).ToString(); } } + public string NumberOfSections { get { return string.Format("0x{0:x4}", _NumberOfSections); } } + public string TimeDateStamp { get { return string.Format("{0} (0x{1:x8})", GetDateTimeFromDosDateTime(_TimeDateStamp).ToString(), _TimeDateStamp); } } + public string PointerToSymbolTable { get { return string.Format("0x{0:x8}", _PointerToSymbolTable); } } + public string NumberOfSymbols { get { return string.Format("0x{0:x8}", _NumberOfSymbols); } } + public string SizeOfOptionalHeader { get { return string.Format("0x{0:x4}", _SizeOfOptionalHeader); } } + public string Characteristics { get { return string.Format("0x{0:x4}", _Characteristics); } } + public override string ToString() { - get { return new string(e_magic); } + return MachineType; } - public bool isValid - { - get { return _e_magic == "MZ"; } - } - } - #endregion - #region IMAGE_NT_HEADERS - [StructLayout(LayoutKind.Explicit)] - public struct IMAGE_NT_HEADERS - { - [FieldOffset(0)] - public uint Signature; - [FieldOffset(4)] - public IMAGE_FILE_HEADER FileHeader; - [FieldOffset(24)] - public IMAGE_OPTIONAL_HEADER OptionalHeader; - private string _Signature + private DateTime GetDateTimeFromDosDateTime(UInt32 i32TimeDate) { - get { return Encoding.ASCII.GetString(BitConverter.GetBytes(Signature)); } + UInt16 i16Time = (UInt16)(i32TimeDate & 0xFFFF); + UInt16 i16Date = (UInt16)((i32TimeDate & 0xFFFF0000) >> 16); + return GetDateTimeFromDosDateTime(i16Time, i16Date); } - - public bool isValid + private DateTime GetDateTimeFromDosDateTime(UInt16 i16Time, UInt16 i16Date) { - get { return _Signature == "PE\0\0" && (OptionalHeader.Magic == MagicType.IMAGE_NT_OPTIONAL_HDR32_MAGIC || OptionalHeader.Magic == MagicType.IMAGE_NT_OPTIONAL_HDR64_MAGIC); } + int iYear = 0; + int iMonth = 1; + int iDay = 1; + int iHour = 0; + int iMinute = 0; + int iSecond = 0; + iDay = (i16Date & 0x1F); + iMonth = ((i16Date & 0x01E0) >> 5); + iYear = 1980 + ((i16Date & 0xFE00) >> 9); + iSecond = (i16Time & 0x1F) * 2; + iMinute = ((i16Time & 0x07E0) >> 5); + iHour = ((i16Time & 0x0F800) >> 11); + return new DateTime(iYear, iMonth, iDay, iHour, iMinute, iSecond); + } + } - #endregion - #region MachineType - public enum MachineType : ushort + [TypeConverter(typeof(ExpandableObjectConverter))] + [StructLayout(LayoutKind.Sequential)] + public struct IMAGE_OPTIONAL_HEADER32 { - Native = 0, - I386 = 0x014c, - Itanium = 0x0200, - x64 = 0x8664 + public UInt16 Magic; + public Byte MajorLinkerVersion; + public Byte MinorLinkerVersion; + public UInt32 SizeOfCode; + public UInt32 SizeOfInitializedData; + public UInt32 SizeOfUninitializedData; + public UInt32 AddressOfEntryPoint; + public UInt32 BaseOfCode; + public UInt32 BaseOfData; + public UInt32 ImageBase; + public UInt32 SectionAlignment; + public UInt32 FileAlignment; + public UInt16 MajorOperatingSystemVersion; + public UInt16 MinorOperatingSystemVersion; + public UInt16 MajorImageVersion; + public UInt16 MinorImageVersion; + public UInt16 MajorSubsystemVersion; + public UInt16 MinorSubsystemVersion; + public UInt32 Win32VersionValue; + public UInt32 SizeOfImage; + public UInt32 SizeOfHeaders; + public UInt32 CheckSum; + public UInt16 Subsystem; + public UInt16 DllCharacteristics; + public UInt32 SizeOfStackReserve; + public UInt32 SizeOfStackCommit; + public UInt32 SizeOfHeapReserve; + public UInt32 SizeOfHeapCommit; + public UInt32 LoaderFlags; + public UInt32 NumberOfRvaAndSizes; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public IMAGE_DATA_DIRECTORY[] DataDirectory; } - #endregion - #region MagicType - public enum MagicType : ushort + [TypeConverter(typeof(ExpandableObjectConverter))] + [StructLayout(LayoutKind.Sequential)] + public struct IMAGE_OPTIONAL_HEADER64 { - IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b, - IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b + public UInt16 Magic; + public Byte MajorLinkerVersion; + public Byte MinorLinkerVersion; + public UInt32 SizeOfCode; + public UInt32 SizeOfInitializedData; + public UInt32 SizeOfUninitializedData; + public UInt32 AddressOfEntryPoint; + public UInt32 BaseOfCode; + public UInt64 ImageBase; + public UInt32 SectionAlignment; + public UInt32 FileAlignment; + public UInt16 MajorOperatingSystemVersion; + public UInt16 MinorOperatingSystemVersion; + public UInt16 MajorImageVersion; + public UInt16 MinorImageVersion; + public UInt16 MajorSubsystemVersion; + public UInt16 MinorSubsystemVersion; + public UInt32 Win32VersionValue; + public UInt32 SizeOfImage; + public UInt32 SizeOfHeaders; + public UInt32 CheckSum; + public UInt16 Subsystem; + public UInt16 DllCharacteristics; + public UInt64 SizeOfStackReserve; + public UInt64 SizeOfStackCommit; + public UInt64 SizeOfHeapReserve; + public UInt64 SizeOfHeapCommit; + public UInt32 LoaderFlags; + public UInt32 NumberOfRvaAndSizes; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public IMAGE_DATA_DIRECTORY[] DataDirectory; } - #endregion - #region SubSystemType - public enum SubSystemType : ushort + [TypeConverter(typeof(ExpandableObjectConverter))] + [StructLayout(LayoutKind.Sequential)] + public struct IMAGE_DATA_DIRECTORY { - 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 UInt32 VirtualAddress; + public UInt32 Size; } - #endregion - #region DllCharacteristicsType - [Flags] - public enum DllCharacteristicsType : ushort + [TypeConverter(typeof(ExpandableObjectConverter))] + [StructLayout(LayoutKind.Sequential)] + public struct IMAGE_SECTION_HEADER { - 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 + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] + public string _Name; + public Misc _Misc; + public UInt32 _VirtualAddress; + public UInt32 _SizeOfRawData; + public UInt32 _PointerToRawData; + public UInt32 _PointerToRelocations; + public UInt32 _PointerToLinenumbers; + public UInt16 _NumberOfRelocations; + public UInt16 _NumberOfLinenumbers; + public UInt32 _Characteristics; + + public string Name { get { return _Name; } } + public Misc Misc { get { return _Misc; } } + public string VirtualAddress { get { return string.Format("0x{0:x8}", _VirtualAddress); } } + public string SizeOfRawData { get { return string.Format("0x{0:x8}", _SizeOfRawData); } } + public string PointerToRawData { get { return string.Format("0x{0:x8}", _PointerToRawData); } } + public string PointerToRelocations { get { return string.Format("0x{0:x8}", _PointerToRelocations); } } + public string PointerToLinenumbers { get { return string.Format("0x{0:x8}", _PointerToLinenumbers); } } + public string NumberOfRelocations { get { return string.Format("0x{0:x4}", _NumberOfRelocations); } } + public string NumberOfLinenumbers { get { return string.Format("0x{0:x4}", _NumberOfLinenumbers); } } + public string Characteristics { get { return string.Format("0x{0:x8}", _Characteristics); } } + public override string ToString() + { + return Name; + } } - #endregion - #region IMAGE_OPTIONAL_HEADER + [TypeConverter(typeof(ExpandableObjectConverter))] [StructLayout(LayoutKind.Explicit)] - public struct IMAGE_OPTIONAL_HEADER + public struct Misc { [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; + public UInt32 _PhysicalAddress; + [FieldOffset(0)] + public UInt32 _VirtualSize; - [FieldOffset(70)] - public DllCharacteristicsType DllCharacteristics; + public string PhysicalAddress { get { return string.Format("0x{0:x8}", _PhysicalAddress); } } + public string VirtualSize { get { return string.Format("0x{0:x8}", _VirtualSize); } } - [FieldOffset(72)] - public uint SizeOfStackReserve; + } - [FieldOffset(76)] - public uint SizeOfStackCommit; + #endregion - [FieldOffset(80)] - public uint SizeOfHeapReserve; + #region Fields - [FieldOffset(84)] - public uint SizeOfHeapCommit; + private readonly IMAGE_DOS_HEADER _dosHeader; + private IMAGE_NT_HEADERS _ntHeaders; + private readonly IList<IMAGE_SECTION_HEADER> _sectionHeaders = new List<IMAGE_SECTION_HEADER>(); + #endregion - [FieldOffset(88)] - public uint LoaderFlags; + #region logging implementation + private static class log + { + public static class verbose + { + public static class debug + { + public static void writeline(string format, params object[] args) + { +#if ENABLE_LOGGING + logger.VerboseDebug.WriteLine(format, args); +#endif + } + public static void write(string format, params object[] args) + { +#if ENABLE_LOGGING + logger.VerboseDebug.Write(format, args); +#endif + } + } + public static class error + { + public static void writeline(string format, params object[] args) + { +#if ENABLE_LOGGING + logger.VerboseError.WriteLine(format, args); +#endif + } + public static void write(string format, params object[] args) + { +#if ENABLE_LOGGING + logger.VerboseError.Write(format, args); +#endif + } + } + } + } + #endregion - [FieldOffset(92)] - public uint NumberOfRvaAndSizes; - [FieldOffset(96)] - public IMAGE_DATA_DIRECTORY ExportTable; + public PEData GetData + { + get + { + PEData _data = new PEData(_dosHeader, _ntHeaders, _sectionHeaders.ToArray()); + return _data; + } + } + #region t + public class PEData + { + public PEData() : this(new IMAGE_DOS_HEADER(), new IMAGE_NT_HEADERS(), new IMAGE_SECTION_HEADER[] { }) { } + public PEData(IMAGE_DOS_HEADER DosHeader, IMAGE_NT_HEADERS NTHeader, IMAGE_SECTION_HEADER[] SectionHeaders) + { + this.DosHeader = DosHeader; + this.NTHeader = NTHeader; + this.SectionHeaders = SectionHeaders; + } + public IMAGE_DOS_HEADER DosHeader { get; private set; } + public IMAGE_NT_HEADERS NTHeader { get; private set; } + public IMAGE_SECTION_HEADER[] SectionHeaders { get; private set; } + } - [FieldOffset(104)] - public IMAGE_DATA_DIRECTORY ImportTable; + #endregion - [FieldOffset(112)] - public IMAGE_DATA_DIRECTORY ResourceTable; + public PEReader(FileInfo fi) : this(fi.FullName) { } + public PEReader(string filename) + { + Exception ErrorInfo = null; + using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) + { + try + { + log.verbose.debug.writeline("Reading PE Format from: {0}", filename); + BinaryReader reader = new BinaryReader(fs); + // Reset reader position, just in case + reader.BaseStream.Seek(0, SeekOrigin.Begin); + + // Read MS-DOS header section + _dosHeader = MarshalBytesTo<IMAGE_DOS_HEADER>(reader); + // MS-DOS magic number should read 'MZ' + if (_dosHeader._e_magic != 0x5a4d) + { + throw new InvalidOperationException("File is not a portable executable."); + } - [FieldOffset(120)] - public IMAGE_DATA_DIRECTORY ExceptionTable; + // Skip MS-DOS stub and seek reader to NT Headers + reader.BaseStream.Seek(_dosHeader._e_lfanew, SeekOrigin.Begin); - [FieldOffset(128)] - public IMAGE_DATA_DIRECTORY CertificateTable; + // Read NT Headers + _ntHeaders._Signature = MarshalBytesTo<UInt32>(reader); - [FieldOffset(136)] - public IMAGE_DATA_DIRECTORY BaseRelocationTable; + // Make sure we have 'PE' in the pe signature + if (_ntHeaders._Signature != 0x4550) + { + throw new InvalidOperationException("Invalid portable executable signature in NT header."); + } - [FieldOffset(144)] - public IMAGE_DATA_DIRECTORY Debug; + _ntHeaders._FileHeader = MarshalBytesTo<IMAGE_FILE_HEADER>(reader); + // Read optional headers + if (Is32bitAssembly()) + { + log.verbose.debug.writeline("\tDetected a 32Bit PE Executable"); + Load32bitOptionalHeaders(reader); + } + else + { + log.verbose.debug.writeline("\tDetected a 64Bit PE Executable"); + Load64bitOptionalHeaders(reader); + } - [FieldOffset(152)] - public IMAGE_DATA_DIRECTORY Architecture; + // Read section data + log.verbose.debug.writeline("\tTotal Section Headers: {0}", _sectionHeaders.Count); + foreach (IMAGE_SECTION_HEADER header in _sectionHeaders) + { + int section_index = _sectionHeaders.IndexOf(header) + 1; + log.verbose.debug.writeline("\tSection Header: {0} of {1}", section_index, _sectionHeaders.Count); + log.verbose.debug.writeline("\t\tName: {0}", header.Name); + log.verbose.debug.writeline("\t\tVirtual Address: 0x{0:x8}", header.VirtualAddress); + log.verbose.debug.writeline("\t\tPhysical Address: 0x{0:x8}", header.Misc.PhysicalAddress); + log.verbose.debug.writeline("\t\tVirtual Size: 0x{0:x8}", header.Misc.VirtualSize); + log.verbose.debug.writeline("\t\tRaw Data Size: 0x{0:x8}", header.SizeOfRawData); + log.verbose.debug.writeline("\t\tPointer To Raw Data: 0x{0:x8}", header.PointerToRawData); - [FieldOffset(160)] - public IMAGE_DATA_DIRECTORY GlobalPtr; + // Skip to beginning of a section + reader.BaseStream.Seek(header._PointerToRawData, SeekOrigin.Begin); - [FieldOffset(168)] - public IMAGE_DATA_DIRECTORY TLSTable; + // Read section data... and do something with it + byte[] sectiondata = reader.ReadBytes((int)header._SizeOfRawData); + } + reader.Close(); + } + catch (Exception ex) + { + ErrorInfo = ex; + throw ErrorInfo; + } + } + if (ErrorInfo != null) + { + log.verbose.error.writeline("Error Reading PE Format from: {0}", filename); + log.verbose.error.writeline(ErrorInfo.ToString()); + } + } - [FieldOffset(176)] - public IMAGE_DATA_DIRECTORY LoadConfigTable; + public IMAGE_DOS_HEADER GetDOSHeader() + { + return _dosHeader; + } - [FieldOffset(184)] - public IMAGE_DATA_DIRECTORY BoundImport; + public UInt32 GetPESignature() + { + return _ntHeaders._Signature; + } - [FieldOffset(192)] - public IMAGE_DATA_DIRECTORY IAT; + public IMAGE_FILE_HEADER GetFileHeader() + { + return _ntHeaders.FileHeader; + } - [FieldOffset(200)] - public IMAGE_DATA_DIRECTORY DelayImportDescriptor; + public IMAGE_OPTIONAL_HEADER32 GetOptionalHeaders32() + { + return _ntHeaders.OptionalHeader32; + } - [FieldOffset(208)] - public IMAGE_DATA_DIRECTORY CLRRuntimeHeader; + public IMAGE_OPTIONAL_HEADER64 GetOptionalHeaders64() + { + return _ntHeaders.OptionalHeader64; + } - [FieldOffset(216)] - public IMAGE_DATA_DIRECTORY Reserved; + public IList<IMAGE_SECTION_HEADER> GetSectionHeaders() + { + return _sectionHeaders; } - #endregion - #region IMAGE_EXPORT_DIRECTORY - [StructLayout(LayoutKind.Sequential)] - public struct IMAGE_EXPORT_DIRECTORY + + public bool Is32bitAssembly() { - public UInt32 Characteristics; - public UInt32 TimeDateStamp; - public UInt16 MajorVersion; - public UInt16 MinorVersion; - public UInt32 Name; - public UInt32 Base; - public UInt32 NumberOfFunctions; - public UInt32 NumberOfNames; - public UInt32 AddressOfFunctions; // RVA from base of image - public UInt32 AddressOfNames; // RVA from base of image - public UInt32 AddressOfNameOrdinals; // RVA from base of image + return ((_ntHeaders.FileHeader._Characteristics & 0x0100) == 0x0100); } - #endregion - #endregion - #region IMAGE_SECTION_HEADER - [StructLayout(LayoutKind.Explicit)] - public struct IMAGE_SECTION_HEADER + + private void Load64bitOptionalHeaders(BinaryReader reader) { - [FieldOffset(0)] - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public char[] Name; + _ntHeaders._OptionalHeader64 = MarshalBytesTo<IMAGE_OPTIONAL_HEADER64>(reader); - [FieldOffset(8)] - public UInt32 VirtualSize; + // Should have 10 data directories + if (_ntHeaders.OptionalHeader64.NumberOfRvaAndSizes != 0x10) + { + throw new InvalidOperationException("Invalid number of data directories in NT header"); + } - [FieldOffset(12)] - public UInt32 VirtualAddress; + // Scan data directories and load section headers + for (int i = 0; i < _ntHeaders.OptionalHeader64.NumberOfRvaAndSizes; i++) + { + if (_ntHeaders.OptionalHeader64.DataDirectory[i].Size > 0) + { + _sectionHeaders.Add(MarshalBytesTo<IMAGE_SECTION_HEADER>(reader)); + } + } + } - [FieldOffset(16)] - public UInt32 SizeOfRawData; + private void Load32bitOptionalHeaders(BinaryReader reader) + { + _ntHeaders._OptionalHeader32 = MarshalBytesTo<IMAGE_OPTIONAL_HEADER32>(reader); - [FieldOffset(20)] - public UInt32 PointerToRawData; + // Should have 10 data directories + if (_ntHeaders.OptionalHeader32.NumberOfRvaAndSizes != 0x10) + { + throw new InvalidOperationException("Invalid number of data directories in NT header"); + } - [FieldOffset(24)] - public UInt32 PointerToRelocations; + // Scan data directories and load section headers + for (int i = 0; i < _ntHeaders.OptionalHeader32.NumberOfRvaAndSizes; i++) + { + if (_ntHeaders.OptionalHeader32.DataDirectory[i].Size > 0) + { + _sectionHeaders.Add(MarshalBytesTo<IMAGE_SECTION_HEADER>(reader)); + } + } + } - [FieldOffset(28)] - public UInt32 PointerToLinenumbers; + private static T MarshalBytesTo<T>(BinaryReader reader) + { + // Unmanaged data + byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T))); - [FieldOffset(32)] - public UInt16 NumberOfRelocations; + // Create a pointer to the unmanaged data pinned in memory to be accessed by unmanaged code + GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); - [FieldOffset(34)] - public UInt16 NumberOfLinenumbers; + // Use our previously created pointer to unmanaged data and marshal to the specified type + T theStructure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); - [FieldOffset(36)] - public DataSectionFlags Characteristics; + // Deallocate pointer + handle.Free(); - public string Section - { - get { return new string(Name); } - } + return theStructure; } - #endregion - #region DataSectionFlags - [Flags] - public enum DataSectionFlags : uint - { - /// <summary> - /// Reserved for future use. - /// </summary> - TypeReg = 0x00000000, - /// <summary> - /// Reserved for future use. - /// </summary> - TypeDsect = 0x00000001, - /// <summary> - /// Reserved for future use. - /// </summary> - TypeNoLoad = 0x00000002, - /// <summary> - /// Reserved for future use. - /// </summary> - TypeGroup = 0x00000004, - /// <summary> - /// The section should not be padded to the next boundary. This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES. This is valid only for object files. - /// </summary> - TypeNoPadded = 0x00000008, - /// <summary> - /// Reserved for future use. - /// </summary> - TypeCopy = 0x00000010, - /// <summary> - /// The section contains executable code. - /// </summary> - ContentCode = 0x00000020, - /// <summary> - /// The section contains initialized data. - /// </summary> - ContentInitializedData = 0x00000040, - /// <summary> - /// The section contains uninitialized data. - /// </summary> - ContentUninitializedData = 0x00000080, - /// <summary> - /// Reserved for future use. - /// </summary> - LinkOther = 0x00000100, - /// <summary> - /// The section contains comments or other information. The .drectve section has this type. This is valid for object files only. - /// </summary> - LinkInfo = 0x00000200, - /// <summary> - /// Reserved for future use. - /// </summary> - TypeOver = 0x00000400, - /// <summary> - /// The section will not become part of the image. This is valid only for object files. - /// </summary> - LinkRemove = 0x00000800, - /// <summary> - /// The section contains COMDAT data. For more information, see section 5.5.6, COMDAT Sections (Object Only). This is valid only for object files. - /// </summary> - LinkComDat = 0x00001000, - /// <summary> - /// Reset speculative exceptions handling bits in the TLB entries for this section. - /// </summary> - NoDeferSpecExceptions = 0x00004000, - /// <summary> - /// The section contains data referenced through the global pointer (GP). - /// </summary> - RelativeGP = 0x00008000, - /// <summary> - /// Reserved for future use. - /// </summary> - MemPurgeable = 0x00020000, - /// <summary> - /// Reserved for future use. - /// </summary> - Memory16Bit = 0x00020000, - /// <summary> - /// Reserved for future use. - /// </summary> - MemoryLocked = 0x00040000, - /// <summary> - /// Reserved for future use. - /// </summary> - MemoryPreload = 0x00080000, - /// <summary> - /// Align data on a 1-byte boundary. Valid only for object files. - /// </summary> - Align1Bytes = 0x00100000, - /// <summary> - /// Align data on a 2-byte boundary. Valid only for object files. - /// </summary> - Align2Bytes = 0x00200000, - /// <summary> - /// Align data on a 4-byte boundary. Valid only for object files. - /// </summary> - Align4Bytes = 0x00300000, - /// <summary> - /// Align data on an 8-byte boundary. Valid only for object files. - /// </summary> - Align8Bytes = 0x00400000, - /// <summary> - /// Align data on a 16-byte boundary. Valid only for object files. - /// </summary> - Align16Bytes = 0x00500000, - /// <summary> - /// Align data on a 32-byte boundary. Valid only for object files. - /// </summary> - Align32Bytes = 0x00600000, - /// <summary> - /// Align data on a 64-byte boundary. Valid only for object files. - /// </summary> - Align64Bytes = 0x00700000, - /// <summary> - /// Align data on a 128-byte boundary. Valid only for object files. - /// </summary> - Align128Bytes = 0x00800000, - /// <summary> - /// Align data on a 256-byte boundary. Valid only for object files. - /// </summary> - Align256Bytes = 0x00900000, - /// <summary> - /// Align data on a 512-byte boundary. Valid only for object files. - /// </summary> - Align512Bytes = 0x00A00000, - /// <summary> - /// Align data on a 1024-byte boundary. Valid only for object files. - /// </summary> - Align1024Bytes = 0x00B00000, - /// <summary> - /// Align data on a 2048-byte boundary. Valid only for object files. - /// </summary> - Align2048Bytes = 0x00C00000, - /// <summary> - /// Align data on a 4096-byte boundary. Valid only for object files. - /// </summary> - Align4096Bytes = 0x00D00000, - /// <summary> - /// Align data on an 8192-byte boundary. Valid only for object files. - /// </summary> - Align8192Bytes = 0x00E00000, - /// <summary> - /// The section contains extended relocations. - /// </summary> - LinkExtendedRelocationOverflow = 0x01000000, - /// <summary> - /// The section can be discarded as needed. - /// </summary> - MemoryDiscardable = 0x02000000, - /// <summary> - /// The section cannot be cached. - /// </summary> - MemoryNotCached = 0x04000000, - /// <summary> - /// The section is not pageable. - /// </summary> - MemoryNotPaged = 0x08000000, - /// <summary> - /// The section can be shared in memory. - /// </summary> - MemoryShared = 0x10000000, - /// <summary> - /// The section can be executed as code. - /// </summary> - MemoryExecute = 0x20000000, - /// <summary> - /// The section can be read. - /// </summary> - MemoryRead = 0x40000000, - /// <summary> - /// The section can be written to. - /// </summary> - MemoryWrite = 0x80000000 - } - #endregion } }
ViewVC Help | |
Powered by ViewVC 1.1.22 |