Add support for GEOS v1 and v2 executables (resource format is unknown).

This commit is contained in:
2018-03-07 15:55:18 +00:00
parent 7106e39901
commit abd532981a
8 changed files with 940 additions and 51 deletions

View File

@@ -52,6 +52,7 @@ namespace exeinfo
IExecutable lxExe = new LX(args[0]);
IExecutable coffExe = new COFF(args[0]);
IExecutable peExe = new PE(args[0]);
IExecutable geosExe = new Geos(args[0]);
if(neExe.Recognized)
{
@@ -71,8 +72,8 @@ namespace exeinfo
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));
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)
{
@@ -140,10 +141,10 @@ namespace exeinfo
{
recognized = true;
Console.Write(mzExe.Information);
if(((MZ)mzExe).ResourceStream != null || ((MZ)mzExe).ResourceHeader.rsh_vrsn != 0 &&
((MZ)mzExe).ResourceHeader.rsh_vrsn != 1 &&
((MZ)mzExe).ResourceHeader.rsh_vrsn != 4 &&
((MZ)mzExe).ResourceHeader.rsh_vrsn != 5)
if(((MZ)mzExe).ResourceStream != null || ((MZ)mzExe).ResourceHeader.rsh_vrsn != 0 &&
((MZ)mzExe).ResourceHeader.rsh_vrsn != 1 &&
((MZ)mzExe).ResourceHeader.rsh_vrsn != 4 &&
((MZ)mzExe).ResourceHeader.rsh_vrsn != 5)
PrintGemResources(((MZ)mzExe).ResourceHeader, ((MZ)mzExe).ResourceObjectRoots,
((MZ)mzExe).ResourceExtension, ((MZ)mzExe).GemColorIcons);
@@ -158,10 +159,10 @@ namespace exeinfo
{
recognized = true;
Console.Write(stExe.Information);
if(((AtariST)stExe).ResourceStream != null || ((AtariST)stExe).ResourceHeader.rsh_vrsn != 0 &&
((AtariST)stExe).ResourceHeader.rsh_vrsn != 1 &&
((AtariST)stExe).ResourceHeader.rsh_vrsn != 4 &&
((AtariST)stExe).ResourceHeader.rsh_vrsn != 5)
if(((AtariST)stExe).ResourceStream != null || ((AtariST)stExe).ResourceHeader.rsh_vrsn != 0 &&
((AtariST)stExe).ResourceHeader.rsh_vrsn != 1 &&
((AtariST)stExe).ResourceHeader.rsh_vrsn != 4 &&
((AtariST)stExe).ResourceHeader.rsh_vrsn != 5)
PrintGemResources(((AtariST)stExe).ResourceHeader, ((AtariST)stExe).ResourceObjectRoots,
((AtariST)stExe).ResourceExtension, ((AtariST)stExe).GemColorIcons);
@@ -184,12 +185,25 @@ namespace exeinfo
}
}
if(geosExe.Recognized)
{
recognized = true;
Console.Write(geosExe.Information);
if(geosExe.Strings != null && geosExe.Strings.Any())
{
Console.WriteLine("\tStrings:");
foreach(string str in geosExe.Strings) Console.WriteLine("\t\t{0}", str);
}
}
if(!recognized) Console.WriteLine("Executable format not recognized");
}
static void PrintGemResources(GEM.MagiCResourceHeader resourceHeader, IReadOnlyList<GEM.TreeObjectNode> roots,
GEM.GemResourceExtension resourceExtension,
GEM.ColorIcon[] colorIcons)
static void PrintGemResources(GEM.MagiCResourceHeader resourceHeader,
IReadOnlyList<GEM.TreeObjectNode> roots,
GEM.GemResourceExtension resourceExtension,
GEM.ColorIcon[] colorIcons)
{
Console.WriteLine("\t\tGEM Resources:");
Console.WriteLine("\t\t\t{0} OBJECTs start at {1}", resourceHeader.rsh_nobs, resourceHeader.rsh_object);
@@ -234,23 +248,19 @@ namespace exeinfo
case GEM.ObjectTypes.G_IBOX:
Console.WriteLine("{0} ({1} {2}) {3} border, {4} text, {5} interior, {6} fill, {7} mode," + " coordinates ({8},{9}) size {10}x{11}",
node.type, node.flags, node.state,
(GEM.ObjectColors)((node.data & 0xFFFF & GEM.BorderColorMask) >> 12),
(GEM.ObjectColors)((node.data & 0xFFFF & GEM.TextColorMask) >> 8),
(GEM.ObjectColors)((node.data & 0xFFFF & GEM.InsideColorMask) >> 8),
(GEM.ObjectColors)((node.data & 0xFFFF & GEM.BorderColorMask) >> 12),
(GEM.ObjectColors)((node.data & 0xFFFF & GEM.TextColorMask) >> 8),
(GEM.ObjectColors)((node.data & 0xFFFF & GEM.InsideColorMask) >> 8),
(GEM.ObjectFillPattern)((node.data & 0xFFFF & GEM.FillPatternMask) >> 4),
(node.data & 0xFFFF & GEM.TransparentColor) != 0
? "transparent"
: "replace",
(node.data & 0xFFFF & GEM.TransparentColor) != 0 ? "transparent" : "replace",
node.x, node.y, node.width, node.height);
break;
case GEM.ObjectTypes.G_BOXCHAR:
sbyte thickness = (sbyte)((node.data & 0xFF0000) >> 16);
if(thickness < 0) thickStr = $"{thickness * -1} pixels outward thickness";
else if(thickness > 0)
thickStr = $"{thickness} pixels inward thickness";
else
thickStr = "no thickness";
else if(thickness > 0) thickStr = $"{thickness} pixels inward thickness";
else thickStr = "no thickness";
char character =
Claunia.Encoding.Encoding.AtariSTEncoding.GetString(new[]
@@ -262,12 +272,10 @@ namespace exeinfo
"{0} ({1} {2}) {3} border, {4} text, {5} interior, {6} fill, {7} mode, {8}," +
" '{9}' character, coordinates ({10},{11}) size {12}x{13}", node.type, node.flags,
node.state, (GEM.ObjectColors)((node.data & 0xFFFF & GEM.BorderColorMask) >> 12),
(GEM.ObjectColors)((node.data & 0xFFFF & GEM.TextColorMask) >> 8),
(GEM.ObjectColors)((node.data & 0xFFFF & GEM.InsideColorMask) >> 8),
(GEM.ObjectFillPattern)((node.data & 0xFFFF & GEM.FillPatternMask) >> 4),
(node.data & 0xFFFF & GEM.TransparentColor) != 0
? "transparent"
: "replace",
(GEM.ObjectColors)((node.data & 0xFFFF & GEM.TextColorMask) >> 8),
(GEM.ObjectColors)((node.data & 0xFFFF & GEM.InsideColorMask) >> 8),
(GEM.ObjectFillPattern)((node.data & 0xFFFF & GEM.FillPatternMask) >> 4),
(node.data & 0xFFFF & GEM.TransparentColor) != 0 ? "transparent" : "replace",
thickStr, character, node.x, node.y, node.width, node.height);
break;
case GEM.ObjectTypes.G_BUTTON:
@@ -283,11 +291,9 @@ namespace exeinfo
if(node.TedInfo == null) goto default;
if(node.TedInfo.Thickness < 0)
thickStr = $"{node.TedInfo.Thickness * -1} pixels outward thickness";
else if(node.TedInfo.Thickness > 0)
thickStr = $"{node.TedInfo.Thickness} pixels inward thickness";
else
thickStr = "no thickness";
thickStr = $"{node.TedInfo.Thickness * -1} pixels outward thickness";
else if(node.TedInfo.Thickness > 0) thickStr = $"{node.TedInfo.Thickness} pixels inward thickness";
else thickStr = "no thickness";
Console.WriteLine("{0} ({1} {2}), coordinates ({3},{4}) size {5}x{6}, font {7}, {8}-justified," + " {9}, {10} border, {11} text, {12} interior, {13} fill, {14} mode," + " text: \"{15}\", validation: \"{16}\", template: \"{17}\"",
node.type, node.flags, node.state, node.x, node.y, node.width, node.height,

View File

@@ -40,23 +40,23 @@ namespace exeinfogui
Label lblSubsystem;
TabGemResources tabGemResources;
TabControl tabMain;
TabNeResources tabNeResources;
TabPageSegments tabSegments;
TabPageStrings tabStrings;
TextBox txtFile;
TextArea txtInformation;
TextBox txtOs;
TextBox txtSubsystem;
TextBox txtType;
TabPageSegments tabSegments;
TabNeResources tabNeResources;
public MainForm()
{
XamlReader.Load(this);
tabSegments = new TabPageSegments {Visible = false};
tabSegments = new TabPageSegments {Visible = false};
tabStrings = new TabPageStrings {Visible = false};
tabGemResources = new TabGemResources {Visible = false};
tabNeResources = new TabNeResources {Visible = false};
tabNeResources = new TabNeResources {Visible = false};
tabMain.Pages.Add(tabSegments);
tabMain.Pages.Add(tabStrings);
tabMain.Pages.Add(tabGemResources);
@@ -78,11 +78,11 @@ namespace exeinfogui
if(dlgOpen.ShowDialog(this) != DialogResult.Ok) return;
txtFile.Text = dlgOpen.FileName;
txtFile.Text = dlgOpen.FileName;
txtInformation.Text = "";
txtOs.Text = "";
txtSubsystem.Text = "";
txtType.Text = "";
txtOs.Text = "";
txtSubsystem.Text = "";
txtType.Text = "";
IExecutable mzExe = new MZ(dlgOpen.FileName);
IExecutable neExe = new libexeinfo.NE(dlgOpen.FileName);
@@ -90,6 +90,7 @@ namespace exeinfogui
IExecutable lxExe = new LX(dlgOpen.FileName);
IExecutable coffExe = new COFF(dlgOpen.FileName);
IExecutable peExe = new PE(dlgOpen.FileName);
IExecutable geosExe = new Geos(dlgOpen.FileName);
IExecutable recognizedExe = null;
if(mzExe.Recognized)
@@ -107,14 +108,13 @@ namespace exeinfogui
recognizedExe = neExe;
if(((libexeinfo.NE)neExe).Resources.types != null && ((libexeinfo.NE)neExe).Resources.types.Any())
{
tabNeResources.Update(((libexeinfo.NE)neExe).Resources.types, ((libexeinfo.NE)neExe).Header.target_os);
tabNeResources.Update(((libexeinfo.NE)neExe).Resources.types,
((libexeinfo.NE)neExe).Header.target_os);
tabNeResources.Visible = true;
}
}
else if(lxExe.Recognized)
recognizedExe = lxExe;
else if(peExe.Recognized)
recognizedExe = peExe;
else if(lxExe.Recognized) recognizedExe = lxExe;
else if(peExe.Recognized) recognizedExe = peExe;
else if(stExe.Recognized)
{
recognizedExe = stExe;
@@ -124,10 +124,9 @@ namespace exeinfogui
tabGemResources.Visible = true;
}
}
else if(coffExe.Recognized)
recognizedExe = coffExe;
else
txtType.Text = "Format not recognized";
else if(coffExe.Recognized) recognizedExe = coffExe;
else if(geosExe.Recognized) recognizedExe = geosExe;
else txtType.Text = "Format not recognized";
if(recognizedExe == null) return;

46
libexeinfo/Geos/Consts.cs Normal file
View File

@@ -0,0 +1,46 @@
//
// Consts.cs
//
// Author:
// Natalia Portillo <claunia@claunia.com>
//
// Copyright (c) 2017 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.namespace libexeinfo.Geos
namespace libexeinfo
{
public partial class Geos
{
/// <summary>GEOS file identification "magic"</summary>
const uint GEOS_ID = 0x53CF45C7;
/// <summary>GEOS2 file identification "magic"</summary>
const uint GEOS2_ID = 0x53C145C7;
const int GEOS_TOKENLEN = 4;
/// <summary>Length of filename</summary>
const int GEOS_LONGNAME = 36;
/// <summary>Length of user file info</summary>
const int GEOS_INFO = 100;
/// <summary>Length of internal filename</summary>
const int GEOS_FNAME = 8;
/// <summary>Length of internal extension</summary>
const int GEOS_FEXT = 4;
}
}

187
libexeinfo/Geos/Enums.cs Normal file
View File

@@ -0,0 +1,187 @@
//
// Enums.cs
//
// Author:
// Natalia Portillo <claunia@claunia.com>
//
// Copyright (c) 2017 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.namespace libexeinfo.Geos
using System;
namespace libexeinfo
{
public partial class Geos
{
[Flags]
enum Attributes : ushort
{
GA_PROCESS = 0x8000,
GA_LIBRARY = 0x4000,
GA_DRIVER = 0x2000,
GA_KEEP_FILE_OPEN = 0x1000,
GA_SYSTEM = 0x0800,
GA_MULTI_LAUNCHABLE = 0x0400,
GA_APPLICATION = 0x0200,
GA_DRIVER_INITIALIZED = 0x0100,
GA_LIBRARY_INITIALIZED = 0x0080,
GA_GEODE_INITIALIZED = 0x0040,
GA_USES_COPROC = 0x0020,
GA_REQUIRES_COPROC = 0x0010,
GA_HAS_GENERAL_CONSUMER_MODE = 0x0008,
GA_ENTRY_POINTS_IN_C = 0x0004
}
enum FileType2 : ushort
{
/// <summary>
/// The file is not a GEOS file.
/// </summary>
GFT_NOT_GEOS_FILE = 0,
/// <summary>
/// The file is executable.
/// </summary>
GFT_EXECUTABLE = 1,
/// <summary>
/// The file is a VM file.
/// </summary>
GFT_VM = 2,
/// <summary>
/// The file is a GEOS byte file.
/// </summary>
GFT_DATA = 3,
/// <summary>
/// The file is a GEOS directory.
/// </summary>
GFT_DIRECTORY = 4,
/// <summary>
/// The file is a symbolic link.
/// </summary>
GFT_LINK = 5
}
enum ApplicationType : ushort
{
Application = 1,
Library = 2,
Driver = 3
}
enum FileType : ushort
{
/// <summary>
/// The file is executable.
/// </summary>
GFT_EXECUTABLE = 0,
/// <summary>
/// The file is a VM file.
/// </summary>
GFT_VM = 1
}
// These are defined in GEOS SDK but itself says they stopped using numerical IDs and should use ASCII ones.
enum ManufacturerId : ushort
{
GeoWorks = 0,
App = 1,
Palm = 2,
Wizard = 3,
CreativeLabs = 4,
DosLauncher = 5,
AmericaOnline = 6,
Intuit = 7,
Sdk = 8,
Agd = 9,
Generic = 10,
Tbd = 11,
Socket = 12
}
[Flags]
enum SegmentFlags : ushort
{
/// <summary>
/// The block will not move from its place in the global heap until it is freed.
/// </summary>
HF_FIXED = 0x80,
/// <summary>
/// The block may be locked by threads belonging to geodes other than the block's owner.
/// </summary>
HF_SHARABLE = 0x40,
/// <summary>
/// The block may be discarded when unlocked.
/// </summary>
HF_DISCARDABLE = 0x20,
/// <summary>
/// The block may be swapped to extended/expanded memory or to the disk swap space when it is unlocked.
/// </summary>
HF_SWAPABLE = 0x10,
/// <summary>
/// The block contains a local memory heap.
/// </summary>
HF_LMEM = 0x08,
/// <summary>
/// The memory manager turns this bit on when it discards a block.
/// </summary>
HF_DISCARDED = 0x02,
/// <summary>
/// The memory manager turns this bit on when it swaps a block to extended/expanded memory or to the disk swap space.
/// </summary>
HF_SWAPPED = 0x01,
HF_STATIC = HF_DISCARDABLE | HF_SWAPABLE,
HF_DYNAMIC = HF_SWAPABLE,
/// <summary>
/// The memory manager should initialize the block to null bytes.
/// </summary>
HAF_ZERO_INIT = 0x8000,
/// <summary>
/// The memory manager should lock the block after allocating it.
/// </summary>
HAF_LOCK = 0x4000,
/// <summary>
/// The memory manager should not return errors. If it cannot allocate block, GEOS will tell the user that there is no
/// memory available and crash.
/// </summary>
HAF_NO_ERR = 0x2000,
/// <summary>
/// If both <see cref="HAF_UI" /> and <see cref="HAF_OBJECT_RESOURCE" /> are set, this block will be run by the
/// application's UI thread.
/// </summary>
HAF_UI = 0x1000,
/// <summary>
/// The block's data will not be modified.
/// </summary>
HAF_READ_ONLY = 0x0800,
/// <summary>
/// This block will be an object block.
/// </summary>
HAF_OBJECT_RESOURCE = 0x0400,
/// <summary>
/// This block contains executable code.
/// </summary>
HAF_CODE = 0x0200,
/// <summary>
/// If the block contains code, the code may be run by a less privileged entity. If the block contains data, the data
/// may be accessed or altered by a less privileged entity.
/// </summary>
HAF_CONFORMING = 0x0100
}
}
}

228
libexeinfo/Geos/Geos.cs Normal file
View File

@@ -0,0 +1,228 @@
//
// Geos.cs
//
// Author:
// Natalia Portillo <claunia@claunia.com>
//
// Copyright (c) 2017 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.namespace libexeinfo.Geos
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
namespace libexeinfo
{
public partial class Geos : IExecutable
{
ApplicationHeader applicationHeader;
ApplicationHeaderV2 applicationHeader2;
Export[] exports;
GeodeHeader header;
GeodeHeaderV2 header2;
Import[] imports;
bool isNewHeader;
SegmentDescriptor[] segments;
/// <summary>
/// Initializes a new instance of the <see cref="T:libexeinfo.NE" /> class.
/// </summary>
/// <param name="path">Executable path.</param>
public Geos(string path)
{
BaseStream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
Initialize();
}
/// <summary>
/// Initializes a new instance of the <see cref="T:libexeinfo.NE" /> class.
/// </summary>
/// <param name="stream">Stream containing the executable.</param>
public Geos(Stream stream)
{
BaseStream = stream;
Initialize();
}
/// <summary>
/// Initializes a new instance of the <see cref="T:libexeinfo.NE" /> class.
/// </summary>
/// <param name="data">Byte array containing the executable.</param>
public Geos(byte[] data)
{
BaseStream = new MemoryStream(data);
Initialize();
}
public bool Recognized { get; private set; }
public string Type =>
isNewHeader ? "GEOS executable v2" : "GEOS executable";
public Stream BaseStream { get; }
public bool IsBigEndian => false;
public IEnumerable<Architecture> Architectures => new[] {Architecture.I86};
public OperatingSystem RequiredOperatingSystem { get; private set; }
public IEnumerable<string> Strings { get; private set; }
public IEnumerable<Segment> Segments { get; private set; }
// TODO: GEOS character set
void Initialize()
{
Recognized = false;
if(BaseStream == null) return;
BaseStream.Seek(0, SeekOrigin.Begin);
byte[] buffer = new byte[Marshal.SizeOf(typeof(GeodeHeaderV2))];
BaseStream.Read(buffer, 0, buffer.Length);
header = BigEndianMarshal.ByteArrayToStructureLittleEndian<GeodeHeader>(buffer);
header2 = BigEndianMarshal.ByteArrayToStructureLittleEndian<GeodeHeaderV2>(buffer);
Recognized = header.magic == GEOS_ID && header.type == FileType.GFT_EXECUTABLE ||
header2.magic == GEOS2_ID && header2.type == FileType2.GFT_EXECUTABLE;
if(!Recognized) return;
isNewHeader = header2.magic == GEOS2_ID;
RequiredOperatingSystem = new OperatingSystem {Name = "GEOS", MajorVersion = isNewHeader ? 2 : 1};
List<string> strings = new List<string>
{
StringHandlers.CToString(isNewHeader ? header2.name : header.name),
StringHandlers.CToString(isNewHeader ? header2.copyright : header.copyright),
StringHandlers.CToString(isNewHeader ? header2.info : header.info)
};
uint segmentBase = 0;
if(isNewHeader)
{
BaseStream.Position = Marshal.SizeOf(typeof(GeodeHeaderV2));
buffer = new byte[Marshal.SizeOf(typeof(ApplicationHeaderV2))];
segmentBase = (uint)Marshal.SizeOf(typeof(GeodeHeaderV2));
BaseStream.Read(buffer, 0, buffer.Length);
applicationHeader2 = BigEndianMarshal.ByteArrayToStructureLittleEndian<ApplicationHeaderV2>(buffer);
imports = new Import[applicationHeader2.imports];
exports = new Export[applicationHeader2.exports];
segments = new SegmentDescriptor[applicationHeader2.segments];
strings.Add($"{StringHandlers.CToString(applicationHeader2.name).Trim()}.{StringHandlers.CToString(applicationHeader2.extension).Trim()}");
}
else
{
BaseStream.Position = Marshal.SizeOf(typeof(GeodeHeader));
buffer = new byte[Marshal.SizeOf(typeof(ApplicationHeader))];
BaseStream.Read(buffer, 0, buffer.Length);
applicationHeader = BigEndianMarshal.ByteArrayToStructureLittleEndian<ApplicationHeader>(buffer);
imports = new Import[applicationHeader.imports];
exports = new Export[applicationHeader.exports];
segments = new SegmentDescriptor[applicationHeader.segments];
strings.Add($"{StringHandlers.CToString(applicationHeader.name).Trim()}.{StringHandlers.CToString(applicationHeader.extension).Trim()}");
}
buffer = new byte[Marshal.SizeOf(typeof(Import))];
for(int i = 0; i < imports.Length; i++)
{
BaseStream.Read(buffer, 0, buffer.Length);
imports[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian<Import>(buffer);
strings.Add(StringHandlers.CToString(imports[i].name).Trim());
}
buffer = new byte[Marshal.SizeOf(typeof(Export))];
for(int i = 0; i < exports.Length; i++)
{
BaseStream.Read(buffer, 0, buffer.Length);
exports[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian<Export>(buffer);
}
if(segments.Length > 0)
{
buffer = new byte[Marshal.SizeOf(typeof(SegmentDescriptor)) * segments.Length];
BaseStream.Read(buffer, 0, buffer.Length);
Segment[] mySegments = new Segment[segments.Length];
for(int i = 0; i < segments.Length; i++)
{
segments[i].length = BitConverter.ToUInt16(buffer, 2 * i);
segments[i].offset =
BitConverter.ToUInt32(buffer, 2 * segments.Length + 4 * i) + segmentBase;
segments[i].relocs_length = BitConverter.ToUInt16(buffer, 6 * segments.Length + 2 * i);
segments[i].flags =
(SegmentFlags)BitConverter.ToUInt16(buffer, 8 * segments.Length + 2 * i);
mySegments[i] = new Segment
{
Flags = $"{segments[i].flags}",
Offset = segments[i].offset,
Size = segments[i].length
};
if(i == 1) mySegments[i].Name = ".idata";
else if(segments[i].flags.HasFlag(SegmentFlags.HAF_CODE)) mySegments[i].Name = ".text";
else if(segments[i].flags.HasFlag(SegmentFlags.HAF_OBJECT_RESOURCE)) mySegments[i].Name = ".rsrc";
else if(segments[i].flags.HasFlag(SegmentFlags.HAF_ZERO_INIT)) mySegments[i].Name = ".bss";
else if(segments[i].flags.HasFlag(SegmentFlags.HAF_READ_ONLY)) mySegments[i].Name = ".rodata";
else mySegments[i].Name = ".data";
}
Segments = mySegments;
}
strings.Remove("");
strings.Remove(null);
Strings = strings;
}
/// <summary>
/// Identifies if the specified executable is a Microsoft/IBM Linear EXecutable
/// </summary>
/// <returns><c>true</c> if the specified executable is a Microsoft/IBM Linear EXecutable, <c>false</c> otherwise.</returns>
/// <param name="path">Executable path.</param>
public static bool Identify(string path)
{
FileStream baseStream = File.Open(path, FileMode.Open, FileAccess.Read);
baseStream.Seek(0, SeekOrigin.Begin);
byte[] buffer = new byte[Marshal.SizeOf(typeof(GeodeHeaderV2))];
baseStream.Read(buffer, 0, buffer.Length);
GeodeHeader header = BigEndianMarshal.ByteArrayToStructureLittleEndian<GeodeHeader>(buffer);
GeodeHeaderV2 header2 = BigEndianMarshal.ByteArrayToStructureLittleEndian<GeodeHeaderV2>(buffer);
return header.magic == GEOS_ID && header.type == FileType.GFT_EXECUTABLE ||
header2.magic == GEOS2_ID && header2.type == FileType2.GFT_EXECUTABLE;
}
/// <summary>
/// Identifies if the specified executable is a Microsoft/IBM Linear EXecutable
/// </summary>
/// <returns><c>true</c> if the specified executable is a Microsoft/IBM Linear EXecutable, <c>false</c> otherwise.</returns>
/// <param name="stream">Stream containing the executable.</param>
public static bool Identify(FileStream stream)
{
FileStream baseStream = stream;
baseStream.Seek(0, SeekOrigin.Begin);
byte[] buffer = new byte[Marshal.SizeOf(typeof(GeodeHeaderV2))];
baseStream.Read(buffer, 0, buffer.Length);
GeodeHeader header = BigEndianMarshal.ByteArrayToStructureLittleEndian<GeodeHeader>(buffer);
GeodeHeaderV2 header2 = BigEndianMarshal.ByteArrayToStructureLittleEndian<GeodeHeaderV2>(buffer);
return header.magic == GEOS_ID && header.type == FileType.GFT_EXECUTABLE ||
header2.magic == GEOS2_ID && header2.type == FileType2.GFT_EXECUTABLE;
}
}
}

110
libexeinfo/Geos/Info.cs Normal file
View File

@@ -0,0 +1,110 @@
//
// Info.cs
//
// Author:
// Natalia Portillo <claunia@claunia.com>
//
// Copyright (c) 2017 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.namespace libexeinfo.Geos
using System.Text;
namespace libexeinfo
{
public partial class Geos
{
public string Information
{
get
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("GEOS executable{0}", isNewHeader ? " v2" : "").AppendLine();
sb.AppendFormat("\tClass: {0}", isNewHeader ? $"{header2.type}" : $"{header.type}").AppendLine();
sb.AppendFormat("\tType: {0}", isNewHeader ? applicationHeader2.type : applicationHeader.type)
.AppendLine();
sb.AppendFormat("\tAttributes: {0}",
isNewHeader ? applicationHeader2.attributes : applicationHeader.attributes)
.AppendLine();
sb.AppendFormat("\tName: {0}", StringHandlers.CToString(isNewHeader ? header2.name : header.name))
.AppendLine();
sb.AppendFormat("\tInternal name: \"{0}.{1}\"",
isNewHeader
? StringHandlers.CToString(applicationHeader2.name).Trim()
: StringHandlers.CToString(applicationHeader.name).Trim(),
isNewHeader
? StringHandlers.CToString(applicationHeader2.extension).Trim()
: StringHandlers.CToString(applicationHeader.extension).Trim()).AppendLine();
sb.AppendFormat("\tVersion: {0}",
isNewHeader
? $"{header2.release.major}.{header2.release.minor}.{header2.release.change}.{header2.release.engineering}"
: $"{header.release.major}.{header.release.minor}.{header.release.change}.{header.release.engineering}")
.AppendLine();
sb.AppendFormat("\tCopyright string: {0}",
StringHandlers.CToString(isNewHeader ? header2.copyright : header.copyright))
.AppendLine();
sb.AppendFormat("\tInformational string: {0}",
StringHandlers.CToString(isNewHeader ? header2.info : header.info)).AppendLine();
sb.AppendFormat("\tProtocol: {0}",
isNewHeader
? $"{header2.protocol.major}.{header2.protocol.minor}"
: $"{header.protocol.major}.{header.protocol.minor}").AppendLine();
sb.AppendFormat("\tApplication token: \"{0}\" id {1}",
isNewHeader
? StringHandlers.CToString(header2.application.str)
: StringHandlers.CToString(header.creator.str),
isNewHeader ? header2.application.manufacturer : header.creator.manufacturer)
.AppendLine();
sb.AppendFormat("\tToken: \"{0}\" id {1}",
isNewHeader
? StringHandlers.CToString(header2.token.str)
: StringHandlers.CToString(header.token.str),
isNewHeader ? header2.token.manufacturer : header.token.manufacturer).AppendLine();
sb.AppendFormat("\tSegments: {0}",
isNewHeader ? applicationHeader2.segments : applicationHeader.segments).AppendLine();
sb.AppendFormat("\tImported libraries: {0}",
isNewHeader ? applicationHeader2.imports : applicationHeader.imports).AppendLine();
sb.AppendFormat("\tExported entry points: {0}",
isNewHeader ? applicationHeader2.exports : applicationHeader.exports).AppendLine();
sb.AppendFormat("\t{0} imports:", imports.Length).AppendLine();
for(int i = 0; i < imports.Length; i++)
sb.AppendFormat("\t\tImport \"{0}\", attributes {1}, protocol {2}.{3}",
StringHandlers.CToString(imports[i].name).Trim(), imports[i].attributes,
imports[i].protocol.major, imports[i].protocol.minor).AppendLine();
sb.AppendFormat("\t{0} exports:", exports.Length).AppendLine();
for(int i = 0; i < exports.Length; i++)
sb.AppendFormat("\t\tExported entry point in segment {0} offset {1}", exports[i].segment,
exports[i].offset).AppendLine();
sb.AppendFormat("\t{0} segments:", segments.Length).AppendLine();
for(int i = 0; i < segments.Length; i++)
sb
.AppendFormat("\t\tSegment {0} starts at {1} runs for {2} bytes with flags {3} has {4} relocations",
i, segments[i].offset, segments[i].length, segments[i].flags,
segments[i].relocs_length / 4).AppendLine();
return sb.ToString();
}
}
}
}

308
libexeinfo/Geos/Structs.cs Normal file
View File

@@ -0,0 +1,308 @@
//
// Structs.cs
//
// Author:
// Natalia Portillo <claunia@claunia.com>
//
// Copyright (c) 2017 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.namespace libexeinfo.Geos
using System.Runtime.InteropServices;
namespace libexeinfo
{
// Thanks to Marcus Gröber for structures
// TODO: Format of resource segments
public partial class Geos
{
/// <summary>ID for file types/icons</summary>
[StructLayout(LayoutKind.Sequential)]
struct Token
{
/// <summary>4 byte string</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = GEOS_TOKENLEN)]
public byte[] str;
/// <summary>Manufacturer ID</summary>
public ManufacturerId manufacturer;
}
/// <summary>Protocol/version number</summary>
[StructLayout(LayoutKind.Sequential)]
struct Protocol
{
/// <summary>Protocol</summary>
public ushort major;
/// <summary>Sub revision</summary>
public ushort minor;
}
[StructLayout(LayoutKind.Sequential)]
struct Release
{
public ushort major;
public ushort minor;
public ushort change;
public ushort engineering;
}
// Followed by followed by geosliblist, followed by exportlist, followed by segmentlist
[StructLayout(LayoutKind.Sequential)]
struct GeodeHeader
{
/// <summary>GEOS id magic: C7 45 CF 53</summary>
public uint magic;
/// <summary>
/// <see cref="FileType" />
/// </summary>
public FileType type;
/// <summary>Flags ??? (always seen 0000h)</summary>
public ushort flags;
/// <summary>Release</summary>
public Release release;
/// <summary>Protocol/version</summary>
public Protocol protocol;
/// <summary>File type/icon</summary>
public Token token;
/// <summary>Tokenof creator application</summary>
public Token creator;
/// <summary>Long filename</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = GEOS_LONGNAME)]
public byte[] name;
/// <summary>User file info</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = GEOS_INFO)]
public byte[] info;
/// <summary>Copyright notice</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
public byte[] copyright;
}
/// <summary>Additional geode file header</summary>
[StructLayout(LayoutKind.Sequential)]
struct ApplicationHeader
{
/// <summary>This is actually not part of the app header, but for historical reasons, I keep it in... :-)</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] unknown;
/// <summary>Attributes <see cref="Attributes" /></summary>
public Attributes _attr;
/// <summary>Application type <see cref="ApplicationType" /></summary>
public ApplicationType _type;
/// <summary>Expected kernel protocol</summary>
public Protocol kernel_protocol;
/// <summary>Number of program segments</summary>
public ushort _numseg;
/// <summary>Number of included libraries</summary>
public ushort _numlib;
/// <summary>Number of exported locations</summary>
public ushort _numexp;
/// <summary>Default stack size</summary>
public ushort stack_size;
/// <summary>If application: segment/offset of ???</summary>
public ushort app_off;
public ushort app_seg;
/// <summary>If application: item of resource with application token</summary>
public ushort tokenres_item;
/// <summary>If application: segment of resource with application token</summary>
public ushort tokenres_segment;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] unknown2;
/// <summary>Attributes <see cref="Attributes" /></summary>
public Attributes attributes;
/// <summary>Application type <see cref="ApplicationType" /></summary>
public ApplicationType type;
/// <summary>Release</summary>
public Release release;
/// <summary>Protocol/version</summary>
public Protocol protocol;
/// <summary>Possibly header checksum (???)</summary>
public ushort crc;
/// <summary>Internal filename (blank padded)</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = GEOS_FNAME)]
public byte[] name;
/// <summary>Internal extension (blank padded)</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = GEOS_FEXT)]
public byte[] extension;
/// <summary>File type/icon</summary>
Token token;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] unknown3;
/// <summary>If driver: entry location</summary>
public ushort entry_off;
public ushort entry_seg;
/// <summary>If library: init location (?)</summary>
public ushort init_off;
public ushort init_seg;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] unknown4;
/// <summary>Number of exported locations</summary>
public ushort exports;
/// <summary>Number of included libraries</summary>
public ushort imports;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] unknown5;
/// <summary>Number of program segments</summary>
public ushort segments;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public byte[] unknown6;
}
/// <summary>Base type of "exported" array</summary>
[StructLayout(LayoutKind.Sequential)]
struct Export
{
/// <summary>Routine entry location</summary>
public ushort offset;
/// <summary>Routine entry location</summary>
public ushort segment;
}
/// <summary>Base type of library array</summary>
[StructLayout(LayoutKind.Sequential)]
struct Import
{
/// <summary>library name</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = GEOS_FNAME)]
public byte[] name;
/// <summary>library type</summary>
public Attributes attributes;
/// <summary>required lib protocol/version</summary>
public Protocol protocol;
}
/// <summary>GEOS2 standard header</summary>
[StructLayout(LayoutKind.Sequential)]
struct GeodeHeaderV2
{
/// <summary>GEOS2 id magic: C7 45 CF 53</summary>
public uint magic;
/// <summary>Long filename</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = GEOS_LONGNAME)]
public byte[] name;
/// <summary>
/// <see cref="FileType2" />
/// </summary>
public FileType2 type;
/// <summary>Flags</summary>
public ushort flags;
/// <summary>Release</summary>
public Release release;
/// <summary>Protocol/version</summary>
public Protocol protocol;
/// <summary>File type/icon</summary>
public Token token;
/// <summary>Token of creator application</summary>
public Token application;
/// <summary>User file info</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = GEOS_INFO)]
public byte[] info;
/// <summary>Copyright notice</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
public byte[] copyright;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] unknown;
/// <summary>Creation date in DOS format</summary>
public byte create_date;
/// <summary>Creation time in DOS format</summary>
public byte create_time;
/// <summary>Password, encrypted as hex string</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] password;
/// <summary>not yet decoded</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 44)]
public byte[] unknown2;
}
/// <summary>Additional geode file header</summary>
[StructLayout(LayoutKind.Sequential)]
struct ApplicationHeaderV2
{
/// <summary>Attributes <see cref="Attributes" /></summary>
public Attributes _attr;
/// <summary>Application type <see cref="ApplicationType" /></summary>
public ApplicationType _type;
/// <summary>Expected kernel protocol</summary>
public Protocol kernel_protocol;
/// <summary>Number of program segments</summary>
public ushort _numseg;
/// <summary>Number of included libraries</summary>
public ushort _numlib;
/// <summary>Number of exported locations</summary>
public ushort _numexp;
/// <summary>Default stack size</summary>
public ushort stack_size;
/// <summary>If application: segment/offset of ???</summary>
public ushort app_off;
public ushort app_seg;
/// <summary>If application: item of resource with application token</summary>
public ushort tokenres_item;
/// <summary>If application: segment of resource with application token</summary>
public ushort tokenres_segment;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] unknown;
/// <summary>Attributes <see cref="Attributes" /></summary>
public Attributes attributes;
/// <summary>Application type <see cref="ApplicationType" /></summary>
public ApplicationType type;
/// <summary>Release"</summary>
public Release release;
/// <summary>Protocol/version</summary>
public Protocol protocol;
/// <summary>Possibly header checksum (???)</summary>
public ushort crc;
/// <summary>Internal filename (blank padded)</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = GEOS_FNAME)]
public byte[] name;
/// <summary>Internal extension (blank padded)</summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = GEOS_FEXT)]
public byte[] extension;
/// <summary>File type/icon</summary>
public Token token;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] unknown2;
/// <summary>If driver: entry location</summary>
public ushort entry_off;
public ushort entry_seg;
/// <summary>If library: init location (?)</summary>
public ushort init_off;
public ushort init_seg;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] unknown3;
/// <summary>Number of exported locations</summary>
public ushort exports;
/// <summary>Number of included libraries</summary>
public ushort imports;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] unknown4;
/// <summary>Number of program segments</summary>
public ushort segments;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public byte[] unknown5;
}
[StructLayout(LayoutKind.Sequential)]
struct SegmentDescriptor
{
public ushort length;
public uint offset;
public ushort relocs_length;
public SegmentFlags flags;
}
}
}

View File

@@ -55,6 +55,11 @@
<Compile Include="GEM\Resources.cs" />
<Compile Include="GEM\Structs.cs" />
<Compile Include="GEM\Vdi.cs" />
<Compile Include="Geos\Consts.cs" />
<Compile Include="Geos\Enums.cs" />
<Compile Include="Geos\Geos.cs" />
<Compile Include="Geos\Info.cs" />
<Compile Include="Geos\Structs.cs" />
<Compile Include="IExecutable.cs" />
<Compile Include="NE\Accelerators.cs" />
<Compile Include="NE\GetStrings.cs" />