Sixem

.NET Inject / Change .Exe Icon

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