Hacking Icon Resources

Introduction

In this tutorial, I will show you how to replace an application’s icon with a given .ICO file. To keep things simple, you will use an .ICO file containing a single 32×32 image (meaning, I will give the complete source code to accomplish this), but I will provide the general theory to enable you to extend the example to support all types of icons.

There are a lot of icon editors around, so use your favorite one to create a 32×32, 256-color icon.

First Things First: the Structure of an .ICO File on Disk

Icon files have the following structure:

ICON HEADER:
   WORD Reserved             - reserved
   WORD Type                 - 1 means icon, 2 means cursor
   WORD ImageCount           - number of images stored inside the file

   ICON DIRECTORY ENTRY      - there are ImageCount directory entries
      BYTE Width             - width of image
      BYTE Height            - height of image
      BYTE Colors            - 0 means 256 or more
      BYTE Reserved          - reserved
      WORD Planes            - number of planes
      WORD BitsPerPixel      - bits per pixel
      DWORD ImageSize        - size of image data
      DWORD ImageOffset      - offset of image data inside file
   ICON DIRECTORY ENTRY
   ...
   ICON DIRECTORY ENTRY

   ICON IMAGE                - the actual image data (which has the
                               structure of ICON IMAGE a bitmap) found
                               at the location specified by ImageOffset
   ...
   ICON IMAGE

As you can see, a .ICO file can contain more than one image.

The Secret

It isn’t enough to read a .ICO file into memory and insert it as a RC_ICON resource because the resulting resource will be corrupted. In resources, icons are split into several RC_ICON resources and a RC_GROUP_ICON. A RC_ICON entry is basically the above ICON IMAGE. RC_GROUP_ICON contains the ICON HEADER and DIRECTORY ENTRIES with a single modification: The DWORD ImageOffset becomes WORD ResourceID. That is because the actual image data is no longer following its header, so it can be identified by its resource ID.

An application can have several icons contained inside its resources. Usually, the displayed icon has the resource ID equal to 1, but this is not necessary. Windows chooses which icon to display based on the RC_GROUP_ICON resource named ‘MAINICON’. You can use a tool such as PE Explorer to take a look at the resources of compiled executable modules (.EXE and .DLL files).

What You Will Do

You will load the ICON IMAGE of an .ICO file into a buffer, create a structure containing RC_GROUP_ICON resource data, and inject both of these into a given executable file.

Here are some structure declarations:

// Make sure structures are packed the same way as Windows packs them
#pragma pack(push, 2)

typedef struct    // This is the Directory Entry stored in resources
{
   BYTE Width;
   BYTE Height;
   BYTE Colors;
   BYTE Reserved;
   WORD Planes;
   WORD BitsPerPixel;
   DWORD ImageSize;
   WORD ResourceID
} IconDirResEntry, *PIconDirResEntry;

typedef struct    // This is the actual RT_GROUP_ICON structure
{
   WORD Reserved;
   WORD ResourceType;
   WORD ImageCount;
   PIconDirResEntry Enries;    // The number of entries is ImageCount
} GroupIcon;

// Restore default packing
#pragma pack(pop)

For the example, you can declare a simpler structure because you will use an .ICO file containing only one image. You will combine the header and the directory entry into a single structure:

#pragma pack(push, 2)

typedef struct {
  WORD Reserved1;       // reserved, must be 0
  WORD ResourceType;    // type is 1 for icons
  WORD ImageCount;      // number of icons in structure (1)
  BYTE Width;           // icon width (32)
  BYTE Height;          // icon height (32)
  BYTE Colors;          // colors (0 means more than 8 bits per pixel)
  BYTE Reserved2;       // reserved, must be 0
  WORD Planes;          // color planes
  WORD BitsPerPixel;    // bit depth
  DWORD ImageSize;      // size of structure
  WORD ResourceID;      // resource ID
} GROUPICON;

#pragma pack(pop)

The last structure is the RC_GROUP_ICON resource you will inject into the executable.

Using WinAPI

You will update the resources using WinAPI’s BeginUpdateResource, UpdateResource, and EndUpdateResource. Declare a InjectMainIcon method that will receive the filename of an application and the filename of an icon.

A quick overview: BeginUpdateResource receives the name of an executable module and a boolean parameter which, if set to TRUE, will remove all resources found in that executable (you don’t want that).

UpdateResource receives the handle of the module in which to do the update (the handle returned by BeginUpdateResource). It receives the type name of the resource and the name of the resource for which you can use MAKEINTRESOURCE. (For example, type is RC_ICON and name is MAKEINTRESOURCE(1). This inserts an icon resource giving it the ID 1.) It also receives the language identifier. You will use MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)to set the resource’s language to default. Finally, UpdateResource receives a pointer to the buffer containing the resource and the length of that buffer.

The last method you will use is EndUpdateResource. It receives the handle provided by BeginUpdateResource and a boolean parameter that, if set to TRUE, discards all changes made to the resources.

Out of the Windows SDK Documentation:

   HANDLE BeginUpdateResource(
      LPCTSTR pFileName,    // pointer to file in which to update
                            // resources
      BOOL bDeleteExistingResources    // deletion option
     );

   BOOL UpdateResource(
      HANDLE hUpdate,    // update-file handle
      LPCTSTR lpType,    // address of resource type to update
      LPCTSTR lpName,    // address of resource name to update
      WORD wLanguage,    // language identifier of resource
      LPVOID lpData,     // address of resource data
      DWORD cbData       // length of resource data, in bytes
     );

   BOOL EndUpdateResource(
      HANDLE hUpdate,    // update-file handle
      BOOL fDiscard      // write flag
     );

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read