using System; using System.IO; using System.Runtime.InteropServices; using System.Security; namespace Server.Helper; public static class IconInjector { [SuppressUnmanagedCodeSecurity] private class NativeMethods { [DllImport("kernel32")] public static extern IntPtr BeginUpdateResource(string fileName, [MarshalAs(UnmanagedType.Bool)] bool deleteExistingResources); [DllImport("kernel32")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool UpdateResource(IntPtr hUpdate, IntPtr type, IntPtr name, short language, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)] byte[] data, int dataSize); [DllImport("kernel32")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool EndUpdateResource(IntPtr hUpdate, [MarshalAs(UnmanagedType.Bool)] bool discard); } private struct ICONDIR { public ushort Reserved; public ushort Type; public ushort Count; } private struct ICONDIRENTRY { public byte Width; public byte Height; public byte ColorCount; public byte Reserved; public ushort Planes; public ushort BitCount; public int BytesInRes; public int ImageOffset; } private struct BITMAPINFOHEADER { public uint Size; public int Width; public int Height; public ushort Planes; public ushort BitCount; public uint Compression; public uint SizeImage; public int XPelsPerMeter; public int YPelsPerMeter; public uint ClrUsed; public uint ClrImportant; } [StructLayout(LayoutKind.Sequential, Pack = 2)] private struct GRPICONDIRENTRY { public byte Width; public byte Height; public byte ColorCount; public byte Reserved; public ushort Planes; public ushort BitCount; public int BytesInRes; public ushort ID; } private class IconFile { private ICONDIR iconDir; private ICONDIRENTRY[] iconEntry; private byte[][] iconImage; public int ImageCount => iconDir.Count; public byte[] ImageData(int index) { return iconImage[index]; } public static IconFile FromFile(string filename) { IconFile iconFile = new IconFile(); byte[] array = File.ReadAllBytes(filename); GCHandle gCHandle = GCHandle.Alloc(array, GCHandleType.Pinned); iconFile.iconDir = (ICONDIR)Marshal.PtrToStructure(gCHandle.AddrOfPinnedObject(), typeof(ICONDIR)); iconFile.iconEntry = new ICONDIRENTRY[iconFile.iconDir.Count]; iconFile.iconImage = new byte[iconFile.iconDir.Count][]; int num = Marshal.SizeOf(iconFile.iconDir); Type typeFromHandle = typeof(ICONDIRENTRY); int num2 = Marshal.SizeOf(typeFromHandle); for (int i = 0; i <= iconFile.iconDir.Count - 1; i++) { ICONDIRENTRY iCONDIRENTRY = (ICONDIRENTRY)Marshal.PtrToStructure(new IntPtr(gCHandle.AddrOfPinnedObject().ToInt64() + num), typeFromHandle); iconFile.iconEntry[i] = iCONDIRENTRY; iconFile.iconImage[i] = new byte[iCONDIRENTRY.BytesInRes]; Buffer.BlockCopy(array, iCONDIRENTRY.ImageOffset, iconFile.iconImage[i], 0, iCONDIRENTRY.BytesInRes); num += num2; } gCHandle.Free(); return iconFile; } public byte[] CreateIconGroupData(uint iconBaseID) { byte[] array = new byte[Marshal.SizeOf(typeof(ICONDIR)) + Marshal.SizeOf(typeof(GRPICONDIRENTRY)) * ImageCount]; GCHandle gCHandle = GCHandle.Alloc(array, GCHandleType.Pinned); Marshal.StructureToPtr(iconDir, gCHandle.AddrOfPinnedObject(), fDeleteOld: false); int num = Marshal.SizeOf(iconDir); for (int i = 0; i <= ImageCount - 1; i++) { GRPICONDIRENTRY structure = default(GRPICONDIRENTRY); BITMAPINFOHEADER bITMAPINFOHEADER = default(BITMAPINFOHEADER); GCHandle gCHandle2 = GCHandle.Alloc(bITMAPINFOHEADER, GCHandleType.Pinned); Marshal.Copy(ImageData(i), 0, gCHandle2.AddrOfPinnedObject(), Marshal.SizeOf(typeof(BITMAPINFOHEADER))); gCHandle2.Free(); structure.Width = iconEntry[i].Width; structure.Height = iconEntry[i].Height; structure.ColorCount = iconEntry[i].ColorCount; structure.Reserved = iconEntry[i].Reserved; structure.Planes = bITMAPINFOHEADER.Planes; structure.BitCount = bITMAPINFOHEADER.BitCount; structure.BytesInRes = iconEntry[i].BytesInRes; structure.ID = Convert.ToUInt16(iconBaseID + i); Marshal.StructureToPtr(structure, new IntPtr(gCHandle.AddrOfPinnedObject().ToInt64() + num), fDeleteOld: false); num += Marshal.SizeOf(typeof(GRPICONDIRENTRY)); } gCHandle.Free(); return array; } } public static void InjectIcon(string exeFileName, string iconFileName) { InjectIcon(exeFileName, iconFileName, 1u, 1u); } public static void InjectIcon(string exeFileName, string iconFileName, uint iconGroupID, uint iconBaseID) { IconFile iconFile = IconFile.FromFile(iconFileName); IntPtr hUpdate = NativeMethods.BeginUpdateResource(exeFileName, deleteExistingResources: false); byte[] array = iconFile.CreateIconGroupData(iconBaseID); NativeMethods.UpdateResource(hUpdate, new IntPtr(14L), new IntPtr(iconGroupID), 0, array, array.Length); for (int i = 0; i <= iconFile.ImageCount - 1; i++) { byte[] array2 = iconFile.ImageData(i); NativeMethods.UpdateResource(hUpdate, new IntPtr(3L), new IntPtr(iconBaseID + i), 0, array2, array2.Length); } NativeMethods.EndUpdateResource(hUpdate, discard: false); } }