mirror of
https://github.com/claunia/libexeinfo.git
synced 2025-12-16 19:14:24 +00:00
Added support for NE version resources.
This commit is contained in:
403
exeinfo/NE.cs
403
exeinfo/NE.cs
@@ -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<ResourceType> types = new List<ResourceType>();
|
||||
|
||||
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 <<table.alignment_shift);
|
||||
exeFs.Read(table.types[t].resources[r].data, 0, table.types[t].resources[r].data.Length);
|
||||
}
|
||||
}
|
||||
|
||||
exeFs.Position = oldPosition;
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
public static string IdToName(ushort id)
|
||||
{
|
||||
switch(id & 0x7FFF)
|
||||
{
|
||||
case 9:
|
||||
return "RT_ACCELERATOR";
|
||||
case 21:
|
||||
return "RT_ANICURSOR";
|
||||
case 22:
|
||||
return "RT_ANIICON";
|
||||
case 2:
|
||||
return "RT_BITMAP";
|
||||
case 1:
|
||||
return "RT_CURSOR";
|
||||
case 5:
|
||||
return "RT_DIALOG";
|
||||
case 18:
|
||||
return "RT_DIALOGEX";
|
||||
case 17:
|
||||
return "RT_DLGINCLUDE";
|
||||
case 240:
|
||||
return "RT_DLGINIT";
|
||||
case 8:
|
||||
return "RT_FONT";
|
||||
case 7:
|
||||
return "RT_FONTDIR";
|
||||
case 12:
|
||||
return "RT_GROUP_CURSOR";
|
||||
case 14:
|
||||
return "RT_GROUP_ICON";
|
||||
case 23:
|
||||
return "RT_HTML";
|
||||
case 3:
|
||||
return "RT_ICON";
|
||||
case 24:
|
||||
return "RT_MANIFEST";
|
||||
case 4:
|
||||
return "RT_MENU";
|
||||
case 15:
|
||||
return "RT_MENUEX";
|
||||
case 11:
|
||||
return "RT_MESSAGETABLE";
|
||||
case 8194:
|
||||
return "RT_NEWBITMAP";
|
||||
case 19:
|
||||
return "RT_PLUGPLAY";
|
||||
case 10:
|
||||
return "RT_RCDATA";
|
||||
case 6:
|
||||
return "RT_STRING";
|
||||
case 241:
|
||||
return "RT_TOOLBAR";
|
||||
case 16:
|
||||
return "RT_VERSION";
|
||||
case 20:
|
||||
return "RT_VXD";
|
||||
default:
|
||||
return string.Format("{0}", id & 0x7FFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
72
exeinfo/NE/Consts.cs
Normal file
72
exeinfo/NE/Consts.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
namespace exeinfo.NE
|
||||
{
|
||||
public static class Consts
|
||||
{
|
||||
public const ushort Signature = 0x454E;
|
||||
public static readonly string FixedFileInfo = "VS_VERSION_INFO";
|
||||
public static readonly string StringFileInfo = "StringFileInfo";
|
||||
|
||||
public static string IdToName(ushort id)
|
||||
{
|
||||
switch (id & 0x7FFF)
|
||||
{
|
||||
case (int)ResourceTypes.RT_ACCELERATOR:
|
||||
return "RT_ACCELERATOR";
|
||||
case (int)ResourceTypes.RT_ANICURSOR:
|
||||
return "RT_ANICURSOR";
|
||||
case (int)ResourceTypes.RT_ANIICON:
|
||||
return "RT_ANIICON";
|
||||
case (int)ResourceTypes.RT_BITMAP:
|
||||
return "RT_BITMAP";
|
||||
case (int)ResourceTypes.RT_CURSOR:
|
||||
return "RT_CURSOR";
|
||||
case (int)ResourceTypes.RT_DIALOG:
|
||||
return "RT_DIALOG";
|
||||
case (int)ResourceTypes.RT_DIALOGEX:
|
||||
return "RT_DIALOGEX";
|
||||
case (int)ResourceTypes.RT_DLGINCLUDE:
|
||||
return "RT_DLGINCLUDE";
|
||||
case (int)ResourceTypes.RT_DLGINIT:
|
||||
return "RT_DLGINIT";
|
||||
case (int)ResourceTypes.RT_FONT:
|
||||
return "RT_FONT";
|
||||
case (int)ResourceTypes.RT_FONTDIR:
|
||||
return "RT_FONTDIR";
|
||||
case (int)ResourceTypes.RT_GROUP_CURSOR:
|
||||
return "RT_GROUP_CURSOR";
|
||||
case (int)ResourceTypes.RT_GROUP_ICON:
|
||||
return "RT_GROUP_ICON";
|
||||
case (int)ResourceTypes.RT_HTML:
|
||||
return "RT_HTML";
|
||||
case (int)ResourceTypes.RT_ICON:
|
||||
return "RT_ICON";
|
||||
case (int)ResourceTypes.RT_MANIFEST:
|
||||
return "RT_MANIFEST";
|
||||
case (int)ResourceTypes.RT_MENU:
|
||||
return "RT_MENU";
|
||||
case (int)ResourceTypes.RT_MENUEX:
|
||||
return "RT_MENUEX";
|
||||
case (int)ResourceTypes.RT_MESSAGETABLE:
|
||||
return "RT_MESSAGETABLE";
|
||||
case (int)ResourceTypes.RT_NEWBITMAP:
|
||||
return "RT_NEWBITMAP";
|
||||
case (int)ResourceTypes.RT_PLUGPLAY:
|
||||
return "RT_PLUGPLAY";
|
||||
case (int)ResourceTypes.RT_RCDATA:
|
||||
return "RT_RCDATA";
|
||||
case (int)ResourceTypes.RT_STRING:
|
||||
return "RT_STRING";
|
||||
case (int)ResourceTypes.RT_TOOLBAR:
|
||||
return "RT_TOOLBAR";
|
||||
case (int)ResourceTypes.RT_VERSION:
|
||||
return "RT_VERSION";
|
||||
case (int)ResourceTypes.RT_VXD:
|
||||
return "RT_VXD";
|
||||
default:
|
||||
return string.Format("{0}", id & 0x7FFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
160
exeinfo/NE/Enums.cs
Normal file
160
exeinfo/NE/Enums.cs
Normal file
@@ -0,0 +1,160 @@
|
||||
using System;
|
||||
namespace exeinfo.NE
|
||||
{
|
||||
[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,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ResourceFlags : ushort
|
||||
{
|
||||
Moveable = 0x10,
|
||||
Pure = 0x20,
|
||||
Preload = 0x40
|
||||
}
|
||||
|
||||
public enum ResourceTypes : ushort
|
||||
{
|
||||
RT_ACCELERATOR = 9,
|
||||
RT_ANICURSOR = 21,
|
||||
RT_ANIICON = 22,
|
||||
RT_BITMAP = 2,
|
||||
RT_CURSOR = 1,
|
||||
RT_DIALOG = 5,
|
||||
RT_DIALOGEX = 18,
|
||||
RT_DLGINCLUDE = 17,
|
||||
RT_DLGINIT = 240,
|
||||
RT_FONT = 8,
|
||||
RT_FONTDIR = 7,
|
||||
RT_GROUP_CURSOR = 12,
|
||||
RT_GROUP_ICON = 13,
|
||||
RT_HTML = 23,
|
||||
RT_ICON = 3,
|
||||
RT_MANIFEST = 24,
|
||||
RT_MENU = 4,
|
||||
RT_MENUEX = 15,
|
||||
RT_MESSAGETABLE = 11,
|
||||
RT_NEWBITMAP = RT_NEW | RT_BITMAP,
|
||||
RT_PLUGPLAY = 19,
|
||||
RT_RCDATA = 10,
|
||||
RT_STRING = 6,
|
||||
RT_TOOLBAR = 241,
|
||||
RT_VERSION = 16,
|
||||
RT_VXD = 20,
|
||||
RT_NEW = 0x2000,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum VersionFileFlags : uint
|
||||
{
|
||||
VS_FF_DEBUG = 0x00000001,
|
||||
VS_FF_INFOINFERRED = 0x00000010,
|
||||
VS_FF_PATCHED = 0x00000004,
|
||||
VS_FF_PRERELEASE = 0x00000002,
|
||||
VS_FF_PRIVATEBUILD = 0x00000008,
|
||||
VS_FF_SPECIALBUILD = 0x00000020,
|
||||
}
|
||||
|
||||
public enum VersionFileOS : uint
|
||||
{
|
||||
VOS_DOS = 0x00010000,
|
||||
VOS_NT = 0x00040000,
|
||||
VOS_WINDOWS16 = 0x00000001,
|
||||
VOS_WINDOWS32 = 0x00000004,
|
||||
VOS_OS216 = 0x00020000,
|
||||
VOS_OS232 = 0x00030000,
|
||||
VOS_PM16 = 0x00000002,
|
||||
VOS_PM32 = 0x00000003,
|
||||
VOS_UNKNOWN = 0x00000000,
|
||||
|
||||
// Combinations, some have no sense
|
||||
VOS_DOS_NT = 0x00050000,
|
||||
VOS_DOS_WINDOWS16 = 0x00010001,
|
||||
VOS_DOS_WINDOWS32 = 0x00010004,
|
||||
VOS_DOS_PM16 = 0x00010002,
|
||||
VOS_DOS_PM32 = 0x00010003,
|
||||
VOS_NT_WINDOWS16 = 0x00040001,
|
||||
VOS_NT_WINDOWS32 = 0x00040004,
|
||||
VOS_NT_PM16 = 0x00040002,
|
||||
VOS_NT_PM32 = 0x00040003,
|
||||
VOS_OS216_WINDOWS16 = 0x00020001,
|
||||
VOS_OS216_WINDOWS32 = 0x00020004,
|
||||
VOS_OS216_PM16 = 0x00020002,
|
||||
VOS_OS216_PM32 = 0x00020003,
|
||||
VOS_OS232_WINDOWS16 = 0x00030001,
|
||||
VOS_OS232_WINDOWS32 = 0x00030004,
|
||||
VOS_OS232_PM16 = 0x00030002,
|
||||
VOS_OS232_PM32 = 0x00030003,
|
||||
}
|
||||
|
||||
public enum VersionFileType : uint
|
||||
{
|
||||
VFT_APP = 0x00000001,
|
||||
VFT_DLL = 0x00000002,
|
||||
VFT_DRV = 0x00000003,
|
||||
VFT_FONT = 0x00000004,
|
||||
VFT_STATIC_LIB = 0x00000007,
|
||||
VFT_UNKNOWN = 0x00000000,
|
||||
VFT_VXD = 0x00000005,
|
||||
}
|
||||
|
||||
public enum VersionFileSubtype : uint
|
||||
{
|
||||
VFT2_UNKNOWN = 0x00000000,
|
||||
// Drivers
|
||||
VFT2_DRV_COMM = 0x0000000A,
|
||||
VFT2_DRV_DISPLAY = 0x00000004,
|
||||
VFT2_DRV_INSTALLABLE = 0x00000008,
|
||||
VFT2_DRV_KEYBOARD = 0x00000002,
|
||||
VFT2_DRV_LANGUAGE = 0x00000003,
|
||||
VFT2_DRV_MOUSE = 0x00000005,
|
||||
VFT2_DRV_NETWORK = 0x00000006,
|
||||
VFT2_DRV_PRINTER = 0x00000001,
|
||||
VFT2_DRV_SOUND = 0x00000009,
|
||||
VFT2_DRV_SYSTEM = 0x00000007,
|
||||
VFT2_DRV_VERSIONED_PRINTER = 0x0000000C,
|
||||
// Fonts
|
||||
VFT2_FONT_RASTER = 0x00000001,
|
||||
VFT2_FONT_TRUETYPE = 0x00000003,
|
||||
VFT2_FONT_VECTOR = 0x00000002,
|
||||
}
|
||||
}
|
||||
221
exeinfo/NE/Info.cs
Normal file
221
exeinfo/NE/Info.cs
Normal file
@@ -0,0 +1,221 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace exeinfo.NE
|
||||
{
|
||||
public class Info
|
||||
{
|
||||
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<ResourceType> types = new List<ResourceType>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
99
exeinfo/NE/Structs.cs
Normal file
99
exeinfo/NE/Structs.cs
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
316
exeinfo/NE/Version.cs
Normal file
316
exeinfo/NE/Version.cs
Normal file
@@ -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<string, Dictionary<string, string>> 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<string, Dictionary<string, string>>();
|
||||
|
||||
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<VersionNode> children = new List<VersionNode>();
|
||||
|
||||
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<string, string> strings = new Dictionary<string, string>();
|
||||
StringsByLanguage.Add(node.szName, strings);
|
||||
}
|
||||
|
||||
if (grandparent == Consts.StringFileInfo)
|
||||
{
|
||||
if (StringsByLanguage.TryGetValue(parent, out Dictionary<string, string> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<string, Dictionary<string, string>> 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<string, string> strings in strByLang.Value)
|
||||
Console.WriteLine("\t\t\t{0}: {1}", strings.Key, strings.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,14 @@
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="MZ.cs" />
|
||||
<Compile Include="NE.cs" />
|
||||
<Compile Include="NE\Version.cs" />
|
||||
<Compile Include="NE\Structs.cs" />
|
||||
<Compile Include="NE\Enums.cs" />
|
||||
<Compile Include="NE\Consts.cs" />
|
||||
<Compile Include="NE\Info.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="NE\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
Reference in New Issue
Block a user