From 8bc30b9b406e69208643b201b8cc93ab95b35107 Mon Sep 17 00:00:00 2001 From: Lloyd Kinsella Date: Tue, 5 Jul 2016 22:47:47 +0100 Subject: [PATCH] Started project that works specifically with resources. --- Src/Demo Application/Demo Application.csproj | 6 + Src/Demo Application/Program.cs | 22 +- .../CursorGroupResource.cs | 172 ++++++++++ Src/Workshell.PE.Resources/CursorResource.cs | 171 ++++++++++ .../Native/BITMAPINFOHEADER.cs | 44 +++ .../Native/CURSORDIR.cs | 21 ++ Src/Workshell.PE.Resources/Native/ICONDIR.cs | 23 ++ .../Native/NEWHEADER.cs | 25 ++ Src/Workshell.PE.Resources/Native/RESDIR.cs | 36 +++ .../Properties/AssemblyInfo.cs | 35 ++ .../Workshell.PE.Resources.csproj | 68 ++++ .../Content/Resources/ResourceProvider.cs | 32 ++ .../Content/Resources/Resources.cs | 303 +++++++----------- Src/Workshell.PE/Properties/AssemblyInfo.cs | 2 + Src/Workshell.PE/Utils.cs | 61 ++++ Src/Workshell.PE/Workshell.PE.csproj | 1 + Src/dotNET PE.2015.sln | 8 +- 17 files changed, 839 insertions(+), 191 deletions(-) create mode 100644 Src/Workshell.PE.Resources/CursorGroupResource.cs create mode 100644 Src/Workshell.PE.Resources/CursorResource.cs create mode 100644 Src/Workshell.PE.Resources/Native/BITMAPINFOHEADER.cs create mode 100644 Src/Workshell.PE.Resources/Native/CURSORDIR.cs create mode 100644 Src/Workshell.PE.Resources/Native/ICONDIR.cs create mode 100644 Src/Workshell.PE.Resources/Native/NEWHEADER.cs create mode 100644 Src/Workshell.PE.Resources/Native/RESDIR.cs create mode 100644 Src/Workshell.PE.Resources/Properties/AssemblyInfo.cs create mode 100644 Src/Workshell.PE.Resources/Workshell.PE.Resources.csproj create mode 100644 Src/Workshell.PE/Content/Resources/ResourceProvider.cs diff --git a/Src/Demo Application/Demo Application.csproj b/Src/Demo Application/Demo Application.csproj index 9925c7e..74208e9 100644 --- a/Src/Demo Application/Demo Application.csproj +++ b/Src/Demo Application/Demo Application.csproj @@ -35,7 +35,9 @@ + + @@ -50,6 +52,10 @@ + + {2b06cbf8-136a-4bec-8624-861992139489} + Workshell.PE.Resources + {2e173d25-1c2e-4a7b-8b37-d231324d372d} Workshell.PE diff --git a/Src/Demo Application/Program.cs b/Src/Demo Application/Program.cs index 80a017b..57909e3 100644 --- a/Src/Demo Application/Program.cs +++ b/Src/Demo Application/Program.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; +using System.Drawing; using System.Linq; using System.Reflection; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading.Tasks; +using System.Windows.Forms; using Workshell.PE; @@ -24,9 +26,6 @@ static void Main(string[] args) //string file_name = @"C:\Windows\System32\shell32.dll"; //string file_name = @"C:\Windows\SysWOW64\xpsservices.dll"; //string file_name = @"c:\windows\system32\advapi32.dll"; - //string file_name = @"P:\Workshell\dotNET Dependency Walker\Bin\Debug\netdepends.exe"; - //string file_name = @"C:\Users\Lloyd\Desktop\PE Related\Tools\PeInternals\x64\PeInternals.exe"; - //string file_name = @"D:\Lloyd\Downloads\Win32DiskImager-0.9.5-install.exe"; string error_message; if (!ExecutableImage.IsValid(file_name,out error_message)) @@ -37,11 +36,18 @@ static void Main(string[] args) } ExecutableImage image = ExecutableImage.FromFile(file_name); - Certificate cert = Certificate.Get(image); - X509Certificate x509 = cert.GetCertificate(); - - if (x509 != null) - X509Certificate2UI.DisplayCertificate((X509Certificate2)x509); + Resources resources = Resources.Get(image); + ResourceType cursor_groups = resources.FirstOrDefault(type => type.Id == ResourceType.RT_GROUP_CURSOR); + Resource group_resource = cursor_groups.FirstOrDefault(res => res.Id == 1001); + CursorGroupResource cursor_group = CursorGroupResource.FromResource(group_resource, Resource.DEFAULT_LANGUAGE); + CursorGroupResourceEntry cursor_entry = cursor_group.FirstOrDefault(); + ResourceType cursors = resources.FirstOrDefault(type => type.Id == ResourceType.RT_CURSOR); + Resource resource = cursors.FirstOrDefault(res => res.Id == cursor_entry.CursorId); + CursorResource cursor_resource = CursorResource.FromResource(resource, Resource.DEFAULT_LANGUAGE); + Cursor cursor = cursor_resource.ToCursor(); + Bitmap bitmap = cursor_resource.ToBitmap(); + + bitmap.Save(@"d:\test.bmp"); Console.ReadKey(); } diff --git a/Src/Workshell.PE.Resources/CursorGroupResource.cs b/Src/Workshell.PE.Resources/CursorGroupResource.cs new file mode 100644 index 0000000..000c1f4 --- /dev/null +++ b/Src/Workshell.PE.Resources/CursorGroupResource.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Workshell.PE.Extensions; +using Workshell.PE.Native; + +namespace Workshell.PE +{ + + public sealed class CursorGroupResourceEntry + { + + internal CursorGroupResourceEntry(CURSOR_RESDIR resDir) + { + Width = resDir.Cursor.Width; + Height = resDir.Cursor.Height; + Planes = resDir.Planes; + BitCount = resDir.BitCount; + BytesInRes = resDir.BytesInRes; + CursorId = resDir.CursorId; + } + + #region Methods + + public override string ToString() + { + return String.Format("{0}x{1} {2}-bit, ID: {3}", Width, Height, BitCount, CursorId); + } + + #endregion + + #region Properties + + public ushort Width + { + get; + private set; + } + + public ushort Height + { + get; + private set; + } + + public ushort Planes + { + get; + private set; + } + + public ushort BitCount + { + get; + private set; + } + + public uint BytesInRes + { + get; + private set; + } + + public ushort CursorId + { + get; + private set; + } + + #endregion + + } + + public sealed class CursorGroupResource : IEnumerable + { + + private CursorGroupResourceEntry[] entries; + + internal CursorGroupResource(CursorGroupResourceEntry[] groupEntries) + { + entries = groupEntries; + } + + #region Static Methods + + public static CursorGroupResource FromBytes(byte[] data) + { + using (MemoryStream mem = new MemoryStream(data)) + { + return FromStream(mem); + } + } + + public static CursorGroupResource FromStream(Stream stream) + { + NEWHEADER header = Utils.Read(stream); + + if (header.ResType != 2) + throw new Exception("Not a cursor group resource."); + + CursorGroupResourceEntry[] entries = new CursorGroupResourceEntry[header.ResCount]; + + for(var i = 0; i < header.ResCount; i++) + { + CURSOR_RESDIR cursor = Utils.Read(stream); + CursorGroupResourceEntry entry = new CursorGroupResourceEntry(cursor); + + entries[i] = entry; + } + + CursorGroupResource group = new CursorGroupResource(entries); + + return group; + } + + public static CursorGroupResource FromResource(Resource resource) + { + return FromResource(resource, Resource.DEFAULT_LANGUAGE); + } + + public static CursorGroupResource FromResource(Resource resource, uint language) + { + byte[] data = resource.ToBytes(language); + + return FromBytes(data); + } + + #endregion + + #region Methods + + public IEnumerator GetEnumerator() + { + for (var i = 0; i < entries.Length; i++) + yield return entries[i]; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion + + #region Properties + + public int Count + { + get + { + return entries.Length; + } + } + + public CursorGroupResourceEntry this[int index] + { + get + { + return entries[index]; + } + } + + #endregion + + } + +} diff --git a/Src/Workshell.PE.Resources/CursorResource.cs b/Src/Workshell.PE.Resources/CursorResource.cs new file mode 100644 index 0000000..3ac0a02 --- /dev/null +++ b/Src/Workshell.PE.Resources/CursorResource.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Workshell.PE +{ + + public class CursorResource + { + + private ushort hotspot_x; + private ushort hotspot_y; + private byte[] dib; + + internal CursorResource(ushort hotspotX, ushort hotspotY, byte[] dibData) + { + hotspot_x = hotspotX; + hotspot_y = hotspotY; + dib = dibData; + } + + #region Static Methods + + public static CursorResource FromBytes(byte[] data) + { + using (MemoryStream mem = new MemoryStream(data)) + { + return FromStream(mem); + } + } + + public static CursorResource FromStream(Stream stream) + { + ushort hotspot_x = Utils.ReadUInt16(stream); + ushort hotspot_y = Utils.ReadUInt16(stream); + byte[] dib; + + using (MemoryStream mem = new MemoryStream()) + { + stream.CopyTo(mem, 4096); + + dib = mem.ToArray(); + } + + CursorResource cursor = new CursorResource(hotspot_x, hotspot_y, dib); + + return cursor; + } + + public static CursorResource FromResource(Resource resource) + { + return FromResource(resource, Resource.DEFAULT_LANGUAGE); + } + + public static CursorResource FromResource(Resource resource, uint language) + { + byte[] data = resource.ToBytes(language); + + return FromBytes(data); + } + + #endregion + + #region Methods + + public void Save(string fileName) + { + using (FileStream file = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None)) + { + Save(file); + file.Flush(); + } + } + + public void Save(Stream stream) + { + using (MemoryStream mem = new MemoryStream(dib)) + { + BITMAPINFOHEADER header = Utils.Read(mem); + + Utils.Write(Convert.ToUInt16(0), stream); + Utils.Write(Convert.ToUInt16(2), stream); + Utils.Write(Convert.ToUInt16(1), stream); + + Utils.Write(Convert.ToByte(header.biWidth), stream); + Utils.Write(Convert.ToByte(header.biHeight), stream); + Utils.Write(Convert.ToByte(0), stream); + Utils.Write(Convert.ToByte(0), stream); + Utils.Write(hotspot_x, stream); + Utils.Write(hotspot_y, stream); + Utils.Write((uint)dib.Length, stream); + Utils.Write((uint)22, stream); + + Utils.Write(dib, stream); + } + } + + public Cursor ToCursor() + { + using (MemoryStream mem = new MemoryStream()) + { + Save(mem); + mem.Seek(0, SeekOrigin.Begin); + + return new Cursor(mem); + } + } + + public Bitmap ToBitmap() + { + return ToBitmap(Color.Transparent); + } + + public Bitmap ToBitmap(Color backgroundColor) + { + using (Cursor cursor = ToCursor()) + { + Rectangle rect = new Rectangle(0, 0, cursor.Size.Width, cursor.Size.Height); + Bitmap bitmap = new Bitmap(rect.Width, rect.Height, PixelFormat.Format32bppArgb); + + using (Graphics graphics = Graphics.FromImage(bitmap)) + { + SolidBrush brush = new SolidBrush(backgroundColor); + + graphics.FillRectangle(brush, rect); + cursor.Draw(graphics, rect); + } + + return bitmap; + } + } + + #endregion + + #region Properties + + public ushort HotspotX + { + get + { + return hotspot_x; + } + } + + public ushort HotspotY + { + get + { + return hotspot_y; + } + } + + public byte[] DIB + { + get + { + return dib; + } + } + + #endregion + + } + +} diff --git a/Src/Workshell.PE.Resources/Native/BITMAPINFOHEADER.cs b/Src/Workshell.PE.Resources/Native/BITMAPINFOHEADER.cs new file mode 100644 index 0000000..2d8028a --- /dev/null +++ b/Src/Workshell.PE.Resources/Native/BITMAPINFOHEADER.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Workshell.PE +{ + + public enum BitmapCompressionMode : uint + { + BI_RGB = 0, + BI_RLE8 = 1, + BI_RLE4 = 2, + BI_BITFIELDS = 3, + BI_JPEG = 4, + BI_PNG = 5 + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct BITMAPINFOHEADER + { + + public uint biSize; + public int biWidth; + public int biHeight; + public ushort biPlanes; + public ushort biBitCount; + public BitmapCompressionMode biCompression; + public uint biSizeImage; + public int biXPelsPerMeter; + public int biYPelsPerMeter; + public uint biClrUsed; + public uint biClrImportant; + + public void Init() + { + biSize = (uint)Marshal.SizeOf(this); + } + + } + +} diff --git a/Src/Workshell.PE.Resources/Native/CURSORDIR.cs b/Src/Workshell.PE.Resources/Native/CURSORDIR.cs new file mode 100644 index 0000000..0f58d7f --- /dev/null +++ b/Src/Workshell.PE.Resources/Native/CURSORDIR.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Workshell.PE.Native +{ + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct CURSORDIR + { + + public ushort Width; + public ushort Height; + + } + +} diff --git a/Src/Workshell.PE.Resources/Native/ICONDIR.cs b/Src/Workshell.PE.Resources/Native/ICONDIR.cs new file mode 100644 index 0000000..4c4a388 --- /dev/null +++ b/Src/Workshell.PE.Resources/Native/ICONDIR.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Workshell.PE.Native +{ + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct ICONDIR + { + + public byte Width; + public byte Height; + public byte ColorCount; + public byte Reserved; + + } + +} diff --git a/Src/Workshell.PE.Resources/Native/NEWHEADER.cs b/Src/Workshell.PE.Resources/Native/NEWHEADER.cs new file mode 100644 index 0000000..9247bf1 --- /dev/null +++ b/Src/Workshell.PE.Resources/Native/NEWHEADER.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Workshell.PE.Native +{ + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct NEWHEADER + { + + public const ushort RES_ICON = 1; + public const ushort RES_CURSOR = 2; + + public ushort Reserved; + public ushort ResType; + public ushort ResCount; + + } + +} diff --git a/Src/Workshell.PE.Resources/Native/RESDIR.cs b/Src/Workshell.PE.Resources/Native/RESDIR.cs new file mode 100644 index 0000000..1c06d9e --- /dev/null +++ b/Src/Workshell.PE.Resources/Native/RESDIR.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Workshell.PE.Native +{ + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct ICON_RESDIR + { + + public ICONDIR Icon; + public ushort Planes; + public ushort BitCount; + public uint BytesInRes; + public ushort IconId; + + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct CURSOR_RESDIR + { + + public CURSORDIR Cursor; + public ushort Planes; + public ushort BitCount; + public uint BytesInRes; + public ushort CursorId; + + } + +} diff --git a/Src/Workshell.PE.Resources/Properties/AssemblyInfo.cs b/Src/Workshell.PE.Resources/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..ebf2307 --- /dev/null +++ b/Src/Workshell.PE.Resources/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Workshell.PE.Resources")] +[assembly: AssemblyDescription("A set of classes for dealing with resources within a PE file.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Workshell Ltd")] +[assembly: AssemblyProduct(".NET PE Resources Class Library")] +[assembly: AssemblyCopyright("Copyright ©2016 Workshell Ltd")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("2b06cbf8-136a-4bec-8624-861992139489")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0")] diff --git a/Src/Workshell.PE.Resources/Workshell.PE.Resources.csproj b/Src/Workshell.PE.Resources/Workshell.PE.Resources.csproj new file mode 100644 index 0000000..73bcd07 --- /dev/null +++ b/Src/Workshell.PE.Resources/Workshell.PE.Resources.csproj @@ -0,0 +1,68 @@ + + + + + Debug + AnyCPU + {2B06CBF8-136A-4BEC-8624-861992139489} + Library + Properties + Workshell.PE.Resources + peres + v4.5 + 512 + + + true + full + false + ..\..\Bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\Bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + {2e173d25-1c2e-4a7b-8b37-d231324d372d} + Workshell.PE + + + + + \ No newline at end of file diff --git a/Src/Workshell.PE/Content/Resources/ResourceProvider.cs b/Src/Workshell.PE/Content/Resources/ResourceProvider.cs new file mode 100644 index 0000000..75861b6 --- /dev/null +++ b/Src/Workshell.PE/Content/Resources/ResourceProvider.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Workshell.PE +{ + + public interface IResourceProvider + { + + Resource Create(ResourceType type, ResourceDirectoryEntry entry); + + } + + public sealed class DefaultResourceProvider : IResourceProvider + { + + #region Methods + + public Resource Create(ResourceType type, ResourceDirectoryEntry entry) + { + Resource resource = new Resource(type, entry); + + return resource; + } + + #endregion + + } + +} diff --git a/Src/Workshell.PE/Content/Resources/Resources.cs b/Src/Workshell.PE/Content/Resources/Resources.cs index 4dfcf01..186e34a 100644 --- a/Src/Workshell.PE/Content/Resources/Resources.cs +++ b/Src/Workshell.PE/Content/Resources/Resources.cs @@ -11,173 +11,90 @@ namespace Workshell.PE { - public sealed class Resource : ISupportsBytes + public sealed class Resource { - private ResourceLanguage language; - private ResourceDataEntry data_entry; + public const uint DEFAULT_LANGUAGE = 1033; - internal Resource(ResourceLanguage resourceLanguage, ResourceDataEntry dataEntry) - { - language = resourceLanguage; - data_entry = dataEntry; - } - - #region Methods - - public byte[] GetBytes() - { - ResourceData data = data_entry.GetData(); - byte[] buffer = data.GetBytes(); - - return buffer; - } + private ResourceType type; + private ResourceDirectoryEntry directory_entry; + private uint id; + private string name; + private Dictionary languages; - public void CopyToStream(Stream stream) + internal Resource(ResourceType owningType, ResourceDirectoryEntry directoryEntry) { - byte[] buffer = GetBytes(); - - stream.Write(buffer, 0, buffer.Length); - } - - #endregion - - #region Properties + type = owningType; + directory_entry = directoryEntry; - public ResourceLanguage Language - { - get + if (directory_entry.NameType == NameType.ID) { - return language; + id = directory_entry.GetId(); + name = null; } - } - - public ResourceDataEntry DataEntry - { - get + else { - return data_entry; + id = 0; + name = directory_entry.GetName(); } - } - - #endregion - - } - - public sealed class ResourceLanguage - { - private ResourceName name; - private ResourceDirectoryEntry directory_entry; - private uint id; - private Resource resource; - - internal ResourceLanguage(ResourceName resourceName, ResourceDirectoryEntry directoryEntry) - { - name = resourceName; - directory_entry = directoryEntry; - id = directory_entry.GetId(); - resource = LoadResource(); + languages = LoadLanguages(); } #region Methods - public override string ToString() + public ResourceData ToData() { - return id.ToString(); + return ToData(DEFAULT_LANGUAGE); } - private Resource LoadResource() + public ResourceData ToData(uint languageId) { - ResourceDataEntry data_entry = directory_entry.GetDataEntry(); - Resource result = new PE.Resource(this, data_entry); - - return result; - } - - #endregion - - #region Properties - - public ResourceName Name - { - get + if (!languages.ContainsKey(languageId)) { - return name; + return null; } - } - - public ResourceDirectoryEntry DirectoryEntry - { - get + else { - return directory_entry; - } - } + ResourceDirectoryEntry language_entry = languages[languageId]; + ResourceDataEntry data_entry = language_entry.GetDataEntry(); + ResourceData data = data_entry.GetData(); - public uint Id - { - get - { - return id; + return data; } } - public Resource Resource + public byte[] ToBytes() { - get - { - return resource; - } + return ToBytes(DEFAULT_LANGUAGE); } - #endregion - - } - - public sealed class ResourceName : IEnumerable - { - - private ResourceType type; - private ResourceDirectoryEntry directory_entry; - private uint id; - private string name; - private ResourceLanguage[] languages; - - internal ResourceName(ResourceType resourceType, ResourceDirectoryEntry directoryEntry) + public byte[] ToBytes(uint languageId) { - type = resourceType; - directory_entry = directoryEntry; - - if (directory_entry.NameType == NameType.ID) + if (!languages.ContainsKey(languageId)) { - id = directory_entry.GetId(); - name = null; + return new byte[0]; } else { - id = 0; - name = directory_entry.GetName(); - } + ResourceDirectoryEntry language_entry = languages[languageId]; + ResourceDataEntry data_entry = language_entry.GetDataEntry(); + ResourceData data = data_entry.GetData(); - languages = LoadLanguages(); + return data.GetBytes(); + } } - #region Methods - - public IEnumerator GetEnumerator() + public void ToStream(Stream stream) { - for(var i = 0; i < languages.Length; i++) - { - ResourceLanguage language = languages[i]; - - yield return language; - } + ToStream(DEFAULT_LANGUAGE, stream); } - IEnumerator IEnumerable.GetEnumerator() + public void ToStream(uint languageId, Stream stream) { - return GetEnumerator(); + byte[] data = ToBytes(languageId); + + stream.Write(data, 0, data.Length); } public override string ToString() @@ -192,19 +109,17 @@ public override string ToString() } } - private ResourceLanguage[] LoadLanguages() + private Dictionary LoadLanguages() { - List results = new List(); + Dictionary results = new Dictionary(); ResourceDirectory directory = directory_entry.GetDirectory(); foreach (ResourceDirectoryEntry entry in directory) { - ResourceLanguage language = new PE.ResourceLanguage(this, entry); - - results.Add(language); + results.Add(entry.GetId(),entry); } - return results.ToArray(); + return results; } #endregion @@ -219,14 +134,6 @@ public ResourceType Type } } - public ResourceDirectoryEntry DirectoryEntry - { - get - { - return directory_entry; - } - } - public uint Id { get @@ -243,19 +150,11 @@ public string Name } } - public int LanguageCount - { - get - { - return languages.Length; - } - } - - public ResourceLanguage this[int index] + public uint[] Languages { get { - return languages[index]; + return languages.Keys.ToArray(); } } @@ -263,7 +162,7 @@ public ResourceLanguage this[int index] } - public sealed class ResourceType : IEnumerable + public sealed class ResourceType : IEnumerable { public const ushort RT_CURSOR = 1; @@ -292,11 +191,11 @@ public sealed class ResourceType : IEnumerable private ResourceDirectoryEntry directory_entry; private uint id; private string name; - private ResourceName[] names; + private Resource[] resource_items; - internal ResourceType(Resources res, ResourceDirectoryEntry directoryEntry) + internal ResourceType(Resources owningResources, ResourceDirectoryEntry directoryEntry) { - resources = res; + resources = owningResources; directory_entry = directoryEntry; if (directory_entry.NameType == NameType.ID) @@ -310,16 +209,16 @@ internal ResourceType(Resources res, ResourceDirectoryEntry directoryEntry) name = directory_entry.GetName(); } - names = LoadResources(); + resource_items = LoadResources(); } #region Methods - public IEnumerator GetEnumerator() + public IEnumerator GetEnumerator() { - for(var i = 0; i < names.Length; i++) + for(var i = 0; i < resource_items.Length; i++) { - ResourceName resource_name = names[i]; + Resource resource_name = resource_items[i]; yield return resource_name; } @@ -348,16 +247,17 @@ public override string ToString() return result; } - private ResourceName[] LoadResources() + private Resource[] LoadResources() { - List results = new List(); + List results = new List(); ResourceDirectory directory = directory_entry.GetDirectory(); foreach(ResourceDirectoryEntry entry in directory) { - ResourceName resource_name = new PE.ResourceName(this, entry); + IResourceProvider provider = (id > 0 ? Resources.GetProvider(id) : Resources.GetProvider(name)); + Resource resource = provider.Create(this, entry); - results.Add(resource_name); + results.Add(resource); } return results.ToArray(); @@ -375,14 +275,6 @@ public Resources Resources } } - public ResourceDirectoryEntry DirectoryEntry - { - get - { - return directory_entry; - } - } - public uint Id { get @@ -399,19 +291,19 @@ public string Name } } - public int NameCount + public int Count { get { - return names.Length; + return resource_items.Length; } } - public ResourceName this[int index] + public Resource this[int index] { get { - return names[index]; + return resource_items[index]; } } @@ -423,12 +315,16 @@ public sealed class Resources : IEnumerable { private static Dictionary> type_info; + private static Dictionary providers; + private static DefaultResourceProvider default_provider; private ResourceType[] types; static Resources() { type_info = new Dictionary>(); + providers = new Dictionary(StringComparer.OrdinalIgnoreCase); + default_provider = new DefaultResourceProvider(); PopulateTypeInfo(); } @@ -476,6 +372,53 @@ public static string GetTypeConstant(uint typeId) } } + public static bool RegisterProvider(uint typeId, IResourceProvider provider) + { + return RegisterProvider(String.Format("#{0}",typeId), provider); + } + + public static bool RegisterProvider(string typeName, IResourceProvider provider) + { + if (providers.ContainsKey(typeName)) + return false; + + providers.Add(typeName, provider); + + return true; + } + + public static bool UnregisterProvider(uint typeId) + { + return UnregisterProvider(String.Format("#{0}", typeId)); + } + + public static bool UnregisterProvider(string typeName) + { + if (!providers.ContainsKey(typeName)) + return false; + + providers.Remove(typeName); + + return true; + } + + public static IResourceProvider GetProvider(uint typeId) + { + return GetProvider(String.Format("#{0}", typeId)); + } + + public static IResourceProvider GetProvider(string typeName) + { + if (!providers.ContainsKey(typeName)) + { + return default_provider; + } + else + { + return providers[typeName]; + } + } + private static void PopulateTypeInfo() { ushort[] known_types = new ushort[] { @@ -500,7 +443,7 @@ private static void PopulateTypeInfo() ResourceType.RT_ANIICON, ResourceType.RT_HTML, ResourceType.RT_MANIFEST - } + }; foreach (ushort type_id in known_types) PopulateTypeInfo(type_id); @@ -618,11 +561,7 @@ private static void PopulateTypeInfo(ushort typeId) public IEnumerator GetEnumerator() { for(var i = 0; i < types.Length; i++) - { - ResourceType type = types[i]; - - yield return type; - } + yield return types[i]; } IEnumerator IEnumerable.GetEnumerator() @@ -636,7 +575,7 @@ private ResourceType[] LoadTypes(ResourceDirectory rootDirectory) foreach(ResourceDirectoryEntry entry in rootDirectory) { - ResourceType type = new ResourceType(this,entry); + ResourceType type = new ResourceType(this, entry); results.Add(type); } @@ -648,7 +587,7 @@ private ResourceType[] LoadTypes(ResourceDirectory rootDirectory) #region Properties - public int TypeCount + public int Count { get { diff --git a/Src/Workshell.PE/Properties/AssemblyInfo.cs b/Src/Workshell.PE/Properties/AssemblyInfo.cs index fb772cd..39d589a 100644 --- a/Src/Workshell.PE/Properties/AssemblyInfo.cs +++ b/Src/Workshell.PE/Properties/AssemblyInfo.cs @@ -33,3 +33,5 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0")] + +[assembly: InternalsVisibleTo("peres")] diff --git a/Src/Workshell.PE/Utils.cs b/Src/Workshell.PE/Utils.cs index cb76afa..3f04d54 100644 --- a/Src/Workshell.PE/Utils.cs +++ b/Src/Workshell.PE/Utils.cs @@ -204,6 +204,67 @@ public static byte[] ReadBytes(Stream stream, Location location) return ReadBytes(stream, location.FileOffset.ToInt64(), location.FileSize.ToInt64()); } + public static void Write(sbyte value, Stream stream) + { + byte[] buffer = BitConverter.GetBytes(value); + + stream.WriteByte((byte)value); + } + + public static void Write(byte value, Stream stream) + { + byte[] buffer = BitConverter.GetBytes(value); + + stream.WriteByte(value); + } + + public static void Write(short value, Stream stream) + { + byte[] buffer = BitConverter.GetBytes(value); + + Write(buffer, stream); + } + + public static void Write(ushort value, Stream stream) + { + byte[] buffer = BitConverter.GetBytes(value); + + Write(buffer, stream); + } + + public static void Write(int value, Stream stream) + { + byte[] buffer = BitConverter.GetBytes(value); + + Write(buffer, stream); + } + + public static void Write(uint value, Stream stream) + { + byte[] buffer = BitConverter.GetBytes(value); + + Write(buffer, stream); + } + + public static void Write(long value, Stream stream) + { + byte[] buffer = BitConverter.GetBytes(value); + + Write(buffer, stream); + } + + public static void Write(ulong value, Stream stream) + { + byte[] buffer = BitConverter.GetBytes(value); + + Write(buffer, stream); + } + + public static void Write(byte[] bytes, Stream stream) + { + stream.Write(bytes, 0, bytes.Length); + } + public static void Write(T structure, byte[] buffer, int startIndex, int count) where T : struct { IntPtr ptr = Marshal.AllocHGlobal(count); diff --git a/Src/Workshell.PE/Workshell.PE.csproj b/Src/Workshell.PE/Workshell.PE.csproj index eeb4d35..236a0a5 100644 --- a/Src/Workshell.PE/Workshell.PE.csproj +++ b/Src/Workshell.PE/Workshell.PE.csproj @@ -78,6 +78,7 @@ + diff --git a/Src/dotNET PE.2015.sln b/Src/dotNET PE.2015.sln index 66d74d8..049e7c4 100644 --- a/Src/dotNET PE.2015.sln +++ b/Src/dotNET PE.2015.sln @@ -1,12 +1,14 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Workshell.PE", "Workshell.PE\Workshell.PE.csproj", "{2E173D25-1C2E-4A7B-8B37-D231324D372D}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo Application", "Demo Application\Demo Application.csproj", "{BE0852C4-A347-4E12-84C3-550AE6E5636F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Workshell.PE.Resources", "Workshell.PE.Resources\Workshell.PE.Resources.csproj", "{2B06CBF8-136A-4BEC-8624-861992139489}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +23,10 @@ Global {BE0852C4-A347-4E12-84C3-550AE6E5636F}.Debug|Any CPU.Build.0 = Debug|Any CPU {BE0852C4-A347-4E12-84C3-550AE6E5636F}.Release|Any CPU.ActiveCfg = Release|Any CPU {BE0852C4-A347-4E12-84C3-550AE6E5636F}.Release|Any CPU.Build.0 = Release|Any CPU + {2B06CBF8-136A-4BEC-8624-861992139489}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2B06CBF8-136A-4BEC-8624-861992139489}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2B06CBF8-136A-4BEC-8624-861992139489}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2B06CBF8-136A-4BEC-8624-861992139489}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE