From 8052ee2afbe940a285f4e03f9560d5a18ef33123 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Tue, 13 Dec 2022 21:05:52 -0800 Subject: [PATCH] Some PE resource handling cleanup --- BurnOutSharp.Builder/Extensions.cs | 344 +++++++++----------- BurnOutSharp.Wrappers/PortableExecutable.cs | 28 +- 2 files changed, 168 insertions(+), 204 deletions(-) diff --git a/BurnOutSharp.Builder/Extensions.cs b/BurnOutSharp.Builder/Extensions.cs index 20fefde7..0845ab4d 100644 --- a/BurnOutSharp.Builder/Extensions.cs +++ b/BurnOutSharp.Builder/Extensions.cs @@ -1416,108 +1416,12 @@ namespace BurnOutSharp.Builder if (nextKey == "StringFileInfo") { - var stringFileInfo = new Models.PortableExecutable.StringFileInfo(); - - stringFileInfo.Length = entry.Data.ReadUInt16(ref offset); - stringFileInfo.ValueLength = entry.Data.ReadUInt16(ref offset); - stringFileInfo.ResourceType = (Models.PortableExecutable.VersionResourceType)entry.Data.ReadUInt16(ref offset); - stringFileInfo.Key = entry.Data.ReadString(ref offset, Encoding.Unicode); - if (stringFileInfo.Key != "StringFileInfo") - return null; - - while ((offset % 4) != 0) - stringFileInfo.Padding = entry.Data.ReadUInt16(ref offset); - - var stringFileInfoChildren = new List(); - while (offset < stringFileInfo.Length) - { - var stringTable = new Models.PortableExecutable.StringTable(); - - stringTable.Length = entry.Data.ReadUInt16(ref offset); - stringTable.ValueLength = entry.Data.ReadUInt16(ref offset); - stringTable.ResourceType = (Models.PortableExecutable.VersionResourceType)entry.Data.ReadUInt16(ref offset); - stringTable.Key = entry.Data.ReadString(ref offset, Encoding.Unicode); - - while ((offset % 4) != 0) - stringTable.Padding = entry.Data.ReadUInt16(ref offset); - - var stringTableChildren = new List(); - while (offset < stringTable.Length) - { - var stringData = new Models.PortableExecutable.StringData(); - - stringData.Length = entry.Data.ReadUInt16(ref offset); - stringData.ValueLength = entry.Data.ReadUInt16(ref offset); - stringData.ResourceType = (Models.PortableExecutable.VersionResourceType)entry.Data.ReadUInt16(ref offset); - stringData.Key = entry.Data.ReadString(ref offset, Encoding.Unicode); - - while ((offset % 4) != 0) - stringData.Padding = entry.Data.ReadUInt16(ref offset); - - if (stringData.ValueLength > 0) - { - byte[] valueBytes = entry.Data.ReadBytes(ref offset, stringData.ValueLength * sizeof(ushort)); - stringData.Value = Encoding.Unicode.GetString(valueBytes); - } - - while ((offset % 4) != 0) - _ = entry.Data.ReadUInt16(ref offset); - - stringTableChildren.Add(stringData); - } - - stringTable.Children = stringTableChildren.ToArray(); - - stringFileInfoChildren.Add(stringTable); - } - - stringFileInfo.Children = stringFileInfoChildren.ToArray(); - + var stringFileInfo = AsStringFileInfo(entry.Data, ref offset); versionInfo.StringFileInfo = stringFileInfo; } else if (nextKey == "VarFileInfo") { - var varFileInfo = new Models.PortableExecutable.VarFileInfo(); - - varFileInfo.Length = entry.Data.ReadUInt16(ref offset); - varFileInfo.ValueLength = entry.Data.ReadUInt16(ref offset); - varFileInfo.ResourceType = (Models.PortableExecutable.VersionResourceType)entry.Data.ReadUInt16(ref offset); - varFileInfo.Key = entry.Data.ReadString(ref offset, Encoding.Unicode); - if (varFileInfo.Key != "VarFileInfo") - return null; - - while ((offset % 4) != 0) - varFileInfo.Padding = entry.Data.ReadUInt16(ref offset); - - var varFileInfoChildren = new List(); - while (offset < varFileInfo.Length) - { - var varData = new Models.PortableExecutable.VarData(); - - varData.Length = entry.Data.ReadUInt16(ref offset); - varData.ValueLength = entry.Data.ReadUInt16(ref offset); - varData.ResourceType = (Models.PortableExecutable.VersionResourceType)entry.Data.ReadUInt16(ref offset); - varData.Key = entry.Data.ReadString(ref offset, Encoding.Unicode); - if (varData.Key != "Translation") - return null; - - while ((offset % 4) != 0) - varData.Padding = entry.Data.ReadUInt16(ref offset); - - var varDataValue = new List(); - while (offset < (varData.ValueLength * sizeof(ushort))) - { - uint languageAndCodeIdentifierPair = entry.Data.ReadUInt32(ref offset); - varDataValue.Add(languageAndCodeIdentifierPair); - } - - varData.Value = varDataValue.ToArray(); - - varFileInfoChildren.Add(varData); - } - - varFileInfo.Children = varFileInfoChildren.ToArray(); - + var varFileInfo = AsVarFileInfo(entry.Data, ref offset); versionInfo.VarFileInfo = varFileInfo; } } @@ -1534,108 +1438,12 @@ namespace BurnOutSharp.Builder if (nextKey == "StringFileInfo") { - var stringFileInfo = new Models.PortableExecutable.StringFileInfo(); - - stringFileInfo.Length = entry.Data.ReadUInt16(ref offset); - stringFileInfo.ValueLength = entry.Data.ReadUInt16(ref offset); - stringFileInfo.ResourceType = (Models.PortableExecutable.VersionResourceType)entry.Data.ReadUInt16(ref offset); - stringFileInfo.Key = entry.Data.ReadString(ref offset, Encoding.Unicode); - if (stringFileInfo.Key != "StringFileInfo") - return null; - - while ((offset % 4) != 0) - stringFileInfo.Padding = entry.Data.ReadUInt16(ref offset); - - var stringFileInfoChildren = new List(); - while (offset < stringFileInfo.Length) - { - var stringTable = new Models.PortableExecutable.StringTable(); - - stringTable.Length = entry.Data.ReadUInt16(ref offset); - stringTable.ValueLength = entry.Data.ReadUInt16(ref offset); - stringTable.ResourceType = (Models.PortableExecutable.VersionResourceType)entry.Data.ReadUInt16(ref offset); - stringTable.Key = entry.Data.ReadString(ref offset, Encoding.Unicode); - - while ((offset % 4) != 0) - stringTable.Padding = entry.Data.ReadUInt16(ref offset); - - var stringTableChildren = new List(); - while (offset < stringTable.Length) - { - var stringData = new Models.PortableExecutable.StringData(); - - stringData.Length = entry.Data.ReadUInt16(ref offset); - stringData.ValueLength = entry.Data.ReadUInt16(ref offset); - stringData.ResourceType = (Models.PortableExecutable.VersionResourceType)entry.Data.ReadUInt16(ref offset); - stringData.Key = entry.Data.ReadString(ref offset, Encoding.Unicode); - - while ((offset % 4) != 0) - stringData.Padding = entry.Data.ReadUInt16(ref offset); - - if (stringData.ValueLength > 0) - { - byte[] valueBytes = entry.Data.ReadBytes(ref offset, stringData.ValueLength * sizeof(ushort)); - stringData.Value = Encoding.Unicode.GetString(valueBytes); - } - - while ((offset % 4) != 0) - _ = entry.Data.ReadUInt16(ref offset); - - stringTableChildren.Add(stringData); - } - - stringTable.Children = stringTableChildren.ToArray(); - - stringFileInfoChildren.Add(stringTable); - } - - stringFileInfo.Children = stringFileInfoChildren.ToArray(); - + var stringFileInfo = AsStringFileInfo(entry.Data, ref offset); versionInfo.StringFileInfo = stringFileInfo; } else if (nextKey == "VarFileInfo") { - var varFileInfo = new Models.PortableExecutable.VarFileInfo(); - - varFileInfo.Length = entry.Data.ReadUInt16(ref offset); - varFileInfo.ValueLength = entry.Data.ReadUInt16(ref offset); - varFileInfo.ResourceType = (Models.PortableExecutable.VersionResourceType)entry.Data.ReadUInt16(ref offset); - varFileInfo.Key = entry.Data.ReadString(ref offset, Encoding.Unicode); - if (varFileInfo.Key != "VarFileInfo") - return null; - - while ((offset % 4) != 0) - varFileInfo.Padding = entry.Data.ReadUInt16(ref offset); - - var varFileInfoChildren = new List(); - while (offset < varFileInfo.Length) - { - var varData = new Models.PortableExecutable.VarData(); - - varData.Length = entry.Data.ReadUInt16(ref offset); - varData.ValueLength = entry.Data.ReadUInt16(ref offset); - varData.ResourceType = (Models.PortableExecutable.VersionResourceType)entry.Data.ReadUInt16(ref offset); - varData.Key = entry.Data.ReadString(ref offset, Encoding.Unicode); - if (varData.Key != "Translation") - return null; - - while ((offset % 4) != 0) - varData.Padding = entry.Data.ReadUInt16(ref offset); - - var varDataValue = new List(); - while (offset < (varData.ValueLength * sizeof(ushort))) - { - uint languageAndCodeIdentifierPair = entry.Data.ReadUInt32(ref offset); - varDataValue.Add(languageAndCodeIdentifierPair); - } - - varData.Value = varDataValue.ToArray(); - - varFileInfoChildren.Add(varData); - } - - varFileInfo.Children = varFileInfoChildren.ToArray(); - + var varFileInfo = AsVarFileInfo(entry.Data, ref offset); versionInfo.VarFileInfo = varFileInfo; } } @@ -1643,6 +1451,150 @@ namespace BurnOutSharp.Builder return versionInfo; } + /// + /// Read byte data as a string file info resource + /// + /// Data to parse into a string file info + /// Offset into the byte array + /// A filled string file info resource on success, null on error + private static Models.PortableExecutable.StringFileInfo AsStringFileInfo(byte[] data, ref int offset) + { + var stringFileInfo = new Models.PortableExecutable.StringFileInfo(); + + stringFileInfo.Length = data.ReadUInt16(ref offset); + stringFileInfo.ValueLength = data.ReadUInt16(ref offset); + stringFileInfo.ResourceType = (Models.PortableExecutable.VersionResourceType)data.ReadUInt16(ref offset); + stringFileInfo.Key = data.ReadString(ref offset, Encoding.Unicode); + if (stringFileInfo.Key != "StringFileInfo") + return null; + + // Align to the DWORD boundary if we're not at the end + if (offset != data.Length) + { + while ((offset % 4) != 0) + stringFileInfo.Padding = data.ReadByte(ref offset); + } + + var stringFileInfoChildren = new List(); + while (offset < stringFileInfo.Length) + { + var stringTable = new Models.PortableExecutable.StringTable(); + + stringTable.Length = data.ReadUInt16(ref offset); + stringTable.ValueLength = data.ReadUInt16(ref offset); + stringTable.ResourceType = (Models.PortableExecutable.VersionResourceType)data.ReadUInt16(ref offset); + stringTable.Key = data.ReadString(ref offset, Encoding.Unicode); + + // Align to the DWORD boundary if we're not at the end + if (offset != data.Length) + { + while ((offset % 4) != 0) + stringTable.Padding = data.ReadByte(ref offset); + } + + var stringTableChildren = new List(); + while (offset < stringTable.Length) + { + var stringData = new Models.PortableExecutable.StringData(); + + stringData.Length = data.ReadUInt16(ref offset); + stringData.ValueLength = data.ReadUInt16(ref offset); + stringData.ResourceType = (Models.PortableExecutable.VersionResourceType)data.ReadUInt16(ref offset); + stringData.Key = data.ReadString(ref offset, Encoding.Unicode); + + // Align to the DWORD boundary if we're not at the end + if (offset != data.Length) + { + while ((offset % 4) != 0) + stringData.Padding = data.ReadByte(ref offset); + } + + if (stringData.ValueLength > 0) + { + byte[] valueBytes = data.ReadBytes(ref offset, stringData.ValueLength * sizeof(ushort)); + stringData.Value = Encoding.Unicode.GetString(valueBytes); + } + + // Align to the DWORD boundary if we're not at the end + if (offset != data.Length) + { + while ((offset % 4) != 0) + _ = data.ReadByte(ref offset); + } + + stringTableChildren.Add(stringData); + } + + stringTable.Children = stringTableChildren.ToArray(); + + stringFileInfoChildren.Add(stringTable); + } + + stringFileInfo.Children = stringFileInfoChildren.ToArray(); + + return stringFileInfo; + } + + /// + /// Read byte data as a var file info resource + /// + /// Data to parse into a var file info + /// Offset into the byte array + /// A filled var file info resource on success, null on error + private static Models.PortableExecutable.VarFileInfo AsVarFileInfo(byte[] data, ref int offset) + { + var varFileInfo = new Models.PortableExecutable.VarFileInfo(); + + varFileInfo.Length = data.ReadUInt16(ref offset); + varFileInfo.ValueLength = data.ReadUInt16(ref offset); + varFileInfo.ResourceType = (Models.PortableExecutable.VersionResourceType)data.ReadUInt16(ref offset); + varFileInfo.Key = data.ReadString(ref offset, Encoding.Unicode); + if (varFileInfo.Key != "VarFileInfo") + return null; + + // Align to the DWORD boundary if we're not at the end + if (offset != data.Length) + { + while ((offset % 4) != 0) + varFileInfo.Padding = data.ReadByte(ref offset); + } + + var varFileInfoChildren = new List(); + while (offset < varFileInfo.Length) + { + var varData = new Models.PortableExecutable.VarData(); + + varData.Length = data.ReadUInt16(ref offset); + varData.ValueLength = data.ReadUInt16(ref offset); + varData.ResourceType = (Models.PortableExecutable.VersionResourceType)data.ReadUInt16(ref offset); + varData.Key = data.ReadString(ref offset, Encoding.Unicode); + if (varData.Key != "Translation") + return null; + + // Align to the DWORD boundary if we're not at the end + if (offset != data.Length) + { + while ((offset % 4) != 0) + varData.Padding = data.ReadByte(ref offset); + } + + var varDataValue = new List(); + while (offset < (varData.ValueLength * sizeof(ushort))) + { + uint languageAndCodeIdentifierPair = data.ReadUInt32(ref offset); + varDataValue.Add(languageAndCodeIdentifierPair); + } + + varData.Value = varDataValue.ToArray(); + + varFileInfoChildren.Add(varData); + } + + varFileInfo.Children = varFileInfoChildren.ToArray(); + + return varFileInfo; + } + #endregion } } \ No newline at end of file diff --git a/BurnOutSharp.Wrappers/PortableExecutable.cs b/BurnOutSharp.Wrappers/PortableExecutable.cs index c0a36fcf..451536ac 100644 --- a/BurnOutSharp.Wrappers/PortableExecutable.cs +++ b/BurnOutSharp.Wrappers/PortableExecutable.cs @@ -2286,14 +2286,26 @@ namespace BurnOutSharp.Wrappers string padding = new string(' ', (level + 1) * 2); Console.WriteLine($"{padding}Application-defined resource found, not parsed yet"); - //if (entry.Data != null) - // Console.WriteLine($"{padding}Value (Byte Data): {BitConverter.ToString(entry.Data).Replace('-', ' ')}"); - //if (entry.Data != null) - // Console.WriteLine($"{padding}Value (ASCII): {Encoding.ASCII.GetString(entry.Data)}"); - //if (entry.Data != null) - // Console.WriteLine($"{padding}Value (UTF-8): {Encoding.UTF8.GetString(entry.Data)}"); - //if (entry.Data != null) - // Console.WriteLine($"{padding}Value (Unicode): {Encoding.Unicode.GetString(entry.Data)}"); + // Then print the data, if needed + if (entry.Data[0] == 0x4D && entry.Data[1] == 0x5A) + { + Console.WriteLine($"{padding}Data: [Embedded Executable File]"); // TODO: Parse this out and print separately + } + else if (entry.Data[0] == 0x4D && entry.Data[1] == 0x53 && entry.Data[2] == 0x46 && entry.Data[3] == 0x54) + { + Console.WriteLine($"{padding}Data: [Embedded OLE Library File]"); // TODO: Parse this out and print separately + } + else + { + //if (entry.Data != null) + // Console.WriteLine($"{padding}Value (Byte Data): {BitConverter.ToString(entry.Data).Replace('-', ' ')}"); + if (entry.Data != null) + Console.WriteLine($"{padding}Value (ASCII): {Encoding.ASCII.GetString(entry.Data)}"); + //if (entry.Data != null) + // Console.WriteLine($"{padding}Value (UTF-8): {Encoding.UTF8.GetString(entry.Data)}"); + //if (entry.Data != null) + // Console.WriteLine($"{padding}Value (Unicode): {Encoding.Unicode.GetString(entry.Data)}"); + } } ///