Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Imports System.Runtime.InteropServices
- Imports System.Security
- Public Class IconInjector
- ' Basically, you can change icons with the UpdateResource api call.
- ' When you make the call you say "I'm updating an icon", and you send the icon data.
- ' The main problem is that ICO files store the icons in one set of structures, and exe/dll files store them in
- ' another set of structures. So you have to translate between the two -- you can't just load the ICO file as
- ' bytes and send them with the UpdateResource api call.
- <SuppressUnmanagedCodeSecurity()> _
- Private Class NativeMethods
- <DllImport("kernel32")> _
- Public Shared Function BeginUpdateResource( _
- ByVal fileName As String, _
- <MarshalAs(UnmanagedType.Bool)> ByVal deleteExistingResources As Boolean) As IntPtr
- End Function
- <DllImport("kernel32")> _
- Public Shared Function UpdateResource( _
- ByVal hUpdate As IntPtr, _
- ByVal type As IntPtr, _
- ByVal name As IntPtr, _
- ByVal language As Short, _
- <MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=5)> _
- ByVal data() As Byte, _
- ByVal dataSize As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
- End Function
- <DllImport("kernel32")> _
- Public Shared Function EndUpdateResource( _
- ByVal hUpdate As IntPtr, _
- <MarshalAs(UnmanagedType.Bool)> ByVal discard As Boolean) As <MarshalAs(UnmanagedType.Bool)> Boolean
- End Function
- End Class
- ' The first structure in an ICO file lets us know how many images are in the file.
- <StructLayout(LayoutKind.Sequential)> _
- Private Structure ICONDIR
- Public Reserved As UShort ' Reserved, must be 0
- Public Type As UShort ' Resource type, 1 for icons.
- Public Count As UShort ' How many images.
- ' The native structure has an array of ICONDIRENTRYs as a final field.
- End Structure
- ' Each ICONDIRENTRY describes one icon stored in the ico file. The offset says where the icon image data
- ' starts in the file. The other fields give the information required to turn that image data into a valid
- ' bitmap.
- <StructLayout(LayoutKind.Sequential)> _
- Private Structure ICONDIRENTRY
- Public Width As Byte ' Width, in pixels, of the image
- Public Height As Byte ' Height, in pixels, of the image
- Public ColorCount As Byte ' Number of colors in image (0 if >=8bpp)
- Public Reserved As Byte ' Reserved ( must be 0)
- Public Planes As UShort ' Color Planes
- Public BitCount As UShort ' Bits per pixel
- Public BytesInRes As Integer ' Length in bytes of the pixel data
- Public ImageOffset As Integer ' Offset in the file where the pixel data starts.
- End Structure
- ' Each image is stored in the file as an ICONIMAGE structure:
- 'typdef struct
- '{
- ' BITMAPINFOHEADER icHeader; // DIB header
- ' RGBQUAD icColors[1]; // Color table
- ' BYTE icXOR[1]; // DIB bits for XOR mask
- ' BYTE icAND[1]; // DIB bits for AND mask
- '} ICONIMAGE, *LPICONIMAGE;
- <StructLayout(LayoutKind.Sequential)> _
- Private Structure BITMAPINFOHEADER
- Public Size As UInteger
- Public Width As Integer
- Public Height As Integer
- Public Planes As UShort
- Public BitCount As UShort
- Public Compression As UInteger
- Public SizeImage As UInteger
- Public XPelsPerMeter As Integer
- Public YPelsPerMeter As Integer
- Public ClrUsed As UInteger
- Public ClrImportant As UInteger
- End Structure
- ' The icon in an exe/dll file is stored in a very similar structure:
- <StructLayout(LayoutKind.Sequential, Pack:=2)> _
- Private Structure GRPICONDIRENTRY
- Public Width As Byte
- Public Height As Byte
- Public ColorCount As Byte
- Public Reserved As Byte
- Public Planes As UShort
- Public BitCount As UShort
- Public BytesInRes As Integer
- Public ID As UShort
- End Structure
- Public Shared Sub InjectIcon(ByVal exeFileName As String, ByVal iconFileName As String)
- InjectIcon(exeFileName, iconFileName, 1, 1)
- End Sub
- Public Shared Sub InjectIcon(ByVal exeFileName As String, ByVal iconFileName As String, ByVal iconGroupID As UInteger, ByVal iconBaseID As UInteger)
- Const RT_ICON = 3UI
- Const RT_GROUP_ICON = 14UI
- Dim iconFile As IconFile = iconFile.FromFile(iconFileName)
- Dim hUpdate = NativeMethods.BeginUpdateResource(exeFileName, False)
- Dim data = iconFile.CreateIconGroupData(iconBaseID)
- NativeMethods.UpdateResource(hUpdate, New IntPtr(RT_GROUP_ICON), New IntPtr(iconGroupID), 0, data, data.Length)
- For i = 0 To iconFile.ImageCount - 1
- Dim image = iconFile.ImageData(i)
- NativeMethods.UpdateResource(hUpdate, New IntPtr(RT_ICON), New IntPtr(iconBaseID + i), 0, image, image.Length)
- Next
- NativeMethods.EndUpdateResource(hUpdate, False)
- End Sub
- Private Class IconFile
- Private iconDir As New ICONDIR
- Private iconEntry() As ICONDIRENTRY
- Private iconImage()() As Byte
- Public ReadOnly Property ImageCount() As Integer
- Get
- Return iconDir.Count
- End Get
- End Property
- Public ReadOnly Property ImageData(ByVal index As Integer) As Byte()
- Get
- Return iconImage(index)
- End Get
- End Property
- Private Sub New()
- End Sub
- Public Shared Function FromFile(ByVal filename As String) As IconFile
- Dim instance As New IconFile
- ' Read all the bytes from the file.
- Dim fileBytes() As Byte = IO.File.ReadAllBytes(filename)
- ' First struct is an ICONDIR
- ' Pin the bytes from the file in memory so that we can read them.
- ' If we didn't pin them then they could move around (e.g. when the
- ' garbage collector compacts the heap)
- Dim pinnedBytes = GCHandle.Alloc(fileBytes, GCHandleType.Pinned)
- ' Read the ICONDIR
- instance.iconDir = DirectCast(Marshal.PtrToStructure(pinnedBytes.AddrOfPinnedObject, GetType(ICONDIR)), ICONDIR)
- ' which tells us how many images are in the ico file. For each image, there's a ICONDIRENTRY, and associated pixel data.
- instance.iconEntry = New ICONDIRENTRY(instance.iconDir.Count - 1) {}
- instance.iconImage = New Byte(instance.iconDir.Count - 1)() {}
- ' The first ICONDIRENTRY will be immediately after the ICONDIR, so the offset to it is the size of ICONDIR
- Dim offset = Marshal.SizeOf(instance.iconDir)
- ' After reading an ICONDIRENTRY we step forward by the size of an ICONDIRENTRY
- Dim iconDirEntryType = GetType(ICONDIRENTRY)
- Dim size = Marshal.SizeOf(iconDirEntryType)
- For i = 0 To instance.iconDir.Count - 1
- ' Grab the structure.
- Dim entry = DirectCast(Marshal.PtrToStructure(New IntPtr(pinnedBytes.AddrOfPinnedObject.ToInt64 + offset), iconDirEntryType), ICONDIRENTRY)
- instance.iconEntry(i) = entry
- ' Grab the associated pixel data.
- instance.iconImage(i) = New Byte(entry.BytesInRes - 1) {}
- Buffer.BlockCopy(fileBytes, entry.ImageOffset, instance.iconImage(i), 0, entry.BytesInRes)
- offset += size
- Next
- pinnedBytes.Free()
- Return instance
- End Function
- Public Function CreateIconGroupData(ByVal iconBaseID As UInteger) As Byte()
- ' This will store the memory version of the icon.
- Dim sizeOfIconGroupData As Integer = Marshal.SizeOf(GetType(ICONDIR)) + Marshal.SizeOf(GetType(GRPICONDIRENTRY)) * ImageCount
- Dim data(sizeOfIconGroupData - 1) As Byte
- Dim pinnedData = GCHandle.Alloc(data, GCHandleType.Pinned)
- Marshal.StructureToPtr(iconDir, pinnedData.AddrOfPinnedObject, False)
- Dim offset = Marshal.SizeOf(iconDir)
- For i = 0 To ImageCount - 1
- Dim grpEntry As New GRPICONDIRENTRY
- Dim bitmapheader As New BITMAPINFOHEADER
- Dim pinnedBitmapInfoHeader = GCHandle.Alloc(bitmapheader, GCHandleType.Pinned)
- Marshal.Copy(ImageData(i), 0, pinnedBitmapInfoHeader.AddrOfPinnedObject, Marshal.SizeOf(GetType(BITMAPINFOHEADER)))
- pinnedBitmapInfoHeader.Free()
- grpEntry.Width = iconEntry(i).Width
- grpEntry.Height = iconEntry(i).Height
- grpEntry.ColorCount = iconEntry(i).ColorCount
- grpEntry.Reserved = iconEntry(i).Reserved
- grpEntry.Planes = bitmapheader.Planes
- grpEntry.BitCount = bitmapheader.BitCount
- grpEntry.BytesInRes = iconEntry(i).BytesInRes
- grpEntry.ID = CType(iconBaseID + i, UShort)
- Marshal.StructureToPtr(grpEntry, New IntPtr(pinnedData.AddrOfPinnedObject.ToInt64 + offset), False)
- offset += Marshal.SizeOf(GetType(GRPICONDIRENTRY))
- Next
- pinnedData.Free()
- Return data
- End Function
- End Class
- End Class
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement