Add support for NE OS/2 resource table format and resource types.

This commit is contained in:
2018-03-02 22:49:19 +00:00
parent 6ac77ac1fa
commit 27a7bbf5d1
4 changed files with 228 additions and 63 deletions

View File

@@ -41,6 +41,12 @@ namespace libexeinfo
/// </summary>
const string STRING_FILE_INFO = "StringFileInfo";
const ushort SEGMENT_TYPE_MASK = 0x07;
const ushort SEGMENT_FLAGS_MASK = 0x3F8;
const ushort SEGMENT_DISCARD_MASK = 0xF000;
const ushort SEGMENT_IOPRVL_MASK = 0xC00;
const ushort KNOWN_RSRC_FLAGS = 0x1070;
/// <summary>
/// Gets the name of a resource type according to its identifier
/// </summary>
@@ -80,10 +86,38 @@ namespace libexeinfo
}
}
const ushort SEGMENT_TYPE_MASK = 0x07;
const ushort SEGMENT_FLAGS_MASK = 0x3F8;
const ushort SEGMENT_DISCARD_MASK = 0xF000;
const ushort SEGMENT_IOPRVL_MASK = 0xC00;
const ushort KNOWN_RSRC_FLAGS = 0x1070;
/// <summary>
/// Gets the name of a resource type according to its identifier
/// </summary>
/// <returns>The resource type name.</returns>
/// <param name="id">Resource type identifier.</param>
public static string ResourceIdToNameOs2(ushort id)
{
switch(id)
{
case (int)Os2ResourceTypes.RT_POINTER: return "RT_POINTER";
case (int)Os2ResourceTypes.RT_BITMAP: return "RT_BITMAP";
case (int)Os2ResourceTypes.RT_MENU: return "RT_MENU";
case (int)Os2ResourceTypes.RT_DIALOG: return "RT_DIALOG";
case (int)Os2ResourceTypes.RT_STRING: return "RT_STRING";
case (int)Os2ResourceTypes.RT_FONTDIR: return "RT_FONTDIR";
case (int)Os2ResourceTypes.RT_FONT: return "RT_FONT";
case (int)Os2ResourceTypes.RT_ACCELTABLE: return "RT_ACCELTABLE";
case (int)Os2ResourceTypes.RT_RCDATA: return "RT_RCDATA";
case (int)Os2ResourceTypes.RT_MESSAGE: return "RT_MESSAGE";
case (int)Os2ResourceTypes.RT_DLGINCLUDE: return "RT_DLGINCLUDE";
case (int)Os2ResourceTypes.RT_VKEYTBL: return "RT_VKEYTBL";
case (int)Os2ResourceTypes.RT_KEYTBL: return "RT_KEYTBL";
case (int)Os2ResourceTypes.RT_CHARTBL: return "RT_CHARTBL";
case (int)Os2ResourceTypes.RT_DISPLAYINFO: return "RT_DISPLAYINFO";
case (int)Os2ResourceTypes.RT_FKASHORT: return "RT_FKASHORT";
case (int)Os2ResourceTypes.RT_FKALONG: return "RT_FKALONG";
case (int)Os2ResourceTypes.RT_HELPTABLE: return "RT_HELPTABLE";
case (int)Os2ResourceTypes.RT_HELPSUBTABLE: return "RT_HELPSUBTABLE";
case (int)Os2ResourceTypes.RT_FDDIR: return "RT_FDDIR";
case (int)Os2ResourceTypes.RT_FD: return "RT_FD";
default: return $"{id}";
}
}
}
}

View File

@@ -55,6 +55,55 @@ namespace libexeinfo
GangloadArea = 1 << 3
}
/// <summary>
/// Resource types.
/// </summary>
public enum Os2ResourceTypes : ushort
{
/// <summary>mouse pointer shape</summary>
RT_POINTER = 1,
/// <summary>bitmap</summary>
RT_BITMAP = 2,
/// <summary>menu template</summary>
RT_MENU = 3,
/// <summary>dialog template</summary>
RT_DIALOG = 4,
/// <summary>string tables</summary>
RT_STRING = 5,
/// <summary>font directory</summary>
RT_FONTDIR = 6,
/// <summary>font</summary>
RT_FONT = 7,
/// <summary>accelerator tables</summary>
RT_ACCELTABLE = 8,
/// <summary>binary data</summary>
RT_RCDATA = 9,
/// <summary>error msg tables</summary>
RT_MESSAGE = 10,
/// <summary>dialog include file name</summary>
RT_DLGINCLUDE = 11,
/// <summary>key to vkey tables</summary>
RT_VKEYTBL = 12,
/// <summary>key to UGL tables</summary>
RT_KEYTBL = 13,
/// <summary>glyph to character tables</summary>
RT_CHARTBL = 14,
/// <summary>screen display information</summary>
RT_DISPLAYINFO = 15,
/// <summary>function key area short form</summary>
RT_FKASHORT = 16,
/// <summary>function key area long form</summary>
RT_FKALONG = 17,
/// <summary>Help table for IPFC</summary>
RT_HELPTABLE = 18,
/// <summary>Help subtable for IPFC</summary>
RT_HELPSUBTABLE = 19,
/// <summary>DBCS uniq/font driver directory</summary>
RT_FDDIR = 20,
/// <summary>DBCS uniq/font driver</summary>
RT_FD = 21
}
/// <summary>
/// Program flags.
/// </summary>
@@ -78,9 +127,9 @@ namespace libexeinfo
[Flags]
public enum ResourceFlags : ushort
{
Moveable = 0x10,
Pure = 0x20,
Preload = 0x40,
Moveable = 0x10,
Pure = 0x20,
Preload = 0x40,
Discardable = 0x1000
}
@@ -118,6 +167,57 @@ namespace libexeinfo
RT_NEW = 0x2000
}
[Flags]
public enum SegmentFlags : ushort
{
/// <summary>
/// Segment data is iterated
/// </summary>
Iterated = 0x08,
/// <summary>
/// Segment is not fixed
/// </summary>
Moveable = 0x10,
/// <summary>
/// Segment can be shared
/// </summary>
Shared = 0x20,
/// <summary>
/// Segment will be preloaded; read-only if this is a data segment
/// </summary>
Preload = 0x40,
/// <summary>
/// Code segment is execute only; data segment is read-only
/// </summary>
Eronly = 0x80,
/// <summary>
/// Segment has relocation records
/// </summary>
Relocinfo = 0x100,
/// <summary>
/// Segment is conforming
/// </summary>
Conform = 0x200,
/// <summary>
/// Discardable
/// </summary>
Discardable = 0x1000,
/// <summary>
/// 32-bit code segment
/// </summary>
Code32 = 0x2000,
/// <summary>
/// Length of segment and minimum allocation size are in units of segment sector size
/// </summary>
Huge = 0x4000
}
public enum SegmentType : ushort
{
Code = 0,
Data = 1
}
/// <summary>
/// Target operating system.
/// </summary>
@@ -217,48 +317,5 @@ namespace libexeinfo
VFT_UNKNOWN = 0x00000000,
VFT_VXD = 0x00000005
}
[Flags]
public enum SegmentFlags : ushort
{
/// <summary>
/// Segment data is iterated
/// </summary>
Iterated = 0x08,
/// <summary>
/// Segment is not fixed
/// </summary>
Moveable = 0x10,
/// <summary>
/// Segment can be shared
/// </summary>
Shared = 0x20,
/// <summary>
/// Segment will be preloaded; read-only if this is a data segment
/// </summary>
Preload = 0x40,
/// <summary>
/// Code segment is execute only; data segment is read-only
/// </summary>
Eronly = 0x80,
/// <summary>
/// Segment has relocation records
/// </summary>
Relocinfo = 0x100,
/// <summary>
/// Segment is conforming
/// </summary>
Conform = 0x200,
/// <summary>
/// Length of segment and minimum allocation size are in units of segment sector size
/// </summary>
Huge = 0x4000
}
public enum SegmentType : ushort
{
Code = 0,
Data = 1
}
}
}

View File

@@ -216,19 +216,86 @@ namespace libexeinfo
if(Header.imported_names_offset >= Header.resource_table_offset &&
Header.imported_names_offset <= resourceUpperLimit) resourceUpperLimit = Header.imported_names_offset;
if(Header.resource_table_offset < resourceUpperLimit && Header.resource_table_offset != 0 &&
(Header.target_os == TargetOS.Windows || Header.target_os == TargetOS.Win32))
{
Resources = GetResources(BaseStream, BaseExecutable.Header.new_offset, Header.resource_table_offset,
resourceUpperLimit);
if(Header.resource_table_offset < resourceUpperLimit && Header.resource_table_offset != 0)
if(Header.target_os == TargetOS.Windows || Header.target_os == TargetOS.Win32)
{
Resources = GetResources(BaseStream, BaseExecutable.Header.new_offset, Header.resource_table_offset,
resourceUpperLimit);
for(int t = 0; t < Resources.types.Length; t++)
Resources.types[t].resources = Resources.types[t].resources.OrderBy(r => r.name).ToArray();
for(int t = 0; t < Resources.types.Length; t++)
Resources.types[t].resources = Resources.types[t].resources.OrderBy(r => r.name).ToArray();
Resources.types = Resources.types.OrderBy(t => t.name).ToArray();
Resources.types = Resources.types.OrderBy(t => t.name).ToArray();
Versions = GetVersions().ToArray();
}
Versions = GetVersions().ToArray();
}
else if(Header.target_os == TargetOS.OS2 && segments != null && Header.resource_entries > 0)
{
BaseStream.Position = BaseExecutable.Header.new_offset + Header.resource_table_offset;
buffer = new byte[Header.resource_entries * 4];
BaseStream.Read(buffer, 0, buffer.Length);
Os2ResourceTableEntry[] entries = new Os2ResourceTableEntry[Header.resource_entries];
for(int i = 0; i < entries.Length; i++)
{
entries[i].etype = BitConverter.ToUInt16(buffer, i * 4 + 0);
entries[i].ename = BitConverter.ToUInt16(buffer, i * 4 + 2);
}
SegmentEntry[] resourceSegments = new SegmentEntry[Header.resource_entries];
Array.Copy(segments, Header.segment_count - Header.resource_entries, resourceSegments, 0,
Header.resource_entries);
SegmentEntry[] realSegments = new SegmentEntry[Header.segment_count - Header.resource_entries];
Array.Copy(segments, 0, realSegments, 0, realSegments.Length);
segments = realSegments;
SortedDictionary<ushort, List<Resource>> os2resources =
new SortedDictionary<ushort, List<Resource>>();
for(int i = 0; i < entries.Length; i++)
{
os2resources.TryGetValue(entries[i].etype, out List<Resource> thisResourceType);
if(thisResourceType == null) thisResourceType = new List<Resource>();
Resource thisResource = new Resource
{
id = entries[i].ename,
name = $"{entries[i].ename}",
flags = (ResourceFlags)resourceSegments[i].dwFlags,
dataOffset = (uint)(resourceSegments[i].dwLogicalSectorOffset * 16),
length = resourceSegments[i].dwSegmentLength
};
if(thisResource.length == 0)
thisResource.length = 65536;
if(thisResource.dataOffset == 0)
thisResource.dataOffset = 65536;
if((resourceSegments[i].dwFlags & (ushort)SegmentFlags.Huge) == (ushort)SegmentFlags.Huge)
thisResource.length *= 16;
thisResource.data = new byte[thisResource.length];
BaseStream.Position = thisResource.dataOffset;
BaseStream.Read(thisResource.data, 0, thisResource.data.Length);
thisResourceType.Add(thisResource);
os2resources.Remove(entries[i].etype);
os2resources.Add(entries[i].etype, thisResourceType);
}
if(os2resources.Count > 0)
{
Resources = new ResourceTable();
int counter = 0;
Resources.types = new ResourceType[os2resources.Count];
foreach(KeyValuePair<ushort, List<Resource>> kvp in os2resources)
{
Resources.types[counter].count = (ushort)kvp.Value.Count;
Resources.types[counter].id = kvp.Key;
Resources.types[counter].name = ResourceIdToNameOs2(kvp.Key);
Resources.types[counter].resources = kvp.Value.OrderBy(r => r.id).ToArray();
counter++;
}
}
}
resourceUpperLimit = ushort.MaxValue;

View File

@@ -98,8 +98,8 @@ namespace libexeinfo
/// </summary>
public struct Resource
{
public ushort dataOffset;
public ushort length;
public uint dataOffset;
public uint length;
public ResourceFlags flags;
public ushort id;
public uint reserved;
@@ -176,5 +176,12 @@ namespace libexeinfo
/// </summary>
public ushort dwMinimumAllocation;
}
[StructLayout(LayoutKind.Sequential)]
public struct Os2ResourceTableEntry
{
public ushort etype;
public ushort ename;
}
}
}