Add PE resource header

This commit is contained in:
Matt Nadareski
2022-11-09 11:58:35 -08:00
parent f7343ea305
commit ac514fce30
3 changed files with 140 additions and 2 deletions

View File

@@ -361,12 +361,40 @@ namespace BurnOutSharp.Builder
return 0;
}
/// <summary>
/// Read resource data as a resource header
/// </summary>
/// <param name="data">Data to parse into a resource header</param>
/// <param name="offset">Offset into the byte array</param>
/// <returns>A filled resource header on success, null on error</returns>
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;
}
/// <summary>
/// Read resource data as an accelerator table resource
/// </summary>
/// <param name="data">Data to parse into an accelerator table resource</param>
/// <param name="offset">Offset into the byte array</param>
/// <returns>A filled accelerator table resource on success, null on error</returns>
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;

View File

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

View File

@@ -0,0 +1,94 @@
namespace BurnOutSharp.Models.PortableExecutable
{
/// <summary>
/// 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.
/// </summary>
/// <see href="https://learn.microsoft.com/en-us/windows/win32/menurc/resourceheader"/>
public class ResourceHeader
{
/// <summary>
/// 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.
/// </summary>
public uint DataSize;
/// <summary>
/// The size, in bytes, of the resource header data that follows.
/// </summary>
public uint HeaderSize;
/// <summary>
/// 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.
/// </summary>
public ResourceType ResourceType;
/// <summary>
/// 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.
/// </summary>
public uint Name;
/// <summary>
/// A predefined resource data version. This will determine which version of the
/// resource data the application should use.
/// </summary>
public uint DataVersion;
/// <summary>
/// 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.
/// </summary>
public MemoryFlags MemoryFlags;
/// <summary>
/// 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.
/// </summary>
public ushort LanguageId;
/// <summary>
/// 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.
/// </summary>
public uint Version;
/// <summary>
/// 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.
/// </summary>
public uint Characteristics;
}
}