Add full decoding of LE and LX objects, tables, and resource tables, plus viewer for LE VxD version resource.

This commit is contained in:
2018-03-08 16:50:25 +00:00
parent 4e130af164
commit 26007b6b8b
10 changed files with 751 additions and 205 deletions

View File

@@ -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<string, Dictionary<string, string>> 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<string, string> 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:");

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<TabPage Text="VxD Version" xmlns="http://schema.picoe.ca/eto.forms" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackLayout Orientation="Vertical">
<StackLayoutItem HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Expand="True">
<Panel ID="pnlVersion"/>
</StackLayoutItem>
</StackLayout>
</TabPage>

View File

@@ -0,0 +1,51 @@
//
// TabLeVxdVersion.xeto.cs
//
// Author:
// Natalia Portillo <claunia@claunia.com>
//
// 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);
}
}
}

View File

@@ -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)
{

View File

@@ -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
{

View File

@@ -19,10 +19,12 @@
</ItemGroup>
<ItemGroup>
<Folder Include="GEM\" />
<Folder Include="LE" />
<Folder Include="NE" />
<Folder Include="NE\" />
<Folder Include="Win16\" />
<Folder Include="Os2\" />
<Folder Include="Windows\" />
<Folder Include="LE\" />
</ItemGroup>
</Project>

View File

@@ -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
{
/// <summary>
/// Offset from preload page section
/// </summary>
LegalPhysicalPage = 0,
/// <summary>
/// Offset from iterated page section
/// </summary>
IteratedDataPage = 1,
Invalid = 2,
Zeroed = 3,
RangeOfPages = 4
}
enum PageTableAttributes16 : byte
{
/// <summary>
/// Offset from preload page section
/// </summary>
LegalPhysicalPage = (byte)PageTableAttributes.LegalPhysicalPage,
/// <summary>
/// Offset from iterated page section
/// </summary>
IteratedDataPage = (byte)PageTableAttributes.IteratedDataPage,
Invalid = (byte)PageTableAttributes.Invalid,
Zeroed = (byte)PageTableAttributes.Zeroed,
RangeOfPages = (byte)PageTableAttributes.RangeOfPages
}
}
}

View File

@@ -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<NE.ResidentName> names = new List<NE.ResidentName>();
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;
}
}
}

View File

@@ -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
{
/// <summary>
/// Represents a Microsoft/IBM Linear EXecutable
/// </summary>
// TODO: Big-endian (really needed?)
public partial class LX : IExecutable
{
MZ baseExecutable;
MZ BaseExecutable;
/// <summary>
/// Header for this executable
/// </summary>
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;
/// <summary>
/// Initializes a new instance of the <see cref="T:libexeinfo.NE" /> class.
@@ -76,50 +87,52 @@ namespace libexeinfo
/// <summary>
/// The <see cref="FileStream" /> that contains the executable represented by this instance
/// </summary>
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<Architecture> Architectures => new[] {CpuToArchitecture(header.cpu_type)};
public IEnumerable<Architecture> Architectures => new[] {CpuToArchitecture(Header.cpu_type)};
public OperatingSystem RequiredOperatingSystem { get; private set; }
public IEnumerable<string> Strings { get; }
public IEnumerable<Segment> Segments { get; }
public IEnumerable<string> Strings { get; private set; }
public IEnumerable<Segment> 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<string> strings = new List<string>();
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<ObjectTableEntry>(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<ObjectPageTableEntry16>(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<ObjectPageTableEntry>(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<ResourceTableEntry>(buffer);
}
Segments = sections;
Strings = strings;
}
/// <summary>

View File

@@ -25,6 +25,7 @@
// THE SOFTWARE.
using System.Runtime.InteropServices;
using libexeinfo.Os2;
namespace libexeinfo
{
@@ -51,7 +52,8 @@ namespace libexeinfo
/// <summary>
/// Format level, should be 0
/// </summary>
public uint format_level;
public ushort format_minor;
public ushort format_major;
/// <summary>
/// Type of CPU required by this executable to run
/// </summary>
@@ -63,7 +65,8 @@ namespace libexeinfo
/// <summary>
/// Executable version
/// </summary>
public uint module_version;
public ushort module_minor;
public ushort module_major;
/// <summary>
/// Executable flags
/// </summary>
@@ -94,6 +97,7 @@ namespace libexeinfo
public uint page_size;
/// <summary>
/// Shift left bits for page offsets
/// LE: Last page size in bytes
/// </summary>
public uint page_off_shift;
/// <summary>
@@ -139,7 +143,7 @@ namespace libexeinfo
/// <summary>
/// Resident name table offset
/// </summary>
public uint resident_names_off;
public ushort resident_names_off;
/// <summary>
/// Entry table offset
/// </summary>
@@ -220,6 +224,55 @@ namespace libexeinfo
/// Heap size added to the auto ds object
/// </summary>
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;
/// <summary>
/// Only used in LE
/// </summary>
[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;
}
}
}