From ac514fce304ee3a7a9cdf1f16b31070fc203fa53 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Wed, 9 Nov 2022 11:58:35 -0800 Subject: [PATCH] Add PE resource header --- BurnOutSharp.Builder/Extensions.cs | 32 ++++++- .../PortableExecutable/Enums.cs | 16 ++++ .../PortableExecutable/ResourceHeader.cs | 94 +++++++++++++++++++ 3 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 BurnOutSharp.Models/PortableExecutable/ResourceHeader.cs diff --git a/BurnOutSharp.Builder/Extensions.cs b/BurnOutSharp.Builder/Extensions.cs index 00bb2ae0..374666b0 100644 --- a/BurnOutSharp.Builder/Extensions.cs +++ b/BurnOutSharp.Builder/Extensions.cs @@ -361,12 +361,40 @@ namespace BurnOutSharp.Builder return 0; } + /// + /// Read resource data as a resource header + /// + /// Data to parse into a resource header + /// Offset into the byte array + /// A filled resource header on success, null on error + public static Models.PortableExecutable.ResourceHeader AsResourceHeader(this byte[] data, ref int offset) + { + // If we have data that's invalid, we can't do anything + if (data == null) + return null; + + // Read in the table + var header = new Models.PortableExecutable.ResourceHeader(); + header.DataSize = data.ReadUInt32(ref offset); + header.HeaderSize = data.ReadUInt32(ref offset); + header.ResourceType = (Models.PortableExecutable.ResourceType)data.ReadUInt32(ref offset); // TODO: Could be a string too + header.Name = data.ReadUInt32(ref offset); // TODO: Could be a string too + header.DataVersion = data.ReadUInt32(ref offset); + header.MemoryFlags = (Models.PortableExecutable.MemoryFlags)data.ReadUInt16(ref offset); + header.LanguageId = data.ReadUInt16(ref offset); + header.Version = data.ReadUInt32(ref offset); + header.Characteristics = data.ReadUInt32(ref offset); + + return header; + } + /// /// Read resource data as an accelerator table resource /// /// Data to parse into an accelerator table resource + /// Offset into the byte array /// A filled accelerator table resource on success, null on error - public static Models.PortableExecutable.AcceleratorTableEntryResource[] AsAcceleratorTableResource(this byte[] data) + public static Models.PortableExecutable.AcceleratorTableEntryResource[] AsAcceleratorTableResource(this byte[] data, ref int offset) { // If we have data that's invalid for this resource type, we can't do anything if (data == null || data.Length % 8 != 0) @@ -374,7 +402,6 @@ namespace BurnOutSharp.Builder // Get the number of entries int count = data.Length / 8; - int offset = 0; // Read in the table var table = new Models.PortableExecutable.AcceleratorTableEntryResource[count]; @@ -385,6 +412,7 @@ namespace BurnOutSharp.Builder entry.Ansi = data.ReadUInt16(ref offset); entry.Id = data.ReadUInt16(ref offset); entry.Padding = data.ReadUInt16(ref offset); + table[i] = entry; } return table; diff --git a/BurnOutSharp.Models/PortableExecutable/Enums.cs b/BurnOutSharp.Models/PortableExecutable/Enums.cs index 814d5bac..265d965e 100644 --- a/BurnOutSharp.Models/PortableExecutable/Enums.cs +++ b/BurnOutSharp.Models/PortableExecutable/Enums.cs @@ -604,6 +604,22 @@ namespace BurnOutSharp.Models.PortableExecutable IMPORT_NAME_UNDECORATE = 3, } + [Flags] + public enum MemoryFlags : ushort + { + // TODO: Validate the ~ statements + MOVEABLE = 0x0010, + FIXED = 0xFFEF, // ~MOVEABLE + + PURE = 0x0020, + IMPURE = 0xFFDF, // ~PURE + + PRELOAD = 0x0040, + LOADONCALL = 0xFFBF, // ~PRELOAD + + DISCARDABLE = 0x1000, + } + public enum MachineType : ushort { /// diff --git a/BurnOutSharp.Models/PortableExecutable/ResourceHeader.cs b/BurnOutSharp.Models/PortableExecutable/ResourceHeader.cs new file mode 100644 index 00000000..c87610eb --- /dev/null +++ b/BurnOutSharp.Models/PortableExecutable/ResourceHeader.cs @@ -0,0 +1,94 @@ +namespace BurnOutSharp.Models.PortableExecutable +{ + /// + /// Contains information about the resource header itself and the data specific to + /// this resource. This structure is not a true C-language structure, because it + /// contains variable-length members. The structure definition provided here is for + /// explanation only; it is not present in any standard header file. + /// + /// + public class ResourceHeader + { + /// + /// The size, in bytes, of the data that follows the resource header for this + /// particular resource. It does not include any file padding between this + /// resource and any resource that follows it in the resource file. + /// + public uint DataSize; + + /// + /// The size, in bytes, of the resource header data that follows. + /// + public uint HeaderSize; + + /// + /// The resource type. The TYPE member can either be a numeric value or a + /// null-terminated Unicode string that specifies the name of the type. See the + /// following Remarks section for a description of Name or Ordinal type members. + /// + /// If the TYPE member is a numeric value, it can specify either a standard or a + /// user-defined resource type. If the member is a string, then it is a + /// user-defined resource type. + /// + /// Values less than 256 are reserved for system use. + /// + public ResourceType ResourceType; + + /// + /// A name that identifies the particular resource. The NAME member, like the TYPE + /// member, can either be a numeric value or a null-terminated Unicode string. + /// See the following Remarks section for a description of Name or Ordinal type + /// members. + /// + /// You do not need to add padding for DWORD alignment between the TYPE and NAME + /// members because they contain WORD data. However, you may need to add a WORD of + /// padding after the NAME member to align the rest of the header on DWORD boundaries. + /// + public uint Name; + + /// + /// A predefined resource data version. This will determine which version of the + /// resource data the application should use. + /// + public uint DataVersion; + + /// + /// A set of attribute flags that can describe the state of the resource. Modifiers + /// in the .RC script file assign these attributes to the resource. The script + /// identifiers can assign the following flag values. + /// + /// Applications do not use any of these attributes. The attributes are permitted + /// in the script for backward compatibility with existing scripts, but they are + /// ignored. Resources are loaded when the corresponding module is loaded, and are + /// freed when the module is unloaded. + /// + public MemoryFlags MemoryFlags; + + /// + /// The language for the resource or set of resources. Set the value for this member + /// with the optional LANGUAGE resource definition statement. The parameters are + /// constants from the Winnt.h file. + /// + /// Each resource includes a language identifier so the system or application can + /// select a language appropriate for the current locale of the system. If there are + /// multiple resources of the same type and name that differ only in the language of + /// the strings within the resources, you will need to specify a LanguageId for each + /// one. + /// + public ushort LanguageId; + + /// + /// A user-defined version number for the resource data that tools can use to read and + /// write resource files. Set this value with the optional VERSION resource definition + /// statement. + /// + public uint Version; + + /// + /// Specifies user-defined information about the resource that tools can use to read and + /// write resource files. Set this value with the optional CHARACTERISTICS resource + /// definition statement. + /// + public uint Characteristics; + } +}