diff --git a/exeinfo/NE.cs b/exeinfo/NE.cs deleted file mode 100644 index 7321fc0..0000000 --- a/exeinfo/NE.cs +++ /dev/null @@ -1,403 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using System.IO; -using System.Collections.Generic; -using System.Text; - -namespace exeinfo -{ - public static class NE - { - public const ushort Signature = 0x454E; - - //[StructLayout(LayoutKind.Sequential, Pack = 2)] - public struct Header - { - public ushort signature; - public byte linker_major; - public byte linker_minor; - public ushort entry_table_offset; - public ushort entry_table_length; - public uint crc; - public ProgramFlags program_flags; - public ApplicationFlags application_flags; - public byte auto_data_segment_index; - public ushort initial_heap; - public ushort initial_stack; - public uint entry_point; - public uint stack_pointer; - public ushort segment_count; - public ushort reference_count; - public ushort nonresident_table_size; - public ushort segment_table_offset; - public ushort resource_table_offset; - public ushort resident_names_offset; - public ushort module_reference_offset; - public ushort imported_names_offset; - public uint nonresident_names_offset; - public ushort movable_entries; - public ushort alignment_shift; - public ushort resource_entries; - public TargetOS target_os; - public OS2Flags os2_flags; - public ushort return_thunks_offset; - public ushort segment_reference_thunks; - public ushort minimum_swap_area; - public byte os_minor; - public byte os_major; - } - - [Flags] - public enum ProgramFlags : byte - { - NoDGroup = 0, - SingleDGroup = 1, - MultipleDGroup = 2, - GlobalInit = 1 << 2, - ProtectedMode = 1 << 3, - i86 = 1 << 4, - i286 = 1 << 5, - i386 = 1 << 6, - i87 = 1 << 7 - } - - public enum TargetOS : byte - { - Unknown = 0, - OS2 = 1, - Windows = 2, - DOS = 3, - Win32 = 4, - Borland = 5 - } - - [Flags] - public enum ApplicationFlags : byte - { - FullScreen = 1, - GUICompatible = 2, - Errors = 1 << 5, - NonConforming = 1 << 6, - DLL = 1 << 7 - } - - [Flags] - public enum OS2Flags : byte - { - LongFilename = 1 << 0, - ProtectedMode2 = 1 << 1, - ProportionalFonts = 1 << 2, - GangloadArea = 1 << 3, - } - - public struct ResourceTable - { - public ushort alignment_shift; - public ResourceType[] types; - } - - public struct ResourceType - { - public ushort id; - public ushort count; - public uint reserved; - public Resource[] resources; - - // Not sequentially stored - public string name; - } - - public struct Resource - { - public ushort dataOffset; - public ushort length; - public ResourceFlags flags; - public ushort id; - public uint reserved; - - // Not sequentially stored - public string name; - public byte[] data; - } - - [Flags] - public enum ResourceFlags : ushort - { - Moveable = 0x10, - Pure = 0x20, - Preload = 0x40 - } - - public static void PrintInfo(Header header) - { - Console.WriteLine("New Executable (NE):"); - Console.WriteLine("\tFile's CRC: 0x{0:X8}", header.crc); - Console.WriteLine("\tLinker version: {0}.{1}", header.linker_major, header.linker_minor); - if (header.program_flags.HasFlag(ProgramFlags.SingleDGroup) && !header.program_flags.HasFlag(ProgramFlags.MultipleDGroup)) - Console.WriteLine("\tApplication uses a single shared DGroup"); - else if (!header.program_flags.HasFlag(ProgramFlags.SingleDGroup) && header.program_flags.HasFlag(ProgramFlags.MultipleDGroup)) - Console.WriteLine("\tApplication uses a multiple DGroup"); - else if (header.program_flags.HasFlag(ProgramFlags.SingleDGroup) && header.program_flags.HasFlag(ProgramFlags.MultipleDGroup)) - Console.WriteLine("\tApplication indicates an incorrect DGroup value"); - else if (!header.program_flags.HasFlag(ProgramFlags.SingleDGroup) && !header.program_flags.HasFlag(ProgramFlags.MultipleDGroup)) - Console.WriteLine("\tApplication does not use DGroup"); - if (header.program_flags.HasFlag(ProgramFlags.GlobalInit)) - Console.WriteLine("\tApplication uses global initialization"); - if (header.program_flags.HasFlag(ProgramFlags.ProtectedMode)) - Console.WriteLine("\tApplication uses protected mode"); - if (header.program_flags.HasFlag(ProgramFlags.i86)) - Console.WriteLine("\tApplication uses 8086 instructions"); - if (header.program_flags.HasFlag(ProgramFlags.i286)) - Console.WriteLine("\tApplication uses 80286 instructions"); - if (header.program_flags.HasFlag(ProgramFlags.i386)) - Console.WriteLine("\tApplication uses 80386 instructions"); - if (header.program_flags.HasFlag(ProgramFlags.i87)) - Console.WriteLine("\tApplication uses floating point instructions"); - - if(header.target_os == TargetOS.OS2) - { - Console.WriteLine("\tOS/2 application"); - Console.WriteLine("\tApplication requires OS/2 {0}.{1} to run", header.os_major, header.os_minor); - if (header.application_flags.HasFlag(ApplicationFlags.FullScreen) && !header.application_flags.HasFlag(ApplicationFlags.GUICompatible)) - Console.WriteLine("\tApplication is full screen, unaware of Presentation Manager"); - else if (!header.application_flags.HasFlag(ApplicationFlags.FullScreen) && header.application_flags.HasFlag(ApplicationFlags.GUICompatible)) - Console.WriteLine("\tApplication is aware of Presentation Manager, but doesn't use it"); - else if (header.application_flags.HasFlag(ApplicationFlags.FullScreen) && header.application_flags.HasFlag(ApplicationFlags.GUICompatible)) - Console.WriteLine("\tApplication uses Presentation Manager"); - if (header.os2_flags.HasFlag(OS2Flags.LongFilename)) - Console.WriteLine("\tApplication supports long filenames"); - if (header.os2_flags.HasFlag(OS2Flags.ProtectedMode2)) - Console.WriteLine("\tApplication uses OS/2 2.x protected mode"); - if (header.os2_flags.HasFlag(OS2Flags.ProportionalFonts)) - Console.WriteLine("\tApplication uses OS/2 2.x proportional fonts"); - if (header.os2_flags.HasFlag(OS2Flags.GangloadArea)) - Console.WriteLine("\tGangload area starts at {0} an runs for {1} bytes", header.return_thunks_offset, header.segment_reference_thunks); - else - { - Console.WriteLine("\tReturn thunks are at: {0}", header.return_thunks_offset); - Console.WriteLine("\tSegment reference thunks are at: {0}", header.segment_reference_thunks); - } - } - else if (header.target_os == TargetOS.Windows || header.target_os == TargetOS.Win32) - { - if (header.target_os == TargetOS.Windows) - Console.WriteLine("\t16-bit Windows application"); - else if (header.target_os == TargetOS.Win32) - Console.WriteLine("\t32-bit Windows application"); - Console.WriteLine("\tApplication requires Windows {0}.{1} to run", header.os_major, header.os_minor); - if (header.application_flags.HasFlag(ApplicationFlags.FullScreen) && !header.application_flags.HasFlag(ApplicationFlags.GUICompatible)) - Console.WriteLine("\tApplication is full screen, unaware of Windows"); - else if (!header.application_flags.HasFlag(ApplicationFlags.FullScreen) && header.application_flags.HasFlag(ApplicationFlags.GUICompatible)) - Console.WriteLine("\tApplication is aware of Windows, but doesn't use it"); - else if (header.application_flags.HasFlag(ApplicationFlags.FullScreen) && header.application_flags.HasFlag(ApplicationFlags.GUICompatible)) - Console.WriteLine("\tApplication uses Windows"); - Console.WriteLine("\tReturn thunks are at: {0}", header.return_thunks_offset); - Console.WriteLine("\tSegment reference thunks are at: {0}", header.segment_reference_thunks); - } - else if (header.target_os == TargetOS.DOS) - { - Console.WriteLine("\tDOS application"); - Console.WriteLine("\tApplication requires DOS {0}.{1} to run", header.os_major, header.os_minor); - if (header.application_flags.HasFlag(ApplicationFlags.FullScreen) && !header.application_flags.HasFlag(ApplicationFlags.GUICompatible)) - Console.WriteLine("\tApplication is full screen, unaware of Windows"); - else if (!header.application_flags.HasFlag(ApplicationFlags.FullScreen) && header.application_flags.HasFlag(ApplicationFlags.GUICompatible)) - Console.WriteLine("\tApplication is aware of Windows, but doesn't use it"); - else if (header.application_flags.HasFlag(ApplicationFlags.FullScreen) && header.application_flags.HasFlag(ApplicationFlags.GUICompatible)) - Console.WriteLine("\tApplication uses Windows"); - Console.WriteLine("\tReturn thunks are at: {0}", header.return_thunks_offset); - Console.WriteLine("\tSegment reference thunks are at: {0}", header.segment_reference_thunks); - } - else if (header.target_os == TargetOS.Borland) - { - Console.WriteLine("\tBorland Operating System Services application"); - Console.WriteLine("\tApplication requires DOS {0}.{1} to run", header.os_major, header.os_minor); - if (header.application_flags.HasFlag(ApplicationFlags.FullScreen) && !header.application_flags.HasFlag(ApplicationFlags.GUICompatible)) - Console.WriteLine("\tApplication is full screen, unaware of Windows"); - else if (!header.application_flags.HasFlag(ApplicationFlags.FullScreen) && header.application_flags.HasFlag(ApplicationFlags.GUICompatible)) - Console.WriteLine("\tApplication is aware of Windows, but doesn't use it"); - else if (header.application_flags.HasFlag(ApplicationFlags.FullScreen) && header.application_flags.HasFlag(ApplicationFlags.GUICompatible)) - Console.WriteLine("\tApplication uses Windows"); - Console.WriteLine("\tReturn thunks are at: {0}", header.return_thunks_offset); - Console.WriteLine("\tSegment reference thunks are at: {0}", header.segment_reference_thunks); - } - else - { - Console.WriteLine("\tApplication for unknown OS {0}", (byte)header.target_os); - Console.WriteLine("\tApplication requires OS {0}.{1} to run", header.os_major, header.os_minor); - Console.WriteLine("\tReturn thunks are at: {0}", header.return_thunks_offset); - Console.WriteLine("\tSegment reference thunks are at: {0}", header.segment_reference_thunks); - } - - if (header.application_flags.HasFlag(ApplicationFlags.Errors)) - Console.WriteLine("\tExecutable has errors"); - if (header.application_flags.HasFlag(ApplicationFlags.NonConforming)) - Console.WriteLine("\tExecutable is non conforming"); - if (header.application_flags.HasFlag(ApplicationFlags.DLL)) - Console.WriteLine("\tExecutable is a dynamic library or a driver"); - - Console.WriteLine("\tMinimum code swap area: {0} bytes", header.minimum_swap_area); - Console.WriteLine("\tFile alignment shift: {0}", 512 << header.alignment_shift); - Console.WriteLine("\tInitial local heap should be {0} bytes", header.initial_heap); - Console.WriteLine("\tInitial stack size should be {0} bytes", header.initial_stack); - Console.WriteLine("\tCS:IP entry point: {0:X4}:{1:X4}", (header.entry_point & 0xFFFF0000) >> 16, header.entry_point & 0xFFFF); - if (!header.application_flags.HasFlag(ApplicationFlags.DLL)) - Console.WriteLine("\tSS:SP initial stack pointer: {0:X4}:{1:X4}", (header.stack_pointer & 0xFFFF0000) >> 16, header.stack_pointer & 0xFFFF); - Console.WriteLine("\tEntry table starts at {0} and runs for {1} bytes", header.entry_table_offset, header.entry_table_length); - Console.WriteLine("\tSegment table starts at {0} and contain {1} segments", header.segment_table_offset, header.segment_count); - Console.WriteLine("\tModule reference table starts at {0} and contain {1} references", header.module_reference_offset, header.reference_count); - Console.WriteLine("\tNon-resident names table starts at {0} and runs for {1} bytes", header.nonresident_names_offset, header.nonresident_table_size); - Console.WriteLine("\tResources table starts at {0} and contains {1} entries", header.resource_table_offset, header.resource_entries); - Console.WriteLine("\tResident names table starts at {0}", header.resident_names_offset); - Console.WriteLine("\tImported names table starts at {0}", header.imported_names_offset); - } - - public static ResourceTable GetResources(FileStream exeFs, uint neStart, ushort tableOff) - { - long oldPosition = exeFs.Position; - byte[] DW = new byte[2]; - byte[] DD = new byte[4]; - - exeFs.Position = neStart + tableOff; - ResourceTable table = new ResourceTable(); - exeFs.Read(DW, 0, 2); - table.alignment_shift = BitConverter.ToUInt16(DW, 0); - - List types = new List(); - - while(true) - { - ResourceType type = new ResourceType(); - exeFs.Read(DW, 0, 2); - type.id = BitConverter.ToUInt16(DW, 0); - if (type.id == 0) - break; - - exeFs.Read(DW, 0, 2); - type.count = BitConverter.ToUInt16(DW, 0); - exeFs.Read(DD, 0, 4); - type.reserved = BitConverter.ToUInt32(DD, 0); - - type.resources = new Resource[type.count]; - for (int i = 0; i < type.count; i++) - { - type.resources[i] = new Resource(); - exeFs.Read(DW, 0, 2); - type.resources[i].dataOffset = BitConverter.ToUInt16(DW, 0); - exeFs.Read(DW, 0, 2); - type.resources[i].length = BitConverter.ToUInt16(DW, 0); - exeFs.Read(DW, 0, 2); - type.resources[i].flags = (ResourceFlags)BitConverter.ToUInt16(DW, 0); - exeFs.Read(DW, 0, 2); - type.resources[i].id = BitConverter.ToUInt16(DW, 0); - exeFs.Read(DD, 0, 4); - type.resources[i].reserved = BitConverter.ToUInt32(DD, 0); - } - - types.Add(type); - } - - table.types = types.ToArray(); - - for (int t = 0; t < table.types.Length; t++) - { - if ((table.types[t].id & 0x8000) == 0) - { - byte len; - byte[] str; - exeFs.Position = neStart + tableOff + table.types[t].id; - len = (byte)exeFs.ReadByte(); - str = new byte[len]; - exeFs.Read(str, 0, len); - table.types[t].name = Encoding.ASCII.GetString(str); - } - else - table.types[t].name = IdToName(table.types[t].id); - - for (int r = 0; r < table.types[t].resources.Length; r++) - { - if ((table.types[t].resources[r].id & 0x8000) == 0) - { - byte len; - byte[] str; - exeFs.Position = neStart + tableOff + table.types[t].resources[r].id; - len = (byte)exeFs.ReadByte(); - str = new byte[len]; - exeFs.Read(str, 0, len); - table.types[t].resources[r].name = Encoding.ASCII.GetString(str); - } - else - table.types[t].resources[r].name = string.Format("{0}", table.types[t].resources[r].id & 0x7FFF); - - table.types[t].resources[r].data = new byte[table.types[t].resources[r].length * (1 << table.alignment_shift)]; - exeFs.Position = table.types[t].resources[r].dataOffset * (1 <> 16, header.entry_point & 0xFFFF); + if (!header.application_flags.HasFlag(ApplicationFlags.DLL)) + Console.WriteLine("\tSS:SP initial stack pointer: {0:X4}:{1:X4}", (header.stack_pointer & 0xFFFF0000) >> 16, header.stack_pointer & 0xFFFF); + Console.WriteLine("\tEntry table starts at {0} and runs for {1} bytes", header.entry_table_offset, header.entry_table_length); + Console.WriteLine("\tSegment table starts at {0} and contain {1} segments", header.segment_table_offset, header.segment_count); + Console.WriteLine("\tModule reference table starts at {0} and contain {1} references", header.module_reference_offset, header.reference_count); + Console.WriteLine("\tNon-resident names table starts at {0} and runs for {1} bytes", header.nonresident_names_offset, header.nonresident_table_size); + Console.WriteLine("\tResources table starts at {0} and contains {1} entries", header.resource_table_offset, header.resource_entries); + Console.WriteLine("\tResident names table starts at {0}", header.resident_names_offset); + Console.WriteLine("\tImported names table starts at {0}", header.imported_names_offset); + } + + public static ResourceTable GetResources(FileStream exeFs, uint neStart, ushort tableOff) + { + long oldPosition = exeFs.Position; + byte[] DW = new byte[2]; + byte[] DD = new byte[4]; + + exeFs.Position = neStart + tableOff; + ResourceTable table = new ResourceTable(); + exeFs.Read(DW, 0, 2); + table.alignment_shift = BitConverter.ToUInt16(DW, 0); + + List types = new List(); + + while (true) + { + ResourceType type = new ResourceType(); + exeFs.Read(DW, 0, 2); + type.id = BitConverter.ToUInt16(DW, 0); + if (type.id == 0) + break; + + exeFs.Read(DW, 0, 2); + type.count = BitConverter.ToUInt16(DW, 0); + exeFs.Read(DD, 0, 4); + type.reserved = BitConverter.ToUInt32(DD, 0); + + type.resources = new Resource[type.count]; + for (int i = 0; i < type.count; i++) + { + type.resources[i] = new Resource(); + exeFs.Read(DW, 0, 2); + type.resources[i].dataOffset = BitConverter.ToUInt16(DW, 0); + exeFs.Read(DW, 0, 2); + type.resources[i].length = BitConverter.ToUInt16(DW, 0); + exeFs.Read(DW, 0, 2); + type.resources[i].flags = (ResourceFlags)BitConverter.ToUInt16(DW, 0); + exeFs.Read(DW, 0, 2); + type.resources[i].id = BitConverter.ToUInt16(DW, 0); + exeFs.Read(DD, 0, 4); + type.resources[i].reserved = BitConverter.ToUInt32(DD, 0); + } + + types.Add(type); + } + + table.types = types.ToArray(); + + for (int t = 0; t < table.types.Length; t++) + { + if ((table.types[t].id & 0x8000) == 0) + { + byte len; + byte[] str; + exeFs.Position = neStart + tableOff + table.types[t].id; + len = (byte)exeFs.ReadByte(); + str = new byte[len]; + exeFs.Read(str, 0, len); + table.types[t].name = Encoding.ASCII.GetString(str); + } + else + table.types[t].name = Consts.IdToName(table.types[t].id); + + for (int r = 0; r < table.types[t].resources.Length; r++) + { + if ((table.types[t].resources[r].id & 0x8000) == 0) + { + byte len; + byte[] str; + exeFs.Position = neStart + tableOff + table.types[t].resources[r].id; + len = (byte)exeFs.ReadByte(); + str = new byte[len]; + exeFs.Read(str, 0, len); + table.types[t].resources[r].name = Encoding.ASCII.GetString(str); + } + else + table.types[t].resources[r].name = string.Format("{0}", table.types[t].resources[r].id & 0x7FFF); + + table.types[t].resources[r].data = new byte[table.types[t].resources[r].length * (1 << table.alignment_shift)]; + exeFs.Position = table.types[t].resources[r].dataOffset * (1 << table.alignment_shift); + exeFs.Read(table.types[t].resources[r].data, 0, table.types[t].resources[r].data.Length); + } + } + + exeFs.Position = oldPosition; + + return table; + } + } +} diff --git a/exeinfo/NE/Structs.cs b/exeinfo/NE/Structs.cs new file mode 100644 index 0000000..d9244cf --- /dev/null +++ b/exeinfo/NE/Structs.cs @@ -0,0 +1,99 @@ +using System; +using System.Runtime.InteropServices; + +namespace exeinfo.NE +{ + [StructLayout(LayoutKind.Sequential/*, Pack = 2*/)] + public struct Header + { + public ushort signature; + public byte linker_major; + public byte linker_minor; + public ushort entry_table_offset; + public ushort entry_table_length; + public uint crc; + public ProgramFlags program_flags; + public ApplicationFlags application_flags; + public byte auto_data_segment_index; + public ushort initial_heap; + public ushort initial_stack; + public uint entry_point; + public uint stack_pointer; + public ushort segment_count; + public ushort reference_count; + public ushort nonresident_table_size; + public ushort segment_table_offset; + public ushort resource_table_offset; + public ushort resident_names_offset; + public ushort module_reference_offset; + public ushort imported_names_offset; + public uint nonresident_names_offset; + public ushort movable_entries; + public ushort alignment_shift; + public ushort resource_entries; + public TargetOS target_os; + public OS2Flags os2_flags; + public ushort return_thunks_offset; + public ushort segment_reference_thunks; + public ushort minimum_swap_area; + public byte os_minor; + public byte os_major; + } + + public struct ResourceTable + { + public ushort alignment_shift; + public ResourceType[] types; + } + + public struct ResourceType + { + public ushort id; + public ushort count; + public uint reserved; + public Resource[] resources; + + // Not sequentially stored + public string name; + } + + public struct Resource + { + public ushort dataOffset; + public ushort length; + public ResourceFlags flags; + public ushort id; + public uint reserved; + + // Not sequentially stored + public string name; + public byte[] data; + } + + class VersionNode + { + public ushort cbNode; + public ushort cbData; + public string szName; + public byte[] rgbData; + public VersionNode[] children; + } + + [StructLayout(LayoutKind.Sequential)] + public class FixedFileInfo + { + public uint dwSignature; + public uint dwStrucVersion; + public uint dwFileVersionMS; + public uint dwFileVersionLS; + public uint dwProductVersionMS; + public uint dwProductVersionLS; + public uint dwFileFlagsMask; + public uint dwFileFlags; + public uint dwFileOS; + public uint dwFileType; + public uint dwFileSubtype; + public uint dwFileDateMS; + public uint dwFileDateLS; + } +} diff --git a/exeinfo/NE/Version.cs b/exeinfo/NE/Version.cs new file mode 100644 index 0000000..ee707ae --- /dev/null +++ b/exeinfo/NE/Version.cs @@ -0,0 +1,316 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + +namespace exeinfo.NE +{ + public class Version + { + public Dictionary> StringsByLanguage { get; } + + string fileVersion; + string productVersion; + VersionFileFlags fileFlags; + VersionFileOS fileOS; + VersionFileType fileType; + VersionFileSubtype fileSubtype; + DateTime fileDate; + + public string FileVersion + { + get + { + return fileVersion; + } + } + + public string ProductVersion + { + get + { + return productVersion; + } + } + + public VersionFileFlags FileFlags + { + get + { + return fileFlags; + } + } + + public VersionFileOS FileOS + { + get + { + return fileOS; + } + } + + public VersionFileType FileType + { + get + { + return fileType; + } + } + + public VersionFileSubtype FileSubtype + { + get + { + return fileSubtype; + } + } + + public DateTime FileDate + { + get + { + return fileDate; + } + } + + public Version(byte[] data) + { + if (data == null || data.Length < 5) + return; + + StringsByLanguage = new Dictionary>(); + + VersionNode root = GetNode(data, 0, out int rootLength); + DecodeNode(root, null, null); + } + + VersionNode GetNode(byte[] data, int startPosition, out int nodeLength) + { + nodeLength = 0; + + VersionNode node = new VersionNode + { + cbNode = BitConverter.ToUInt16(data, startPosition + nodeLength), + cbData = BitConverter.ToUInt16(data, startPosition + nodeLength + 2) + }; + nodeLength += 4; + + MemoryStream nameMs = new MemoryStream(); + while (data[startPosition + nodeLength] > 0) + { + nameMs.WriteByte(data[startPosition + nodeLength]); + nodeLength++; + } + node.szName = Encoding.ASCII.GetString(nameMs.ToArray()); + nodeLength++; + + if (nodeLength % 4 > 0) + nodeLength += 4 - (nodeLength % 4); + + node.rgbData = new byte[node.cbData]; + Array.Copy(data, startPosition + nodeLength, node.rgbData, 0, node.cbData); + nodeLength += node.cbData; + if (nodeLength % 4 > 0) + nodeLength += 4 - (nodeLength % 4); + + List children = new List(); + + while (nodeLength < node.cbNode) + { + children.Add(GetNode(data, startPosition + nodeLength, out int childLength)); + nodeLength += childLength; + } + + if (children.Count > 0) + node.children = children.ToArray(); + + return node; + } + + void DecodeNode(VersionNode node, string parent, string grandparent) + { + if (node.szName == Consts.FixedFileInfo) + { + IntPtr infoPtr = Marshal.AllocHGlobal(node.cbData); + Marshal.Copy(node.rgbData, 0, infoPtr, node.cbData); + FixedFileInfo info = (FixedFileInfo)Marshal.PtrToStructure(infoPtr, typeof(FixedFileInfo)); + Marshal.FreeHGlobal(infoPtr); + + fileVersion = string.Format("{0}.{1:D2}.{2}.{3}", (info.dwFileVersionMS & 0xFFFF0000) >> 16, info.dwFileVersionMS & 0xFFFF, + (info.dwFileVersionLS & 0xFFFF0000) >> 16, info.dwFileVersionLS & 0xFFFF); + productVersion = string.Format("{0}.{1:D2}.{2}.{3}", (info.dwProductVersionMS & 0xFFFF0000) >> 16, info.dwProductVersionMS & 0xFFFF, + (info.dwProductVersionLS & 0xFFFF0000) >> 16, info.dwProductVersionLS & 0xFFFF); + fileFlags = (VersionFileFlags)(info.dwFileFlags & info.dwFileFlagsMask); + fileOS = (VersionFileOS)info.dwFileOS; + fileType = (VersionFileType)info.dwFileType; + fileSubtype = (VersionFileSubtype)info.dwFileSubtype; + fileDate = DateTime.FromFileTime(info.dwFileDateMS * 0x100000000 + info.dwFileDateLS); + } + + if (parent == Consts.StringFileInfo) + { + Dictionary strings = new Dictionary(); + StringsByLanguage.Add(node.szName, strings); + } + + if (grandparent == Consts.StringFileInfo) + { + if (StringsByLanguage.TryGetValue(parent, out Dictionary strings)) + { + Encoding encoding; + + try + { + encoding = Encoding.GetEncoding(Convert.ToInt32(parent.Substring(4), 16)); + } + catch + { + encoding = Encoding.ASCII; + } + + strings.Add(node.szName, encoding.GetString(node.rgbData)); + } + } + + if (node.children != null) + { + for (int i = 0; i < node.children.Length; i++) + DecodeNode(node.children[i], node.szName, parent); + } + } + + public static string TypeToString(VersionFileType type) + { + switch (type) + { + case VersionFileType.VFT_APP: + return "Application"; + case VersionFileType.VFT_DLL: + return "Dynamic-link library"; + case VersionFileType.VFT_DRV: + return "Device driver"; + case VersionFileType.VFT_FONT: + return "Font"; + case VersionFileType.VFT_STATIC_LIB: + return "Static-link library"; + case VersionFileType.VFT_UNKNOWN: + return "Unknown"; + case VersionFileType.VFT_VXD: + return "Virtual device"; + default: + return string.Format("Unknown type code {0}", (uint)type); + } + } + + public static string DriverToString(VersionFileSubtype subtype) + { + switch (subtype) + { + case VersionFileSubtype.VFT2_DRV_COMM: + return "Communications"; + case VersionFileSubtype.VFT2_DRV_DISPLAY: + return "Display"; + case VersionFileSubtype.VFT2_DRV_INSTALLABLE: + return "Installable"; + case VersionFileSubtype.VFT2_DRV_KEYBOARD: + return "Keyboard"; + case VersionFileSubtype.VFT2_DRV_LANGUAGE: + return "Language"; + case VersionFileSubtype.VFT2_DRV_MOUSE: + return "Mouse"; + case VersionFileSubtype.VFT2_DRV_NETWORK: + return "Network"; + case VersionFileSubtype.VFT2_DRV_PRINTER: + return "Printer"; + case VersionFileSubtype.VFT2_DRV_SOUND: + return "Sound"; + case VersionFileSubtype.VFT2_DRV_SYSTEM: + return "System"; + case VersionFileSubtype.VFT2_DRV_VERSIONED_PRINTER: + return "Versioned"; + case VersionFileSubtype.VFT2_UNKNOWN: + return "Unknown"; + default: + return string.Format("Unknown type code {0}", (uint)subtype); + } + } + + public static string FontToString(VersionFileSubtype subtype) + { + switch (subtype) + { + case VersionFileSubtype.VFT2_FONT_RASTER: + return "Raster"; + case VersionFileSubtype.VFT2_FONT_TRUETYPE: + return "TrueType"; + case VersionFileSubtype.VFT2_FONT_VECTOR: + return "Vector"; + case VersionFileSubtype.VFT2_UNKNOWN: + return "Unknown"; + default: + return string.Format("Unknown type code {0}", (uint)subtype); + } + } + public static string OsToString(VersionFileOS os) + { + switch (os) + { + case VersionFileOS.VOS_DOS: + return "DOS"; + case VersionFileOS.VOS_NT: + return "Windows NT"; + case VersionFileOS.VOS_WINDOWS16: + return "16-bit Windows"; + case VersionFileOS.VOS_WINDOWS32: + return "32-bit Windows"; + case VersionFileOS.VOS_OS216: + return "16-bit OS/2"; + case VersionFileOS.VOS_OS232: + return "32-bit OS/2"; + case VersionFileOS.VOS_PM16: + return "16-bit Presentation Manager"; + case VersionFileOS.VOS_PM32: + return "32-bit Presentation Manager"; + case VersionFileOS.VOS_UNKNOWN: + return "Unknown"; + case VersionFileOS.VOS_DOS_NT: + return "DOS running under Windows NT"; + case VersionFileOS.VOS_DOS_WINDOWS16: + return "16-bit Windows running under DOS"; + case VersionFileOS.VOS_DOS_WINDOWS32: + return "32-bit Windows running under DOS"; + case VersionFileOS.VOS_DOS_PM16: + return "16-bit Presentation Manager running under DOS"; + case VersionFileOS.VOS_DOS_PM32: + return "32-bit Presentation Manager running under DOS"; + case VersionFileOS.VOS_NT_WINDOWS16: + return "16-bit Windows running under Windows NT"; + case VersionFileOS.VOS_NT_WINDOWS32: + return "32-bit Windows running under Windows NT"; + case VersionFileOS.VOS_NT_PM16: + return "16-bit Presentation Manager running under Windows NT"; + case VersionFileOS.VOS_NT_PM32: + return "32-bit Presentation Manager running under Windows NT"; + case VersionFileOS.VOS_OS216_WINDOWS16: + return "16-bit Windows running under 16-bit OS/2"; + case VersionFileOS.VOS_OS216_WINDOWS32: + return "32-bit Windows running under 16-bit OS/2"; + case VersionFileOS.VOS_OS216_PM16: + return "16-bit Presentation Manager running under 16-bit OS/2"; + case VersionFileOS.VOS_OS216_PM32: + return "32-bit Presentation Manager running under 16-bit OS/2"; + case VersionFileOS.VOS_OS232_WINDOWS16: + return "16-bit Windows running under 32-bit OS/2"; + case VersionFileOS.VOS_OS232_WINDOWS32: + return "32-bit Windows running under 32-bit OS/2"; + case VersionFileOS.VOS_OS232_PM16: + return "16-bit Presentation Manager running under 32-bit OS/2"; + case VersionFileOS.VOS_OS232_PM32: + return "32-bit Presentation Manager running under 32-bit OS/2"; + default: + return string.Format("Unknown OS code {0}", (uint)os); + } + } + } +} diff --git a/exeinfo/Program.cs b/exeinfo/Program.cs index 0d6ac92..93a90ef 100644 --- a/exeinfo/Program.cs +++ b/exeinfo/Program.cs @@ -1,6 +1,9 @@ using System; using System.IO; using System.Runtime.InteropServices; +using System.Collections.Generic; +using System.Globalization; +using System.Text; namespace exeinfo { @@ -46,10 +49,41 @@ namespace exeinfo neHdr = (NE.Header)Marshal.PtrToStructure(hdrPtr, typeof(NE.Header)); Marshal.FreeHGlobal(hdrPtr); - if (neHdr.signature == NE.Signature) + if (neHdr.signature == NE.Consts.Signature) { - NE.PrintInfo(neHdr); - NE.GetResources(exeFs, mzHdr.new_offset, neHdr.resource_table_offset); + NE.Info.PrintInfo(neHdr); + NE.ResourceTable resources = NE.Info.GetResources(exeFs, mzHdr.new_offset, neHdr.resource_table_offset); + foreach(NE.ResourceType type in resources.types) + { + if((type.id & 0x7FFF) == (int)NE.ResourceTypes.RT_VERSION) + { + foreach(NE.Resource resource in type.resources) + { + NE.Version vers = new NE.Version(resource.data); + Console.WriteLine("\tVersion resource {0}:", resource.name); + Console.WriteLine("\t\tFile version: {0}", vers.FileVersion); + Console.WriteLine("\t\tProduct version: {0}", vers.ProductVersion); + Console.WriteLine("\t\tFile type: {0}", NE.Version.TypeToString(vers.FileType)); + if(vers.FileType == NE.VersionFileType.VFT_DRV) + Console.WriteLine("\t\tFile subtype: {0} driver", NE.Version.DriverToString(vers.FileSubtype)); + else if (vers.FileType == NE.VersionFileType.VFT_DRV) + Console.WriteLine("\t\tFile subtype: {0} font", NE.Version.FontToString(vers.FileSubtype)); + else if(vers.FileSubtype > 0) + Console.WriteLine("\t\tFile subtype: {0}", (uint)vers.FileSubtype); + Console.WriteLine("\t\tFile flags: {0}", vers.FileFlags); + Console.WriteLine("\t\tFile OS: {0}", NE.Version.OsToString(vers.FileOS)); + + foreach (KeyValuePair> strByLang in vers.StringsByLanguage) + { + CultureInfo cult = new CultureInfo(Convert.ToInt32(strByLang.Key.Substring(0, 4), 16)); + Encoding encoding = Encoding.GetEncoding(Convert.ToInt32(strByLang.Key.Substring(4), 16)); + Console.WriteLine("\t\tStrings for {0} in codepage {1}:", cult.DisplayName, encoding.EncodingName); + foreach(KeyValuePair strings in strByLang.Value) + Console.WriteLine("\t\t\t{0}: {1}", strings.Key, strings.Value); + } + } + } + } } } } diff --git a/exeinfo/exeinfo.csproj b/exeinfo/exeinfo.csproj index 5736f7a..f8f6e71 100644 --- a/exeinfo/exeinfo.csproj +++ b/exeinfo/exeinfo.csproj @@ -35,7 +35,14 @@ - + + + + + + + + \ No newline at end of file