mirror of
https://github.com/claunia/libexeinfo.git
synced 2025-12-16 19:14:24 +00:00
Add full decoding of LE and LX objects, tables, and resource tables, plus viewer for LE VxD version resource.
This commit is contained in:
@@ -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:");
|
||||
|
||||
8
exeinfogui/LE/TabLeVxdVersion.xeto
Normal file
8
exeinfogui/LE/TabLeVxdVersion.xeto
Normal 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>
|
||||
51
exeinfogui/LE/TabLeVxdVersion.xeto.cs
Normal file
51
exeinfogui/LE/TabLeVxdVersion.xeto.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user