diff --git a/exeinfo/Program.cs b/exeinfo/Program.cs index 4a966f2..aa75684 100644 --- a/exeinfo/Program.cs +++ b/exeinfo/Program.cs @@ -120,6 +120,55 @@ namespace exeinfo recognized = true; Console.Write(lxExe.Information); + if(((LX)lxExe).WinVersion != null) + { + NE.Version vers = ((LX)lxExe).WinVersion; + Console.WriteLine("\tVxD version resource {0}:", vers.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) + { + string cultureName; + string encodingName; + + try + { + cultureName = new CultureInfo(Convert.ToInt32(strByLang.Key.Substring(0, 4), 16)) + .DisplayName; + } + catch + { + cultureName = + $"unsupported culture 0x{Convert.ToInt32(strByLang.Key.Substring(0, 4), 16):X4}"; + } + + try + { + encodingName = Encoding.GetEncoding(Convert.ToInt32(strByLang.Key.Substring(4), 16)) + .EncodingName; + } + catch + { + encodingName = + $"unsupported encoding 0x{Convert.ToInt32(strByLang.Key.Substring(4), 16):X4}"; + } + + Console.WriteLine("\t\tStrings for {0} in codepage {1}:", cultureName, encodingName); + foreach(KeyValuePair strings in strByLang.Value) + Console.WriteLine("\t\t\t{0}: {1}", strings.Key, strings.Value); + } + } + if(lxExe.Strings != null && lxExe.Strings.Any()) { Console.WriteLine("\tStrings:"); diff --git a/exeinfogui/LE/TabLeVxdVersion.xeto b/exeinfogui/LE/TabLeVxdVersion.xeto new file mode 100644 index 0000000..a265f95 --- /dev/null +++ b/exeinfogui/LE/TabLeVxdVersion.xeto @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/exeinfogui/LE/TabLeVxdVersion.xeto.cs b/exeinfogui/LE/TabLeVxdVersion.xeto.cs new file mode 100644 index 0000000..50706f3 --- /dev/null +++ b/exeinfogui/LE/TabLeVxdVersion.xeto.cs @@ -0,0 +1,51 @@ +// +// TabLeVxdVersion.xeto.cs +// +// Author: +// Natalia Portillo +// +// Copyright (c) 2017-2018 Copyright © Claunia.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using exeinfogui.Win16; +using Eto.Forms; +using Eto.Serialization.Xaml; + +namespace exeinfogui.LE +{ + public class TabLeVxdVersion : TabPage + { + PanelWin16Version panelWin16Version; + Panel pnlVersion; + + public TabLeVxdVersion() + { + XamlReader.Load(this); + + panelWin16Version = new PanelWin16Version(); + pnlVersion.Content = panelWin16Version; + } + + public void Update(libexeinfo.NE.Version version) + { + panelWin16Version.Update(version); + } + } +} \ No newline at end of file diff --git a/exeinfogui/MainForm.xeto.cs b/exeinfogui/MainForm.xeto.cs index ff25146..26c69ad 100644 --- a/exeinfogui/MainForm.xeto.cs +++ b/exeinfogui/MainForm.xeto.cs @@ -27,6 +27,7 @@ using System; using System.Linq; using exeinfogui.GEM; +using exeinfogui.LE; using exeinfogui.NE; using Eto.Forms; using Eto.Serialization.Xaml; @@ -39,6 +40,7 @@ namespace exeinfogui ComboBox cmbArch; Label lblSubsystem; TabGemResources tabGemResources; + TabLeVxdVersion tabLeVxdVersion; TabControl tabMain; TabNeResources tabNeResources; TabPageSegments tabSegments; @@ -57,10 +59,12 @@ namespace exeinfogui tabStrings = new TabPageStrings {Visible = false}; tabGemResources = new TabGemResources {Visible = false}; tabNeResources = new TabNeResources {Visible = false}; + tabLeVxdVersion = new TabLeVxdVersion {Visible = false}; tabMain.Pages.Add(tabSegments); tabMain.Pages.Add(tabStrings); tabMain.Pages.Add(tabGemResources); tabMain.Pages.Add(tabNeResources); + tabMain.Pages.Add(tabLeVxdVersion); } protected void OnBtnLoadClick(object sender, EventArgs e) @@ -73,6 +77,9 @@ namespace exeinfogui txtSubsystem.Visible = false; tabStrings.Visible = false; tabGemResources.Visible = false; + tabSegments.Visible = false; + tabNeResources.Visible = false; + tabLeVxdVersion.Visible = false; OpenFileDialog dlgOpen = new OpenFileDialog {Title = "Choose executable file", MultiSelect = false}; @@ -113,7 +120,15 @@ namespace exeinfogui tabNeResources.Visible = true; } } - else if(lxExe.Recognized) recognizedExe = lxExe; + else if(lxExe.Recognized) + { + recognizedExe = lxExe; + if(((LX)lxExe).WinVersion != null) + { + tabLeVxdVersion.Visible = true; + tabLeVxdVersion.Update(((LX)lxExe).WinVersion); + } + } else if(peExe.Recognized) recognizedExe = peExe; else if(stExe.Recognized) { diff --git a/exeinfogui/Win16/PanelWin16Version.xeto.cs b/exeinfogui/Win16/PanelWin16Version.xeto.cs index 42b4f71..7ec1e8a 100644 --- a/exeinfogui/Win16/PanelWin16Version.xeto.cs +++ b/exeinfogui/Win16/PanelWin16Version.xeto.cs @@ -88,19 +88,22 @@ namespace exeinfogui.Win16 public void Update(byte[] data) { - libexeinfo.NE.Version version = new libexeinfo.NE.Version(data); - txtFileDate.Text = version.FileDate != new DateTime(1601, 1, 1) ? $"{version.FileDate}" : "Not set"; - txtFileFlags.Text = version.FileFlags == 0 ? "Normal" : $"{version.FileFlags}"; - txtFileOs.Text = libexeinfo.NE.Version.OsToString(version.FileOS); + Update(new libexeinfo.NE.Version(data)); + } + + public void Update(libexeinfo.NE.Version version) + { + txtFileDate.Text = version.FileDate != new DateTime(1601, 1, 1) ? $"{version.FileDate}" : "Not set"; + txtFileFlags.Text = version.FileFlags == 0 ? "Normal" : $"{version.FileFlags}"; + txtFileOs.Text = libexeinfo.NE.Version.OsToString(version.FileOS); if(version.FileType == libexeinfo.NE.VersionFileType.VFT_DRV) txtFileSubtype.Text = $"{libexeinfo.NE.Version.DriverToString(version.FileSubtype)} driver"; else if(version.FileType == libexeinfo.NE.VersionFileType.VFT_DRV) - txtFileSubtype.Text = $"{libexeinfo.NE.Version.FontToString(version.FileSubtype)} font"; - else if(version.FileSubtype > 0) - txtFileSubtype.Text = $"{(uint)version.FileSubtype}"; - else - txtFileSubtype.Text = "None"; + txtFileSubtype.Text = + $"{libexeinfo.NE.Version.FontToString(version.FileSubtype)} font"; + else if(version.FileSubtype > 0) txtFileSubtype.Text = $"{(uint)version.FileSubtype}"; + else txtFileSubtype.Text = "None"; txtFileType.Text = libexeinfo.NE.Version.TypeToString(version.FileType); txtFileVersion.Text = $"{version.FileVersion}"; @@ -113,8 +116,8 @@ namespace exeinfogui.Win16 string cultureName; string encodingName; - try { cultureName = new CultureInfo(Convert.ToInt32(strByLang.Key.Substring(0, 4), 16)).DisplayName; } - catch { cultureName = $"0x{Convert.ToInt32(strByLang.Key.Substring(0, 4), 16):X4}"; } + try { cultureName = new CultureInfo(Convert.ToInt32(strByLang.Key.Substring(0, 4), 16)).DisplayName; } + catch { cultureName = $"0x{Convert.ToInt32(strByLang.Key.Substring(0, 4), 16):X4}"; } try { diff --git a/exeinfogui/exeinfogui.csproj b/exeinfogui/exeinfogui.csproj index 03dcaa7..c3206fc 100644 --- a/exeinfogui/exeinfogui.csproj +++ b/exeinfogui/exeinfogui.csproj @@ -19,10 +19,12 @@ + + \ No newline at end of file diff --git a/libexeinfo/LX/Enums.cs b/libexeinfo/LX/Enums.cs index 6a0c2b2..1dbd12c 100644 --- a/libexeinfo/LX/Enums.cs +++ b/libexeinfo/LX/Enums.cs @@ -109,7 +109,9 @@ namespace libexeinfo OS2 = 1, Windows = 2, DOS = 3, - Win32 = 4 + Win32 = 4, + NT = 0x20, + Posix = 0x21 } static Architecture CpuToArchitecture(TargetCpu cpu) @@ -117,16 +119,68 @@ namespace libexeinfo switch(cpu) { case TargetCpu.i286: return Architecture.I286; - case TargetCpu.i386: - case TargetCpu.i486: + case TargetCpu.i386: + case TargetCpu.i486: case TargetCpu.Pentium: return Architecture.I386; - case TargetCpu.i860: + case TargetCpu.i860: case TargetCpu.N11: return Architecture.I860; - case TargetCpu.MIPS1: + case TargetCpu.MIPS1: case TargetCpu.MIPS2: return Architecture.Mips; case TargetCpu.MIPS3: return Architecture.Mips3; - default: return Architecture.Unknown; + default: return Architecture.Unknown; } } + + [Flags] + enum ObjectFlags + { + Readable = 0x0001, + Writable = 0x0002, + Executable = 0x0004, + Resource = 0x0008, + Discardable = 0x0010, + Shared = 0x0020, + Preload = 0x0040, + Invalid = 0x0080, + Zeroed = 0x0100, + Resident = 0x0200, + Contiguous = 0x0300, + LongLockable = 0x0400, + Reserved = 0x0800, + Alias1616Required = 0x1000, + BigDefaultBitSetting = 0x2000, + Conforming = 0x4000, + Privilege = 0x8000 + } + + enum PageTableAttributes : ushort + { + /// + /// Offset from preload page section + /// + LegalPhysicalPage = 0, + /// + /// Offset from iterated page section + /// + IteratedDataPage = 1, + Invalid = 2, + Zeroed = 3, + RangeOfPages = 4 + } + + enum PageTableAttributes16 : byte + { + /// + /// Offset from preload page section + /// + LegalPhysicalPage = (byte)PageTableAttributes.LegalPhysicalPage, + /// + /// Offset from iterated page section + /// + IteratedDataPage = (byte)PageTableAttributes.IteratedDataPage, + Invalid = (byte)PageTableAttributes.Invalid, + Zeroed = (byte)PageTableAttributes.Zeroed, + RangeOfPages = (byte)PageTableAttributes.RangeOfPages + } } } \ No newline at end of file diff --git a/libexeinfo/LX/Info.cs b/libexeinfo/LX/Info.cs index a07dd90..383602e 100644 --- a/libexeinfo/LX/Info.cs +++ b/libexeinfo/LX/Info.cs @@ -24,179 +24,295 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +using System; +using System.Collections.Generic; +using System.IO; using System.Text; namespace libexeinfo { public partial class LX { - public string Information => GetInfo(header, baseExecutable); - - static string GetInfo(LXHeader header, IExecutable baseExecutable) + public string Information { - StringBuilder sb = new StringBuilder(); - sb.Append(baseExecutable.Information); - sb.AppendLine(header.signature == SIGNATURE16 ? "Linear Executable (LE):" : "Linear eXecutable (LX):"); - - switch(header.os_type) + get { - case TargetOS.OS2: - sb.AppendLine("\tOS/2 application"); - if(header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && - !header.module_flags.HasFlag(ModuleFlags.PMCompatible)) - sb.AppendLine("\tApplication is full screen, unaware of Presentation Manager"); - else if(!header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && - header.module_flags.HasFlag(ModuleFlags.PMCompatible)) - sb.AppendLine("\tApplication is aware of Presentation Manager, but doesn't use it"); - else if(header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && - header.module_flags.HasFlag(ModuleFlags.PMCompatible)) - sb.AppendLine("\tApplication uses Presentation Manager"); - break; - case TargetOS.Windows: - case TargetOS.Win32: - case TargetOS.Unknown: - switch(header.os_type) - { - case TargetOS.Windows: - case TargetOS.Unknown: - sb.AppendLine("\t16-bit Windows application"); - break; - case TargetOS.Win32: - sb.AppendLine("\t32-bit Windows application"); - break; - } + StringBuilder sb = new StringBuilder(); + sb.Append(BaseExecutable.Information); + sb.AppendLine(Header.signature == SIGNATURE16 ? "Linear Executable (LE):" : "Linear eXecutable (LX):"); + if(!string.IsNullOrEmpty(ModuleName)) sb.AppendFormat("\tModule name: {0}", ModuleName).AppendLine(); + if(!string.IsNullOrEmpty(ModuleDescription)) + sb.AppendFormat("\tModule description: {0}", ModuleDescription).AppendLine(); - if(header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && - !header.module_flags.HasFlag(ModuleFlags.PMCompatible)) - sb.AppendLine("\tApplication is full screen, unaware of Windows"); - else if(!header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && - header.module_flags.HasFlag(ModuleFlags.PMCompatible)) - sb.AppendLine("\tApplication is aware of Windows, but doesn't use it"); - else if(header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && - header.module_flags.HasFlag(ModuleFlags.PMCompatible)) - sb.AppendLine("\tApplication uses Windows"); - break; - case TargetOS.DOS: - sb.AppendLine("\tDOS application"); - if(header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && - !header.module_flags.HasFlag(ModuleFlags.PMCompatible)) - sb.AppendLine("\tApplication is full screen, unaware of Windows"); - else if(!header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && - header.module_flags.HasFlag(ModuleFlags.PMCompatible)) - sb.AppendLine("\tApplication is aware of Windows, but doesn't use it"); - else if(header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && - header.module_flags.HasFlag(ModuleFlags.PMCompatible)) - sb.AppendLine("\tApplication uses Windows"); - break; - default: - sb.AppendFormat("\tApplication for unknown OS {0}", (ushort)header.os_type).AppendLine(); - break; + switch(Header.os_type) + { + case TargetOS.OS2: + sb.AppendLine("\tOS/2 application"); + if(Header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && + !Header.module_flags.HasFlag(ModuleFlags.PMCompatible)) + sb.AppendLine("\tApplication is full screen, unaware of Presentation Manager"); + else if(!Header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && + Header.module_flags.HasFlag(ModuleFlags.PMCompatible)) + sb.AppendLine("\tApplication is aware of Presentation Manager, but doesn't use it"); + else if(Header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && + Header.module_flags.HasFlag(ModuleFlags.PMCompatible)) + sb.AppendLine("\tApplication uses Presentation Manager"); + break; + case TargetOS.Windows: + case TargetOS.Win32: + case TargetOS.Unknown: + switch(Header.os_type) + { + case TargetOS.Windows: + case TargetOS.Unknown: + sb.AppendLine("\t16-bit Windows application"); + break; + case TargetOS.Win32: + sb.AppendLine("\t32-bit Windows application"); + break; + } + + if(Header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && + !Header.module_flags.HasFlag(ModuleFlags.PMCompatible)) + sb.AppendLine("\tApplication is full screen, unaware of Windows"); + else if(!Header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && + Header.module_flags.HasFlag(ModuleFlags.PMCompatible)) + sb.AppendLine("\tApplication is aware of Windows, but doesn't use it"); + else if(Header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && + Header.module_flags.HasFlag(ModuleFlags.PMCompatible)) + sb.AppendLine("\tApplication uses Windows"); + break; + case TargetOS.DOS: + sb.AppendLine("\tDOS application"); + if(Header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && + !Header.module_flags.HasFlag(ModuleFlags.PMCompatible)) + sb.AppendLine("\tApplication is full screen, unaware of Windows"); + else if(!Header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && + Header.module_flags.HasFlag(ModuleFlags.PMCompatible)) + sb.AppendLine("\tApplication is aware of Windows, but doesn't use it"); + else if(Header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && + Header.module_flags.HasFlag(ModuleFlags.PMCompatible)) + sb.AppendLine("\tApplication uses Windows"); + break; + default: + sb.AppendFormat("\tApplication for unknown OS {0}", (ushort)Header.os_type).AppendLine(); + break; + } + + sb.AppendFormat("\tByte ordering: {0}", Header.byte_order == 1 ? "Big-endian" : "Little-Endian") + .AppendLine(); + sb.AppendFormat("\tWord ordering: {0}", Header.word_order == 1 ? "Big-endian" : "Little-Endian") + .AppendLine(); + sb.AppendFormat("\tFormat level: {0}.{1}", Header.format_major, Header.format_minor).AppendLine(); + sb.AppendFormat("\tExecutable version: {0}.{1}", Header.module_major, Header.module_minor).AppendLine(); + + switch(Header.cpu_type) + { + case TargetCpu.i286: + sb.AppendLine("\tExecutable requires at least an 80286 processor to run."); + break; + case TargetCpu.i386: + sb.AppendLine("\tExecutable requires at least an 80386 processor to run."); + break; + case TargetCpu.i486: + sb.AppendLine("\tExecutable requires at least an 80486 processor to run."); + break; + case TargetCpu.Pentium: + sb.AppendLine("\tExecutable requires at least a Pentium processor to run."); + break; + case TargetCpu.i860: + sb.AppendLine("\tExecutable requires at least an Intel 860 processor to run."); + break; + case TargetCpu.N11: + sb.AppendLine("\tExecutable requires at least an Intel N11 processor to run."); + break; + case TargetCpu.MIPS1: + sb.AppendLine("\tExecutable requires at least a MIPS I processor to run."); + break; + case TargetCpu.MIPS2: + sb.AppendLine("\tExecutable requires at least a MIPS II processor to run."); + break; + case TargetCpu.MIPS3: + sb.AppendLine("\tExecutable requires at least a MIPS III processor to run."); + break; + default: + sb.AppendFormat("\tExecutable requires unknown cpu with type code {0} to run.", + (ushort)Header.cpu_type).AppendLine(); + break; + } + + if(Header.module_flags.HasFlag(ModuleFlags.PerProcessLibrary)) + sb.AppendLine("\tLibrary should be initialized per-process."); + if(Header.module_flags.HasFlag(ModuleFlags.PerProcessTermination)) + sb.AppendLine("\tLibrary should be terminated per-process."); + if(Header.module_flags.HasFlag(ModuleFlags.InternalFixups)) + sb.AppendLine("\tInternal fixups have been applied."); + if(Header.module_flags.HasFlag(ModuleFlags.ExternalFixups)) + sb.AppendLine("\tExternal fixups have been applied."); + if(Header.module_flags.HasFlag(ModuleFlags.NotLoadable)) + sb.AppendLine("\tExecutable is not loadable, it contains errors or is still being linked."); + + if(Header.module_flags.HasFlag(ModuleFlags.VirtualDeviceDriver)) + sb.AppendLine("\tExecutable is a driver for a virtual device."); + else if(Header.module_flags.HasFlag(ModuleFlags.PhysicalDeviceDriver)) + sb.AppendLine("\tExecutable is a driver for a physical device."); + else if(Header.module_flags.HasFlag(ModuleFlags.ProtectedMemoryLibrary)) + sb.AppendLine("\tExecutable is a protected mode library."); + else if(Header.module_flags.HasFlag(ModuleFlags.Library)) sb.AppendLine("\tExecutable is a library."); + + sb.AppendFormat("\tThis executable contains {0} pages", Header.module_pages_no).AppendLine(); + sb.AppendFormat("\tObject number to which the Entry Address is relative: {0}", Header.eip_object) + .AppendLine(); + sb.AppendFormat("\tEntry address of module: {0:X8}h", Header.eip).AppendLine(); + sb.AppendFormat("\tObject number to which the ESP is relative: {0}", Header.esp_object).AppendLine(); + sb.AppendFormat("\tStarting stack address of module: {0:X8}h", Header.esp).AppendLine(); + sb.AppendFormat("\tOne page is {0} bytes", Header.page_size).AppendLine(); + sb + .AppendFormat(Header.signature == SIGNATURE16 ? "\tLast page size: {0} bytes" : "\tShift left bits for page offsets: {0}", + Header.page_off_shift).AppendLine(); + sb.AppendFormat("\tTotal size of the fixup information: {0}", Header.fixup_size).AppendLine(); + sb.AppendFormat("\tChecksum for fixup information: 0x{0:X8}", Header.fixup_checksum).AppendLine(); + sb.AppendFormat("\tMemory resident tables are {0} bytes long", Header.loader_size).AppendLine(); + sb.AppendFormat("\tChecksum for loader section: 0x{0:X8}", Header.loader_checksum).AppendLine(); + sb.AppendFormat("\tObject table starts at {0} and contains {1} objects", Header.obj_table_off, + Header.obj_no).AppendLine(); + sb.AppendFormat("\tObject page table starts at {0}", Header.obj_page_table_off).AppendLine(); + sb.AppendFormat("\tObject iterated pages starts at {0}", Header.obj_iter_pages_off).AppendLine(); + sb.AppendFormat("\tResources table starts at {0} and contains {1} entries", Header.resource_table_off, + Header.resource_entries).AppendLine(); + sb.AppendFormat("\tResident name table starts at {0}", Header.resident_names_off).AppendLine(); + sb.AppendFormat("\tEntry table starts at {0}", Header.entry_table_off).AppendLine(); + sb.AppendFormat("\tModule format directives table starts at {0} and contains {1} entries", + Header.directives_off, Header.directives_no).AppendLine(); + sb.AppendFormat("\tFixup page table starts at {0}", Header.fixup_page_table_off).AppendLine(); + sb.AppendFormat("\tFixup record table starts at {0}", Header.fixup_record_table_off).AppendLine(); + sb.AppendFormat("\tImport module name table starts at {0} and contains {1} entries", + Header.import_module_table_off, Header.import_module_entries).AppendLine(); + sb.AppendFormat("\tImport procedure name table starts at {0}", Header.import_proc_table_off) + .AppendLine(); + sb.AppendFormat("\tPer-page checksum table starts at {0}", Header.perpage_checksum_off).AppendLine(); + sb.AppendFormat("\tData pages start at {0}", Header.data_pages_off).AppendLine(); + sb.AppendFormat("\t{0} pages to preload in this executable", Header.preload_pages_no).AppendLine(); + sb.AppendFormat("\tNon-resident names table starts at {0} and runs for {1} bytes", + Header.nonresident_name_table_off, Header.nonresident_name_table_len).AppendLine(); + sb.AppendFormat("\tNon-resident name table checksum: 0x{0:X8}", Header.nonresident_name_table_checksum) + .AppendLine(); + sb.AppendFormat("\tThe auto data segment object number: {0}", Header.auto_ds_obj_no).AppendLine(); + sb.AppendFormat("\tDebug information starts at {0} and is {1} bytes", Header.debug_info_off, + Header.debug_info_len).AppendLine(); + sb.AppendFormat("\tInstance pages in preload section: {0}", Header.instance_preload_no).AppendLine(); + sb.AppendFormat("\tInstance pages in demand section: {0}", Header.instance_demand_no).AppendLine(); + sb.AppendFormat("\tHeap size added to the auto ds object: {0}", Header.heap_size).AppendLine(); + if(Header.signature == SIGNATURE16 && Header.win_res_len > 0) + { + sb.AppendFormat("\tWindows resource starts at {0} and runs for {1} bytes", Header.win_res_off, + Header.win_res_len).AppendLine(); + sb.AppendFormat("\tDevice ID: {0}", Header.device_id).AppendLine(); + sb.AppendFormat("\tDDK version {0}.{1}", Header.ddk_major, Header.ddk_minor).AppendLine(); + } + + if(ImportedNames != null) + { + sb.AppendLine("\tImported names:"); + foreach(string name in ImportedNames) sb.AppendFormat("\t\t{0}", name).AppendLine(); + } + + if(ResidentNames != null) + { + sb.AppendLine("\tResident names:"); + foreach(NE.ResidentName name in ResidentNames) + sb.AppendFormat("\t\t{0} at index {1}", name.name, name.entryTableIndex).AppendLine(); + } + + if(NonResidentNames != null) + { + sb.AppendLine("\tNon-resident names:"); + foreach(NE.ResidentName name in NonResidentNames) + sb.AppendFormat("\t\t{0} at index {1}", name.name, name.entryTableIndex).AppendLine(); + } + + sb.AppendLine("\tObjects:"); + for(int i = 0; i < objectTableEntries.Length; i++) + { + sb.AppendFormat("\t\tObject {0}:", i + 1).AppendLine(); + sb.AppendFormat("\t\t\tVirtual size: {0}", objectTableEntries[i].VirtualSize).AppendLine(); + sb.AppendFormat("\t\t\tRelocation base address: {0:X8}h", + objectTableEntries[i].RelocationBaseAddress).AppendLine(); + sb.AppendFormat("\t\t\tFlags: {0}", objectTableEntries[i].ObjectFlags).AppendLine(); + sb.AppendFormat("\t\t\tFirst page table index: {0}", objectTableEntries[i].PageTableIndex) + .AppendLine(); + sb.AppendFormat("\t\t\tHas {0} pages", objectTableEntries[i].PageTableEntries).AppendLine(); + if(Header.signature == SIGNATURE16) + sb.AppendFormat("\t\t\tName: \"{0}\"", + StringHandlers.CToString(objectTableEntries[i].Name).Trim()).AppendLine(); + } + + sb.AppendLine("\tPages:"); + for(int i = 0; i < objectPageTableEntries.Length; i++) + { + sb.AppendFormat("\t\tPage {0}:", i + 1).AppendLine(); + sb.AppendFormat("\t\t\tFlags: {0}", objectPageTableEntries[i].Flags).AppendLine(); + sb.AppendFormat("\t\t\tSize: {0} bytes", objectPageTableEntries[i].DataSize).AppendLine(); + sb.AppendFormat("\t\t\tRelative offset: {0}", objectPageTableEntries[i].PageDataOffset) + .AppendLine(); + } + + sb.AppendLine("\tSections:"); + int count = 0; + foreach(Segment section in Segments) + { + sb.AppendFormat("\t\tSection {0}:", count).AppendLine(); + sb.AppendFormat("\t\t\tName: {0}", section.Name).AppendLine(); + sb.AppendFormat("\t\t\tFlags: {0}", section.Flags).AppendLine(); + sb.AppendFormat("\t\t\tOffset: {0}", section.Offset).AppendLine(); + sb.AppendFormat("\t\t\tSize: {0} bytes", section.Size).AppendLine(); + count++; + } + + if(resources.Length <= 0) return sb.ToString(); + + { + sb.AppendLine("\tResources:"); + for(int i = 0; i < resources.Length; i++) + sb.AppendFormat("\t\tType {0}, id {1}, {2} bytes, object {3} at offset {4}", resources[i].type, + resources[i].id, resources[i].size, resources[i].obj_no, resources[i].offset) + .AppendLine(); + } + + return sb.ToString(); + } + } + + static NE.ResidentName[] GetResidentStrings(Stream stream, uint neStart, uint tableOff) + { + List names = new List(); + byte stringSize; + byte[] nameString; + byte[] DW = new byte[2]; + + long oldPosition = stream.Position; + + stream.Position = neStart + tableOff; + while(true) + { + stringSize = (byte)stream.ReadByte(); + + if(stringSize == 0) break; + + nameString = new byte[stringSize]; + stream.Read(nameString, 0, stringSize); + stream.Read(DW, 0, 2); + + names.Add(new NE.ResidentName + { + name = Encoding.ASCII.GetString(nameString), + entryTableIndex = BitConverter.ToUInt16(DW, 0) + }); } - sb.AppendFormat("\tByte ordering: {0}", header.byte_order == 1 ? "Big-endian" : "Little-Endian") - .AppendLine(); - sb.AppendFormat("\tWord ordering: {0}", header.word_order == 1 ? "Big-endian" : "Little-Endian") - .AppendLine(); - sb.AppendFormat("\tFormat level: {0}", header.format_level).AppendLine(); - sb.AppendFormat("\tExecutable version: {0}", header.module_version).AppendLine(); + stream.Position = oldPosition; - switch(header.cpu_type) - { - case TargetCpu.i286: - sb.AppendLine("\tExecutable requires at least an 80286 processor to run."); - break; - case TargetCpu.i386: - sb.AppendLine("\tExecutable requires at least an 80386 processor to run."); - break; - case TargetCpu.i486: - sb.AppendLine("\tExecutable requires at least an 80486 processor to run."); - break; - case TargetCpu.Pentium: - sb.AppendLine("\tExecutable requires at least a Pentium processor to run."); - break; - case TargetCpu.i860: - sb.AppendLine("\tExecutable requires at least an Intel 860 processor to run."); - break; - case TargetCpu.N11: - sb.AppendLine("\tExecutable requires at least an Intel N11 processor to run."); - break; - case TargetCpu.MIPS1: - sb.AppendLine("\tExecutable requires at least a MIPS I processor to run."); - break; - case TargetCpu.MIPS2: - sb.AppendLine("\tExecutable requires at least a MIPS II processor to run."); - break; - case TargetCpu.MIPS3: - sb.AppendLine("\tExecutable requires at least a MIPS III processor to run."); - break; - default: - sb.AppendFormat("\tExecutable requires unknown cpu with type code {0} to run.", - (ushort)header.cpu_type).AppendLine(); - break; - } - - if(header.module_flags.HasFlag(ModuleFlags.PerProcessLibrary)) - sb.AppendLine("Library should be initialized per-process."); - if(header.module_flags.HasFlag(ModuleFlags.PerProcessTermination)) - sb.AppendLine("Library should be terminated per-process."); - if(header.module_flags.HasFlag(ModuleFlags.InternalFixups)) - sb.AppendLine("Internal fixups have been applied."); - if(header.module_flags.HasFlag(ModuleFlags.ExternalFixups)) - sb.AppendLine("External fixups have been applied."); - if(header.module_flags.HasFlag(ModuleFlags.NotLoadable)) - sb.AppendLine("Executable is not loadable, it contains errors or is still being linked."); - - if(header.module_flags.HasFlag(ModuleFlags.VirtualDeviceDriver)) - sb.AppendLine("Executable is a driver for a virtual device."); - else if(header.module_flags.HasFlag(ModuleFlags.PhysicalDeviceDriver)) - sb.AppendLine("Executable is a driver for a physical device."); - else if(header.module_flags.HasFlag(ModuleFlags.ProtectedMemoryLibrary)) - sb.AppendLine("Executable is a protected mode library."); - else if(header.module_flags.HasFlag(ModuleFlags.Library)) - sb.AppendLine("Executable is a library."); - - sb.AppendFormat("\tThis executable contains {0} pages", header.module_pages_no) - .AppendLine(); - sb.AppendFormat("\tObject number to which the Entry Address is relative: {0}", header.eip_object) - .AppendLine(); - sb.AppendFormat("\tEntry address of module: {0:X8}h", header.eip).AppendLine(); - sb.AppendFormat("\tObject number to which the ESP is relative: {0}", header.esp_object).AppendLine(); - sb.AppendFormat("\tStarting stack address of module: {0:X8}h", header.esp).AppendLine(); - sb.AppendFormat("\tOne page is {0} bytes", header.page_size).AppendLine(); - sb.AppendFormat("\tShift left bits for page offsets: {0}", header.page_off_shift).AppendLine(); - sb.AppendFormat("\tTotal size of the fixup information: {0}", header.fixup_size).AppendLine(); - sb.AppendFormat("\tChecksum for fixup information: 0x{0:X8}", header.fixup_checksum).AppendLine(); - sb.AppendFormat("\tMemory resident tables are {0} bytes long", header.loader_size).AppendLine(); - sb.AppendFormat("\tChecksum for loader section: 0x{0:X8}", header.loader_checksum).AppendLine(); - sb.AppendFormat("\tObject table starts at {0} and contains {1} objects", header.obj_table_off, - header.obj_no).AppendLine(); - sb.AppendFormat("\tObject page table starts at {0}", header.obj_page_table_off).AppendLine(); - sb.AppendFormat("\tObject iterated pages starts at {0}", header.obj_iter_pages_off).AppendLine(); - sb.AppendFormat("\tResources table starts at {0} and contains {1} entries", header.resource_table_off, - header.resource_entries).AppendLine(); - sb.AppendFormat("\tResident name table starts at {0}", header.resident_names_off).AppendLine(); - sb.AppendFormat("\tEntry table starts at {0}", header.entry_table_off).AppendLine(); - sb.AppendFormat("\tModule format directives table starts at {0} and contains {1} entries", - header.directives_off, header.directives_no).AppendLine(); - sb.AppendFormat("\tFixup page table starts at {0}", header.fixup_page_table_off).AppendLine(); - sb.AppendFormat("\tFixup record table starts at {0}", header.fixup_record_table_off).AppendLine(); - sb.AppendFormat("\tImport module name table starts at {0} and contains {1} entries", - header.import_module_table_off, header.import_module_entries).AppendLine(); - sb.AppendFormat("\tImport procedure name table starts at {0}", header.import_proc_table_off).AppendLine(); - sb.AppendFormat("\tPer-page checksum table starts at {0}", header.perpage_checksum_off).AppendLine(); - sb.AppendFormat("\tData pages start at {0}", header.data_pages_off).AppendLine(); - sb.AppendFormat("\t{0} pages to preload in this executable", header.preload_pages_no).AppendLine(); - sb.AppendFormat("\tNon-resident names table starts at {0} and runs for {1} bytes", - header.nonresident_name_table_off, header.nonresident_name_table_len).AppendLine(); - sb.AppendFormat("\tNon-resident name table checksum: 0x{0:X8}", header.nonresident_name_table_checksum) - .AppendLine(); - sb.AppendFormat("\tThe auto data segment object number: {0}", header.auto_ds_obj_no).AppendLine(); - sb.AppendFormat("\tDebug information starts at {0} and is {1} bytes", header.debug_info_off, - header.debug_info_len).AppendLine(); - sb.AppendFormat("\tInstance pages in preload section: {0}", header.instance_preload_no).AppendLine(); - sb.AppendFormat("\tInstance pages in demand section: {0}", header.instance_demand_no).AppendLine(); - sb.AppendFormat("\tHeap size added to the auto ds object: {0}", header.heap_size).AppendLine(); - return sb.ToString(); + return names.Count > 0 ? names.ToArray() : null; } } } \ No newline at end of file diff --git a/libexeinfo/LX/LX.cs b/libexeinfo/LX/LX.cs index add332c..ea2a376 100644 --- a/libexeinfo/LX/LX.cs +++ b/libexeinfo/LX/LX.cs @@ -27,21 +27,32 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Runtime.InteropServices; +using System.Text; namespace libexeinfo { /// /// Represents a Microsoft/IBM Linear EXecutable /// - // TODO: Big-endian (really needed?) public partial class LX : IExecutable { - MZ baseExecutable; + MZ BaseExecutable; /// /// Header for this executable /// - LXHeader header; + LXHeader Header; + string[] ImportedNames; + public NE.ResidentName[] ImportNames; + string ModuleDescription; + string ModuleName; + public NE.ResidentName[] NonResidentNames; + ObjectPageTableEntry[] objectPageTableEntries; + ObjectTableEntry[] objectTableEntries; + public NE.ResidentName[] ResidentNames; + ResourceTableEntry[] resources; + public NE.Version WinVersion; /// /// Initializes a new instance of the class. @@ -76,50 +87,52 @@ namespace libexeinfo /// /// The that contains the executable represented by this instance /// - public Stream BaseStream { get; } + public Stream BaseStream { get; } public bool IsBigEndian { get; private set; } public bool Recognized { get; private set; } public string Type { get; private set; } - public IEnumerable Architectures => new[] {CpuToArchitecture(header.cpu_type)}; + public IEnumerable Architectures => new[] {CpuToArchitecture(Header.cpu_type)}; public OperatingSystem RequiredOperatingSystem { get; private set; } - public IEnumerable Strings { get; } - public IEnumerable Segments { get; } + public IEnumerable Strings { get; private set; } + public IEnumerable Segments { get; private set; } + // TODO: How to know VxD structure offset void Initialize() { Recognized = false; if(BaseStream == null) return; - baseExecutable = new MZ(BaseStream); - if(!baseExecutable.Recognized) return; + BaseExecutable = new MZ(BaseStream); + if(!BaseExecutable.Recognized) return; - if(baseExecutable.Header.new_offset >= BaseStream.Length) return; + if(BaseExecutable.Header.new_offset >= BaseStream.Length) return; - BaseStream.Seek(baseExecutable.Header.new_offset, SeekOrigin.Begin); + BaseStream.Seek(BaseExecutable.Header.new_offset, SeekOrigin.Begin); byte[] buffer = new byte[Marshal.SizeOf(typeof(LXHeader))]; BaseStream.Read(buffer, 0, buffer.Length); IntPtr hdrPtr = Marshal.AllocHGlobal(buffer.Length); Marshal.Copy(buffer, 0, hdrPtr, buffer.Length); - header = (LXHeader)Marshal.PtrToStructure(hdrPtr, typeof(LXHeader)); + Header = (LXHeader)Marshal.PtrToStructure(hdrPtr, typeof(LXHeader)); Marshal.FreeHGlobal(hdrPtr); - Recognized = header.signature == SIGNATURE || header.signature == SIGNATURE16; + Recognized = Header.signature == SIGNATURE || Header.signature == SIGNATURE16; if(!Recognized) return; - Type = header.signature == SIGNATURE16 ? "Linear Executable (LE)" : "Linear eXecutable (LX)"; - IsBigEndian = header.byte_order == 1 || header.word_order == 1; + Type = Header.signature == SIGNATURE16 ? "Linear Executable (LE)" : "Linear eXecutable (LX)"; + IsBigEndian = Header.byte_order == 1 || Header.word_order == 1; + List strings = new List(); OperatingSystem reqOs = new OperatingSystem(); - switch(header.os_type) + switch(Header.os_type) { case TargetOS.OS2: reqOs.Name = "OS/2"; - if(header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && - !header.module_flags.HasFlag(ModuleFlags.PMCompatible) || - !header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && - header.module_flags.HasFlag(ModuleFlags.PMCompatible)) reqOs.Subsystem = "Console"; - else if(header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && - header.module_flags.HasFlag(ModuleFlags.PMCompatible)) + if(Header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && + !Header.module_flags.HasFlag(ModuleFlags.PMCompatible) || + !Header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && + Header.module_flags.HasFlag(ModuleFlags.PMCompatible)) reqOs.Subsystem = "Console"; + else if(Header.module_flags.HasFlag(ModuleFlags.PMIncompatible) && + Header.module_flags.HasFlag(ModuleFlags.PMCompatible)) reqOs.Subsystem = "Presentation Manager"; break; case TargetOS.Windows: @@ -131,11 +144,193 @@ namespace libexeinfo reqOs.Name = "Windows"; break; default: - reqOs.Name = $"Unknown code {(ushort)header.os_type}"; + reqOs.Name = $"Unknown code {(ushort)Header.os_type}"; break; } RequiredOperatingSystem = reqOs; + + if(Header.resident_names_off != 0) + { + ResidentNames = + GetResidentStrings(BaseStream, BaseExecutable.Header.new_offset, Header.resident_names_off); + + if(ResidentNames.Length >= 1) + { + ModuleName = ResidentNames[0].name; + + if(ResidentNames.Length > 1) + { + NE.ResidentName[] newResidentNames = new NE.ResidentName[ResidentNames.Length - 1]; + Array.Copy(ResidentNames, 1, newResidentNames, 0, ResidentNames.Length - 1); + ResidentNames = newResidentNames; + } + else ResidentNames = null; + } + } + + if(Header.nonresident_name_table_len > 0) + { + NonResidentNames = GetResidentStrings(BaseStream, 0, Header.nonresident_name_table_off); + + if(NonResidentNames.Length >= 1) + { + ModuleDescription = NonResidentNames[0].name; + + if(NonResidentNames.Length > 1) + { + NE.ResidentName[] newNonResidentNames = new NE.ResidentName[NonResidentNames.Length - 1]; + Array.Copy(NonResidentNames, 1, newNonResidentNames, 0, NonResidentNames.Length - 1); + NonResidentNames = newNonResidentNames; + } + else NonResidentNames = null; + } + } + + if(Header.import_module_table_off != 0 && Header.import_module_entries > 0) + { + BaseStream.Position = Header.import_module_table_off + BaseExecutable.Header.new_offset; + ImportedNames = new string[Header.import_module_entries]; + for(int i = 0; i < Header.import_module_entries; i++) + { + int len = BaseStream.ReadByte(); + buffer = new byte[len]; + BaseStream.Read(buffer, 0, len); + ImportedNames[i] = Encoding.ASCII.GetString(buffer); + } + } + + if(!string.IsNullOrEmpty(ModuleName)) strings.Add(ModuleName); + if(!string.IsNullOrEmpty(ModuleDescription)) strings.Add(ModuleDescription); + + objectTableEntries = new ObjectTableEntry[Header.obj_no]; + objectPageTableEntries = new ObjectPageTableEntry[Header.module_pages_no]; + + BaseStream.Position = Header.obj_table_off + BaseExecutable.Header.new_offset; + buffer = new byte[Marshal.SizeOf(typeof(ObjectTableEntry))]; + for(int i = 0; i < Header.obj_no; i++) + { + BaseStream.Read(buffer, 0, buffer.Length); + objectTableEntries[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian(buffer); + } + + BaseStream.Position = Header.obj_page_table_off + BaseExecutable.Header.new_offset; + + if(Header.signature == SIGNATURE16) + { + buffer = new byte[Marshal.SizeOf(typeof(ObjectPageTableEntry16))]; + for(int i = 0; i < Header.module_pages_no; i++) + { + BaseStream.Read(buffer, 0, buffer.Length); + ObjectPageTableEntry16 page16 = + BigEndianMarshal.ByteArrayToStructureLittleEndian(buffer); + + int pageNo = (page16.High << 8) + page16.Low; + + objectPageTableEntries[i] = new ObjectPageTableEntry + { + DataSize = (ushort)Header.page_size, + Flags = (PageTableAttributes)page16.Flags, + PageDataOffset = (uint)((pageNo - 1) * Header.page_size) + }; + } + } + else + { + buffer = new byte[Marshal.SizeOf(typeof(ObjectPageTableEntry))]; + for(int i = 0; i < Header.module_pages_no; i++) + { + BaseStream.Read(buffer, 0, buffer.Length); + objectPageTableEntries[i] = + BigEndianMarshal.ByteArrayToStructureLittleEndian(buffer); + } + } + + int debugSections = 0; + int winrsrcSections = 0; + + if(Header.debug_info_len > 0) debugSections = 1; + if(Header.win_res_len > 0) winrsrcSections = 1; + + Segment[] sections = new Segment[objectTableEntries.Length + debugSections + winrsrcSections]; + for(int i = 0; i < objectTableEntries.Length; i++) + { + sections[i] = new Segment {Flags = $"{objectTableEntries[i].ObjectFlags}"}; + if(objectTableEntries[i].ObjectFlags.HasFlag(ObjectFlags.Resource)) sections[i].Name = ".rsrc"; + else if(objectTableEntries[i].ObjectFlags.HasFlag(ObjectFlags.Executable)) sections[i].Name = ".text"; + else if(!objectTableEntries[i].ObjectFlags.HasFlag(ObjectFlags.Writable)) sections[i].Name = ".rodata"; + else if(StringHandlers.CToString(objectTableEntries[i].Name).ToLower() == "bss") + sections[i].Name = ".bss"; + else if(!string.IsNullOrWhiteSpace(StringHandlers.CToString(objectTableEntries[i].Name).Trim())) + sections[i].Name = StringHandlers.CToString(objectTableEntries[i].Name).Trim(); + else sections[i].Name = ".data"; + + if(objectTableEntries[i].PageTableEntries == 0 || + objectTableEntries[i].PageTableIndex > objectPageTableEntries.Length) + { + sections[i].Size = objectTableEntries[i].VirtualSize; + continue; + } + + int shift = (int)(Header.signature == SIGNATURE16 ? 0 : Header.page_off_shift); + + if(objectPageTableEntries[objectTableEntries[i].PageTableIndex - 1] + .Flags.HasFlag(PageTableAttributes.IteratedDataPage)) + sections[i].Offset = + (objectPageTableEntries[objectTableEntries[i].PageTableIndex - 1].PageDataOffset << shift) + + Header.obj_iter_pages_off; + else if(objectPageTableEntries[objectTableEntries[i].PageTableIndex - 1] + .Flags.HasFlag(PageTableAttributes.LegalPhysicalPage)) + sections[i].Offset = + (objectPageTableEntries[objectTableEntries[i].PageTableIndex - 1].PageDataOffset << shift) + + Header.data_pages_off; + else sections[i].Offset = 0; + + sections[i].Size = 0; + for(int j = 0; j < objectTableEntries[i].PageTableEntries; j++) + sections[i].Size += objectPageTableEntries[j + objectTableEntries[i].PageTableIndex - 1].DataSize; + + if(sections[i].Offset + sections[i].Size > BaseStream.Length) + sections[i].Size = BaseStream.Length - sections[i].Offset; + } + + if(winrsrcSections > 0) + sections[sections.Length - debugSections - winrsrcSections] = new Segment + { + Name = ".rsrc", + Size = Header.win_res_len, + Offset = Header.win_res_off + }; + + if(debugSections > 0) + sections[sections.Length - debugSections] = new Segment + { + Name = ".debug", + Size = Header.debug_info_len, + Offset = Header.debug_info_off + }; + + // It only contains a RT_VERSION resource prefixed by some 12-byte header I can't find information about, so let's just skip it. + if(winrsrcSections > 0) + { + buffer = new byte[Header.win_res_len]; + BaseStream.Position = Header.win_res_off + 12; + BaseStream.Read(buffer, 0, buffer.Length); + WinVersion = new NE.Version(buffer); + strings.AddRange(from s in WinVersion.StringsByLanguage from k in s.Value select k.Value); + } + + resources = new ResourceTableEntry[Header.resource_entries]; + BaseStream.Position = Header.resource_table_off + BaseExecutable.Header.new_offset; + buffer = new byte[Marshal.SizeOf(typeof(ResourceTableEntry))]; + for(int i = 0; i < resources.Length; i++) + { + BaseStream.Read(buffer, 0, buffer.Length); + resources[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian(buffer); + } + + Segments = sections; + Strings = strings; } /// diff --git a/libexeinfo/LX/Structs.cs b/libexeinfo/LX/Structs.cs index 64d46c0..a7f31a6 100644 --- a/libexeinfo/LX/Structs.cs +++ b/libexeinfo/LX/Structs.cs @@ -25,6 +25,7 @@ // THE SOFTWARE. using System.Runtime.InteropServices; +using libexeinfo.Os2; namespace libexeinfo { @@ -51,7 +52,8 @@ namespace libexeinfo /// /// Format level, should be 0 /// - public uint format_level; + public ushort format_minor; + public ushort format_major; /// /// Type of CPU required by this executable to run /// @@ -63,7 +65,8 @@ namespace libexeinfo /// /// Executable version /// - public uint module_version; + public ushort module_minor; + public ushort module_major; /// /// Executable flags /// @@ -94,6 +97,7 @@ namespace libexeinfo public uint page_size; /// /// Shift left bits for page offsets + /// LE: Last page size in bytes /// public uint page_off_shift; /// @@ -139,7 +143,7 @@ namespace libexeinfo /// /// Resident name table offset /// - public uint resident_names_off; + public ushort resident_names_off; /// /// Entry table offset /// @@ -220,6 +224,55 @@ namespace libexeinfo /// Heap size added to the auto ds object /// public uint heap_size; + // Following is only defined for Windows VxDs + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] + public byte[] reserved; + public uint win_res_off; + public uint win_res_len; + public ushort device_id; + public byte ddk_minor; + public byte ddk_major; + } + + [StructLayout(LayoutKind.Sequential, Pack = 2)] + struct ObjectTableEntry + { + public uint VirtualSize; + public uint RelocationBaseAddress; + public ObjectFlags ObjectFlags; + public uint PageTableIndex; + public uint PageTableEntries; + /// + /// Only used in LE + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] Name; + } + + [StructLayout(LayoutKind.Sequential, Pack = 2)] + struct ObjectPageTableEntry + { + public uint PageDataOffset; + public ushort DataSize; + public PageTableAttributes Flags; + } + + [StructLayout(LayoutKind.Sequential, Pack = 2)] + struct ObjectPageTableEntry16 + { + public ushort High; + public byte Low; + public PageTableAttributes16 Flags; + } + + [StructLayout(LayoutKind.Sequential, Pack = 2)] + struct ResourceTableEntry + { + public ResourceTypes type; + public ushort id; + public uint size; + public ushort obj_no; + public uint offset; } } } \ No newline at end of file