Modify the icon of the EXE file

Source: Internet
Author: User

[Keyword] VC ++, modifying the icon of the EXE file

The famous pandatv virus many years ago has discovered the behavior of searching executable files on the hard disk and infecting them. Its typical appearance isProgramThe icon becomes pandatv. This document describes how to modify the icon of an EXE file (executable file ).ArticleThis article is a technical feasibility study. The following features can be found in files on Windows:

(1) the executable file of an application can have its own defined icons, which are usually located in its resource. The resource manager uses the icons in the resource to display them. If there are no resources, the default executable file icon is displayed.

(2) Although the DLL can contain ICON resources, the system always displays them with the uniform DLL icon.

(3) The shortcut icon can specify the source at will, usually from the target file to which it points. You can modify the shortcut icon at will.

(4) It is the document type registered in the system, such as Doc, txt, and other suffixed files. Its icons are registered in the registry, usually from opening their default programs.

Check the four icons shown above, where (2) depends on the system and cannot be modified or necessary. (1) It is difficult to modify the icon because you must modify the PE file itself. We usually need to use a dedicated resource editing tool (such as vs.net) to open it. This article describes how to modify (1) the icon of the EXE file.

Now let's introduce myCodeThe principle is that the icon is composed of multiple images, and the data of each image is stored in the PE file. I located the data in the PE file, and then overwritten the data with other icons selected by the user. In this way, the icons in the PE file are completely replaced. I have not checked whether the memory write is out of bounds here, because if nothing happens, I will replace the standard icon (usually the color palette of the index image is full, for example, the image color palette of 4bpp is 16 colors, and the image color palette of 8bpp is 256 colors). Therefore, the PE file may not be damaged due to the cross-border operation. Because only the icon is changed, the PE file can still run normally after modification. To prevent exceptions, I will back up the PE file before modification. You can use the backup file to overwrite it back during restoration.

It displays some directory of the PE file using the tool I wrote. Use it to open the windows Notepad program and you can see the position of the icon in the notepad file in the resource table of the PE file:

Note that the icon node is located in the depth of the first subnode, and its entry. ID is 3. The following table contains multiple child nodes, each of which is an image. After each child node reaches the leaf, it is the image data. They are composed of three parts: bitmapinfoheader, color palette (for indexed images), XOR mask data, and mask data (the width of scan rows of the mask data must be 4 bytes aligned ). If you are familiar with the ICO file format, you don't need to introduce it here. For details, refer to the ICO file format.

After I locate the task, the rest of the task is to replace the data here. For this reason, I first load the content of the PE file into the memory, then locate the image data, and try to replace the data with a selected icon. Here I am using the method, the image in the selected icon, such as the image in the PE file, must be replaced. The so-called consistency means that the three data items are exactly the same (width, height, bit depth ), in fact, if the selected icon image (copy source) is smaller than the size of the overwritten data, there is no problem, this is equivalent to some bytes of useless junk data after the image data in the PE file. For example, we use 32*32, 8 BPP image data to overwrite 48*48, 8 BPP data will not cause problems, but here we should also modify the icon height and width information in groupicon at the same time to match the actual image data. However, if we use big data to cover small data, it is absolutely impossible, because we cannot write anything beyond the scope of what we know, it may cause damage to PE files, it even makes him unable to run.

There is a "language" directory under each icon node before it reaches the real leaf node (that is, the entrance to the bitmapinfoheader of the image ). So here I still use a recursive function to find the final leaf node, and then use memcpy to overwrite the data here. Finally, we can rewrite the entire PE file and save it to the hard disk.

The key code is provided here, that is, the following two functions. In the first function, I used imagervatova to locate the corresponding data structure (such as Directory) address in the PE file. To make it clearer, some code related to UI and verification has been omitted.

 

Change_icon

 //  Change icon  
Bool changeicon (hwnd hdlg)
{
Tchar szpath_app [max_path];
Tchar szpath_ico [max_path];

// ... Some unimportant code is omitted here -- hoodlum1980

// Read all programs into memory first
Handle hfile = createfile (szpath_app,
Generic_read,
File_pai_read,
Null,
Open_existing,
File_attribute_normal,
Null );


DWORD dwbytesread = 0 ;
DWORD dwappfilesize = getfilesize (hfile, null );


Pbyte lpbaseaddress = (pbyte) malloc (dwappfilesize );


If (! Readfile (hfile, lpbaseaddress, dwappfilesize, & dwbytesread, null) | dwbytesread! = Dwappfilesize)
{
Closehandle (hfile );
Free (lpbaseaddress );
Return False;
}
Closehandle (hfile ); // Close file

//
// Load icon
//

If (! G_icofile.loadfile (szpath_ico ))
{
Free (lpbaseaddress );
Return False;
}


//
// Replace icon in memory (overwrite memory data)
//

Int Totalimgcount = 0 , Replacedimgcount = 0 ;

Pimage_dos_header pdosheader = (pimage_dos_header) lpbaseaddress;
Pimage_nt_headers pntheaders = (pimage_nt_headers) (lpbaseaddress + pdosheader-> e_lfanew );

Bool bfindicon = false;
// Resource table RVA
DWORD rva_restable = pntheaders-> optionalheader. datadirectory [image_directory_entry_resource]. virtualaddress;
If (Rva_restable> 0 )
{
// This-> loadrestable (lpbaseaddress, pntheaders, rva_restable );
Pimage_resource_directory prestable = (pimage_resource_directory) imagervatova (
Pntheaders,
Lpbaseaddress,
Rva_restable,
Null );

Pimage_resource_directory_entry pentries = (pimage_resource_directory_entry) (DWORD) prestable + Sizeof (Image_resource_directory ));

// Search for icon subnodes (on the first layer)
For ( Int I = 0 ; I <(prestable-> numberofnamedentries + prestable-> numberofidentries); I ++)
{
// This-> addchildnode (hitem_res, lpbaseaddress, pntheaders, (DWORD) prestable, pentries + I, 1 );
If (! Pentries [I]. nameisstring & pentries [I]. ID =3 ) // Icon found?
{
Bfindicon = true;

//
// Now traverse each icon and try to replace the icon data on the leaf node
//

DWORD tableaddress = (DWORD) prestable;
Pimage_resource_directory pdir = (pimage_resource_directory) (tableaddress + pentries [I]. offsettodirectory );
Pimage_resource_directory_entry pentries_icon = (pimage_resource_directory_entry) (DWORD) pdir + Sizeof (Image_resource_directory ));

Totalimgcount = pdir-> numberofnamedentries + pdir-> numberofidentries;

For ( Int J = 0 ; J <totalimgcount; j ++)
{
Overwriteicon (lpbaseaddress, pntheaders, tableaddress, pentries_icon + J, & replacedimgcount );
}
Break ;
}
}
}

If (! Bfindicon)
{
Free (lpbaseaddress );
MessageBox (hdlg, _ T ( " There is no icon in the program file, so you do not need to replace it. " ), _ T ( " Warning " ), Mb_ OK | mb_iconwarning );
Return False;
}

// Save the modified content to app.exe. modified.

Handle hfile2 = createfile (szpath_appmodified,
Generic_write,
File_pai_read,
Null,
Create_always,
File_attribute_normal,
Null );


DWORD dwbytestotal = dwappfilesize;
DWORD dwbytestowrite = 0 , Dwbyteswritten = 0 ;
Pbyte pbytepos = lpbaseaddress;

While (Dwbytestotal> 0 )
{
Dwbytestowrite = min ( 1024 , Dwbytestotal );
Writefile (hfile2, pbytepos, dwbytestowrite, & dwbyteswritten, null );
Dwbytestotal-= dwbytestowrite;
Pbytepos + = dwbytestowrite;
}
Closehandle (hfile2 );

// Release memory
Free (lpbaseaddress );
Lpbaseaddress = NULL;

G_icofile.clear ();

If (! Copyfile (szpath_appmodified, szpath_app, false ))
{
Return False;
}

Deletefile (szpath_appmodified );
Return True;
}

// [Recursive function] a subnode of an icon, but not a leaf node. After Recursion to a leaf node, data is overwritten.

Void Overwriteicon (lpvoid lpbaseaddress,
Pimage_nt_headers pntheaders,
DWORD tableaddress,
Pimage_resource_directory_entry pentry,
Int * Preplacedcount)
{
// Determine the node type (directory or leaf)
If (Pentry-> dataisdirectory)
{
Pimage_resource_directory pdir = (pimage_resource_directory) (tableaddress + pentry-> offsettodirectory );
Pimage_resource_directory_entry pentries = (pimage_resource_directory_entry) (DWORD) pdir + Sizeof (Image_resource_directory ));
For ( Int I = 0 ; I <(pdir-> numberofnamedentries + pdir-> numberofidentries); I ++)
{
Overwriteicon (lpbaseaddress, pntheaders, tableaddress, pentries + I, preplacedcount );
}
}
Else
{
// Leaf node already exists!
Pimage_resource_data_entry pdataentry = (pimage_resource_data_entry) (tableaddress + pentry-> offsettodata );

// The specific resource is located at: pdata-> offsettodata. This is an RVA (not an offset relative to the resource table header !!!)
// Locate the actual resource data

Pbyte lpicondata = (pbyte) imagervatova (pntheaders, lpbaseaddress, pdataentry-> offsettodata, null );


Pbitmapinfoheader pbminfohdr = (pbitmapinfoheader) lpicondata;

Int Imgindex = g_icofile.getimageindex (pbminfohdr-> biwidth, pbminfohdr-> biheight, pbminfohdr-> bibitcount );

If (Imgindex> = 0 )
{
// Overwrite bitmapinfoheader
Int Bytescopy = Sizeof (Bitmapinfoheader) + g_icofile.m_pimages [imgindex]. npalettesize * Sizeof (Rgbquad );
Memcpy (lpicondata, g_icofile.m_pimages [imgindex]. lpinfo, bytescopy );
Lpicondata + = bytescopy;

// Overwrite the XOR mask Section
Bytescopy = g_icofile.m_pimages [imgindex]. nsize_xor;
Memcpy (lpicondata, g_icofile.m_pimages [imgindex]. lpxor, bytescopy );
Lpicondata + = bytescopy;

// Overwrite and mask
Bytescopy = g_icofile.m_pimages [imgindex]. nsize_and;
Memcpy (lpicondata, g_icofile.m_pimages [imgindex]. lpand, bytescopy );
Lpicondata + = bytescopy;

// Increase the number of replaced Images
* Preplacedcount = * preplacedcount + 1 ;
}
}
}

 

 

The following is the demo program: Click the replace icon and try to replace it. After the replacement, the program can still be executed normally without any other damage to the program. Click the restore button to restore the original EXE file. Of course, important system files are protected by system services, so they cannot be replaced. You can select some unimportant EXE files for testing, and this program only modifies the view icon of EXE in the resource manager. Icons after the program runs (for example, the title bar, system tray, and other icons may be set at runtime, and their source may not be in the modified PE file, for example, from other DLL files, these runtime icons cannot be replaced unless you find them and change them ).

In this example, I also used a class (cicofile) that I wrote in The Photoshop ICO file format plug-in. It was also used in image file data viewer earlier, this example is used to load the ICO file.

The following is the complete source code download link of this sample program. To facilitate the test, I also provide an image containing multiple images (from 128*128 to 16*16) the ICO file of the Green Frog, which is located in the debug output directory. The following source code is developed by vs2005 using VC ++ and Win32 SDK (without MFC ):

Http://files.cnblogs.com/hoodlum1980/ChgAppIcon.rar

 

--------------------------------------------

[Supplement]: listicons, a small tool that facilitates searching for the icon Source

 

After developing the Photoshop ICO format plug-in, I found that there is an inconvenient point, that is, if a program contains many DLL and exe files, it is difficult to determine whether the icon is located in that file. If you open the experiment one by one, the efficiency is obviously very low. In the text example, I mentioned that if you want to modify some icons, you must locate them. If we know where the icon comes from (which dll/EXE file), we can easily locate its data based on the structure of the resource table and modify it accordingly. (In this example, all the icons in a PE file are replaced by a violent brain ). So I developed the following tool.

This tool can open a folder, and then try to find the icon in all PE files under the folder, and load it to a listview (the group is enabled Based on the files from. Because the grouping function of listview is required, the operating system must be WINXP or later. As shown in, the icons in all PE files under the System32 folder of the XP system are loaded:

This tool allows you to quickly find the icon position. Here I have not implemented the function of exporting icons. If you need to export icons, you can use iconpro or the ps ico plug-in I developed (of course, you need to install Photoshop before using this plug-in ).

For efficiency, when implementing this tool, I did not recursively traverse subfolders. That is to say, the program will only try to load the files in the root directory of the folder selected by the user. If there are too many files below, for example, there are more than 1700 PE files under system32, I will enable multithreading to display a progress bar dialog box for the user.

The download link between the source code and the compiled version of the tool is as follows:

Http://files.cnblogs.com/hoodlum1980/ListIcons.rar

-- Hoodlum1980, on 2011-8-11.

 

[Supplement: Known issues (resolved )]

 

Use the listicons ToolCreateiconfromresourceWhen a function creates an icon, the GDI object is exposed for unknown reasons. According to the description of msdn, the cause of the leakage of the GDI object is not found. The system displays an exception when a folder containing a large number of icons is added repeatedly.

In addition, the iconpro in the msdn example also has a problem with the leakage of This GDI object (only this problem is not significant, as long as you keep switching the selected icon on the import icon dialog box, you can see that the number of GDI objects slowly increases to 10000 ). It seems that this problem is causedCreateiconfromresourceThis API function is introduced.

 

[Supplement 2: Solving the Problem of GDI object leakage]

 

After my research, I found that, in fact, the leakage of the GDI object is caused by the default icon as the shared mode in the createiconfromresource function, once the icon is obtained by other processes using the "share" method (note:"Sharing"The meaning here is that the objects created, obtained, applied, and used by multiple processes areSame object), Which process does not work whether or not to call functions such as destroyicon.

I estimate that the system may regard shared icons as "long-term use", that is, multiple processes may need to frequently use them, so Shared Mode's GDI objects will not be released. This makes sense for system-level GDI objects. For example, getstockobject and other obtained GDI objects (such as white brush and black brush) actually survive in the system for a long time. This is because these objects are frequently used, so holding them for a long time can save the system running timeliness rate.

Therefore, the potential requirement of the sharing method is: the number of GDI objects requested or created by the program through sharing method should not be too large (Note: Not too many, if the number of GDI objects reaches 10000, this will cause system rendering exceptions. Here I think the number is less than 1000, which is also related to the specific environment). If there are too many, essentially, it is equivalent to the leakage of GDI objects. Because the shared object is released only when the process exits. Therefore, shared objects in small batches will not cause problems, but shared GDI objects in large batches (hundreds of thousands) are held in a process and will continue to grow as the running continues (when the GDI object reaches and approaches 10000) this will definitely cause the system to be unable to draw normally due to the leakage of the GDI object (for example, the pop-up menu background is black, the title bar and other interface elements cannot be re-painted normally, etc, this may be because the system cannot successfully create a new GDI object resource ).

The createiconfromresource function cannot be used to create icons without using the shared method. In other words, the icons created by this API must be in the Shared Mode, even if you have called freelibary to release the corresponding module, these objects still exist in your process. Therefore, when a large number of icons are loaded from a large number of DLL files, the GDI object is exposed.

 

Solution:

To solve this problem, use other API functions to create icons. Here I use the LoadImage function. The last parameter of this function is a flag. You can specify the lr_shared flag, which is equivalent to the sharing mode. It is suitable for objects that need to be loaded frequently (not released ). If lr_shared is specified in the Code, problems encountered by createiconfromresource will also occur.

 

Therefore, replace the createiconfromresouce function with LoadImage, and do not use the lr_shared flag.

 

However, it is pointed out in msdn that some icons will not be loaded successfully if they are not loaded using the shared method. Therefore, I first load the image in a non-shared manner in the Code. If it fails, try sharing again. However, the test found that there is no such special icon that can only be loaded in shared mode.

 

Other items:

The icons in some resources do not contain any images, so no matter what APIs or methods are used, they cannot be exported. For example:

In c: \ windows \ system32 \ ieframe. dll, the ID is 101,104,108,109,114,115,117.
In c: \ windows \ system32 \ shdocvw. dll, the ID is 101,104,107,108,109,114,115,117.

 

[Supplement 3] Description of the program title bar icon

 

The static icon displayed by a program in the resource manager is an icon in its PE file. After the program runs, an icon is displayed on the title bar and the left side of the taskbar button. This is the runtime icon. You can set this icon through seticon. The system uses this icon to draw it on the title bar. Therefore, you can modify the icons on the title bar and the taskbar button as long as you locate these icons.

 

However, the exception is that it is not a non-customer zone (NC) drawn by the system ). For example, for a fully directui window, the entire window is drawn by the user. Such windows are easy to observe because these windows are more personalized in appearance, it is different from the Unified appearance in the system. In this way, we may not be able to replace its "title bar icon" because it may be a "pseudo title bar ". You do not have to use an icon. If it is not an icon, I think it is likely that other bitmap image resources are used, or some built-in image files are loaded at runtime. In this case, you cannot change the icon by replacing the icon. (Essentially because of non-system plotting)

 

One feature of the system title bar is that the title bar icon is a click area, on the title bar iconLeft clickClick (or in the non-Icon area of the title bar)Right-clickClick) The system menu is displayed.

 

-- Hoodlum1980 2011-8-22.

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.