Advertisement
GreyPhantom

IconInjector.vb Class

Sep 29th, 2014
2,355
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
VB.NET 9.29 KB | None | 0 0
  1. Imports System.Runtime.InteropServices
  2. Imports System.Security
  3.  
  4. Public Class IconInjector
  5.  
  6.     ' Basically, you can change icons with the UpdateResource api call.
  7.     ' When you make the call you say "I'm updating an icon", and you send the icon data.
  8.     ' The main problem is that ICO files store the icons in one set of structures, and exe/dll files store them in
  9.     ' another set of structures. So you have to translate between the two -- you can't just load the ICO file as
  10.     ' bytes and send them with the UpdateResource api call.
  11.  
  12.     <SuppressUnmanagedCodeSecurity()> _
  13.     Private Class NativeMethods
  14.         <DllImport("kernel32")> _
  15.         Public Shared Function BeginUpdateResource( _
  16.     ByVal fileName As String, _
  17.     <MarshalAs(UnmanagedType.Bool)> ByVal deleteExistingResources As Boolean) As IntPtr
  18.         End Function
  19.  
  20.         <DllImport("kernel32")> _
  21.         Public Shared Function UpdateResource( _
  22.     ByVal hUpdate As IntPtr, _
  23.     ByVal type As IntPtr, _
  24.     ByVal name As IntPtr, _
  25.     ByVal language As Short, _
  26.     <MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=5)> _
  27.     ByVal data() As Byte, _
  28.     ByVal dataSize As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
  29.         End Function
  30.  
  31.         <DllImport("kernel32")> _
  32.         Public Shared Function EndUpdateResource( _
  33.     ByVal hUpdate As IntPtr, _
  34.     <MarshalAs(UnmanagedType.Bool)> ByVal discard As Boolean) As <MarshalAs(UnmanagedType.Bool)> Boolean
  35.         End Function
  36.     End Class
  37.  
  38.     ' The first structure in an ICO file lets us know how many images are in the file.
  39.     <StructLayout(LayoutKind.Sequential)> _
  40.     Private Structure ICONDIR
  41.         Public Reserved As UShort  ' Reserved, must be 0
  42.         Public Type As UShort  ' Resource type, 1 for icons.
  43.         Public Count As UShort  ' How many images.
  44.         ' The native structure has an array of ICONDIRENTRYs as a final field.
  45.     End Structure
  46.  
  47.     ' Each ICONDIRENTRY describes one icon stored in the ico file. The offset says where the icon image data
  48.     ' starts in the file. The other fields give the information required to turn that image data into a valid
  49.     ' bitmap.
  50.     <StructLayout(LayoutKind.Sequential)> _
  51.     Private Structure ICONDIRENTRY
  52.         Public Width As Byte    ' Width, in pixels, of the image
  53.         Public Height As Byte  ' Height, in pixels, of the image
  54.         Public ColorCount As Byte  ' Number of colors in image (0 if >=8bpp)
  55.         Public Reserved As Byte  ' Reserved ( must be 0)
  56.         Public Planes As UShort  ' Color Planes
  57.         Public BitCount As UShort  ' Bits per pixel
  58.         Public BytesInRes As Integer   ' Length in bytes of the pixel data
  59.         Public ImageOffset As Integer  ' Offset in the file where the pixel data starts.
  60.     End Structure
  61.  
  62.     ' Each image is stored in the file as an ICONIMAGE structure:
  63.     'typdef struct
  64.     '{
  65.     '   BITMAPINFOHEADER   icHeader;  // DIB header
  66.     '   RGBQUAD  icColors[1];   // Color table
  67.     '   BYTE    icXOR[1];  // DIB bits for XOR mask
  68.     '   BYTE    icAND[1];  // DIB bits for AND mask
  69.     '} ICONIMAGE, *LPICONIMAGE;
  70.  
  71.     <StructLayout(LayoutKind.Sequential)> _
  72.     Private Structure BITMAPINFOHEADER
  73.         Public Size As UInteger
  74.         Public Width As Integer
  75.         Public Height As Integer
  76.         Public Planes As UShort
  77.         Public BitCount As UShort
  78.         Public Compression As UInteger
  79.         Public SizeImage As UInteger
  80.         Public XPelsPerMeter As Integer
  81.         Public YPelsPerMeter As Integer
  82.         Public ClrUsed As UInteger
  83.         Public ClrImportant As UInteger
  84.     End Structure
  85.  
  86.     ' The icon in an exe/dll file is stored in a very similar structure:
  87.     <StructLayout(LayoutKind.Sequential, Pack:=2)> _
  88.     Private Structure GRPICONDIRENTRY
  89.         Public Width As Byte
  90.         Public Height As Byte
  91.         Public ColorCount As Byte
  92.         Public Reserved As Byte
  93.         Public Planes As UShort
  94.         Public BitCount As UShort
  95.         Public BytesInRes As Integer
  96.         Public ID As UShort
  97.     End Structure
  98.  
  99.     Public Shared Sub InjectIcon(ByVal exeFileName As String, ByVal iconFileName As String)
  100.         InjectIcon(exeFileName, iconFileName, 1, 1)
  101.     End Sub
  102.  
  103.     Public Shared Sub InjectIcon(ByVal exeFileName As String, ByVal iconFileName As String, ByVal iconGroupID As UInteger, ByVal iconBaseID As UInteger)
  104.         Const RT_ICON = 3UI
  105.         Const RT_GROUP_ICON = 14UI
  106.         Dim iconFile As IconFile = iconFile.FromFile(iconFileName)
  107.         Dim hUpdate = NativeMethods.BeginUpdateResource(exeFileName, False)
  108.         Dim data = iconFile.CreateIconGroupData(iconBaseID)
  109.         NativeMethods.UpdateResource(hUpdate, New IntPtr(RT_GROUP_ICON), New IntPtr(iconGroupID), 0, data, data.Length)
  110.         For i = 0 To iconFile.ImageCount - 1
  111.             Dim image = iconFile.ImageData(i)
  112.             NativeMethods.UpdateResource(hUpdate, New IntPtr(RT_ICON), New IntPtr(iconBaseID + i), 0, image, image.Length)
  113.         Next
  114.         NativeMethods.EndUpdateResource(hUpdate, False)
  115.     End Sub
  116.  
  117.     Private Class IconFile
  118.  
  119.         Private iconDir As New ICONDIR
  120.         Private iconEntry() As ICONDIRENTRY
  121.         Private iconImage()() As Byte
  122.  
  123.         Public ReadOnly Property ImageCount() As Integer
  124.             Get
  125.                 Return iconDir.Count
  126.             End Get
  127.         End Property
  128.  
  129.         Public ReadOnly Property ImageData(ByVal index As Integer) As Byte()
  130.             Get
  131.                 Return iconImage(index)
  132.             End Get
  133.         End Property
  134.  
  135.         Private Sub New()
  136.         End Sub
  137.  
  138.         Public Shared Function FromFile(ByVal filename As String) As IconFile
  139.             Dim instance As New IconFile
  140.             ' Read all the bytes from the file.
  141.             Dim fileBytes() As Byte = IO.File.ReadAllBytes(filename)
  142.             ' First struct is an ICONDIR
  143.             ' Pin the bytes from the file in memory so that we can read them.
  144.             ' If we didn't pin them then they could move around (e.g. when the
  145.             ' garbage collector compacts the heap)
  146.             Dim pinnedBytes = GCHandle.Alloc(fileBytes, GCHandleType.Pinned)
  147.             ' Read the ICONDIR
  148.             instance.iconDir = DirectCast(Marshal.PtrToStructure(pinnedBytes.AddrOfPinnedObject, GetType(ICONDIR)), ICONDIR)
  149.             ' which tells us how many images are in the ico file. For each image, there's a ICONDIRENTRY, and associated pixel data.
  150.             instance.iconEntry = New ICONDIRENTRY(instance.iconDir.Count - 1) {}
  151.             instance.iconImage = New Byte(instance.iconDir.Count - 1)() {}
  152.             ' The first ICONDIRENTRY will be immediately after the ICONDIR, so the offset to it is the size of ICONDIR
  153.             Dim offset = Marshal.SizeOf(instance.iconDir)
  154.             ' After reading an ICONDIRENTRY we step forward by the size of an ICONDIRENTRY    
  155.             Dim iconDirEntryType = GetType(ICONDIRENTRY)
  156.             Dim size = Marshal.SizeOf(iconDirEntryType)
  157.             For i = 0 To instance.iconDir.Count - 1
  158.                 ' Grab the structure.
  159.                 Dim entry = DirectCast(Marshal.PtrToStructure(New IntPtr(pinnedBytes.AddrOfPinnedObject.ToInt64 + offset), iconDirEntryType), ICONDIRENTRY)
  160.                 instance.iconEntry(i) = entry
  161.                 ' Grab the associated pixel data.
  162.                 instance.iconImage(i) = New Byte(entry.BytesInRes - 1) {}
  163.                 Buffer.BlockCopy(fileBytes, entry.ImageOffset, instance.iconImage(i), 0, entry.BytesInRes)
  164.                 offset += size
  165.             Next
  166.             pinnedBytes.Free()
  167.             Return instance
  168.         End Function
  169.  
  170.         Public Function CreateIconGroupData(ByVal iconBaseID As UInteger) As Byte()
  171.             ' This will store the memory version of the icon.
  172.             Dim sizeOfIconGroupData As Integer = Marshal.SizeOf(GetType(ICONDIR)) + Marshal.SizeOf(GetType(GRPICONDIRENTRY)) * ImageCount
  173.             Dim data(sizeOfIconGroupData - 1) As Byte
  174.             Dim pinnedData = GCHandle.Alloc(data, GCHandleType.Pinned)
  175.             Marshal.StructureToPtr(iconDir, pinnedData.AddrOfPinnedObject, False)
  176.             Dim offset = Marshal.SizeOf(iconDir)
  177.             For i = 0 To ImageCount - 1
  178.                 Dim grpEntry As New GRPICONDIRENTRY
  179.                 Dim bitmapheader As New BITMAPINFOHEADER
  180.                 Dim pinnedBitmapInfoHeader = GCHandle.Alloc(bitmapheader, GCHandleType.Pinned)
  181.                 Marshal.Copy(ImageData(i), 0, pinnedBitmapInfoHeader.AddrOfPinnedObject, Marshal.SizeOf(GetType(BITMAPINFOHEADER)))
  182.                 pinnedBitmapInfoHeader.Free()
  183.                 grpEntry.Width = iconEntry(i).Width
  184.                 grpEntry.Height = iconEntry(i).Height
  185.                 grpEntry.ColorCount = iconEntry(i).ColorCount
  186.                 grpEntry.Reserved = iconEntry(i).Reserved
  187.                 grpEntry.Planes = bitmapheader.Planes
  188.                 grpEntry.BitCount = bitmapheader.BitCount
  189.                 grpEntry.BytesInRes = iconEntry(i).BytesInRes
  190.                 grpEntry.ID = CType(iconBaseID + i, UShort)
  191.                 Marshal.StructureToPtr(grpEntry, New IntPtr(pinnedData.AddrOfPinnedObject.ToInt64 + offset), False)
  192.                 offset += Marshal.SizeOf(GetType(GRPICONDIRENTRY))
  193.             Next
  194.             pinnedData.Free()
  195.             Return data
  196.         End Function
  197.  
  198.     End Class
  199.  
  200. End Class
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement