终于修改了EXE的图标罗

这些天研究怎样修改EXE文件里面的图标,看了antghazi<<如何修改可执行文件的图标>>一文,一开始连代码该怎么打也不知道,后来代码拼出来了,有些地方还是不明白,耽搁了两三天.

关键就在
 pFirstIcon = firstIconData->OffsetToData - rsrc_SectionHeader->VirtualAddress + (char*)dirRoot;

为什么要减去 VirtualAddress  呢?

最后看了张正秋的<>网上试读的文章,才明白了些.

OffsetToData是一个内存中的RVA,用这个值减去"资源节的开始RVA"(对应的Section Header的VirtualAddress),就可以得到相对于资源节开始的偏移。

得到的是相于于资源节,也就是相对于.rsrc节的偏移地址.加上它!就是第一个图标的图像数据了.

至少是为什么要这样减,我还没弄清楚,暂时死记下来算了。

感觉资源树好麻烦,还是不明白里面是怎么分布的.

理解PE的文件格式和资源树对理解那些代码至关重要!!!

PE文件的格式示意图(完全按我个人理解,勿以为是标准)

Dos Header Dos Stub PE Header Section Header 1 Section Header …… Section Header n Section 1 Section …… Section  n

PE文件的资源树,个人觉得不好理解,就讲本例子中一个图标图像数据获取的过程吧。

先确定一个事实,图标放在盒子里面,盒子放在抽屉里面,抽屉嵌在柜子上。

1.找到资源段的Section Header。

2.根据Section Header找到资源段。

3.在资源段里面找到图标的"柜子",有不少柜子,找到专放图标的。

4.在图标的"柜子"里面找到放第一个图标的"抽屉"。里面不止一个抽屉,
有些抽屉放着图标,有些没有放。我们找到第一个就算了。

5.在放图标的"抽屉"里面找到放图标的"盒子"。

6.盒子打开后,里面没有图标???不过有张纸,写着图标在哪。然后我们去找就是了。

不知道有没有人没听懂。。。。。。

贴出来的代码是完整的,但不能直接运行,你先在程序运行的当前目录下放两个EXE,一个叫Test1.exe,一个叫Test2.exe。图标要不一样的(不然怎么试)。然后运行程序后,Test2.exe的图标会变成Test1.exe的图标。

主要写了两个函数
1.GetIconData 得到EXE的第一个图标的图像数据。
2.WriteIconData 把图像数据写入(替换)EXE中第一个图标。

要注意的是,写入图标数据时不考虑是否与之前图标大小一致的问题,因为本人也不知道如果不一致又怎么办。。。

源代码的前部分写注释比较多,后面部分,我自己都有点晕,所以注释不大好写。

哇,三点多了,我死。不写了。欢迎有人来指点我啊。

#include "stdafx.h"
#include "stdlib.h"
#include "windows.h"


void GetIconData(char *pfile,char **pdata,DWORD *size)
{
 HANDLE hSrcFile;
 DWORD dwFileSize;
 char *pSrcFile;
 DWORD dwReaded;
 IMAGE_DOS_HEADER *dosHeader;
 IMAGE_NT_HEADERS *ntHeader;

 IMAGE_SECTION_HEADER *sectionHeader;
 IMAGE_SECTION_HEADER *rsrc_SectionHeader;

 IMAGE_RESOURCE_DIRECTORY *dirRoot;

 IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
 IMAGE_RESOURCE_DIRECTORY_ENTRY *iconEntry;

 IMAGE_RESOURCE_DIRECTORY *tempDir;
 IMAGE_RESOURCE_DIRECTORY_ENTRY *tempEntry;
 
 IMAGE_RESOURCE_DIRECTORY *firstIconDir;
 IMAGE_RESOURCE_DIRECTORY_ENTRY *firstIconEntry;
 IMAGE_RESOURCE_DATA_ENTRY *firstIconData;

 char *pFirstIcon;

 /*将目标EXE文件读入内存(不同于操作系统的调用)*/
 hSrcFile = CreateFile(pfile,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
 if(hSrcFile == INVALID_HANDLE_VALUE)
 {
  printf("Can't open the %s file./n",pfile);return;
 }
 dwFileSize = GetFileSize(hSrcFile,NULL);
 pSrcFile = (char *)malloc(dwFileSize);
 ReadFile(hSrcFile,pSrcFile,dwFileSize,&dwReaded,NULL);
 //至此pSrcFile已是目标EXE文件在内存的首地址了.

 /*下一步就是找出Dos Header.*/
 dosHeader = (IMAGE_DOS_HEADER*)pSrcFile;
 /*根据dosHeader里面的一个成员找到PE Header.*/
 ntHeader = (IMAGE_NT_HEADERS*)(pSrcFile + dosHeader->e_lfanew);
 /*找出第一个Sesion Header.*/
 sectionHeader = (IMAGE_SECTION_HEADER*)((char*)ntHeader + sizeof(IMAGE_NT_HEADERS));
 /*找出.rsrc的Section Header.*/
 printf("There are the Section Header follow./n");
 for(int i=0;iFileHeader.NumberOfSections;i++,sectionHeader++)
 {
  printf("Section Header #%d: %s/n",i+1,sectionHeader->Name);
  if(strcmp((char*)sectionHeader->Name,".rsrc") == 0)
   rsrc_SectionHeader = sectionHeader;///找到.rsrc的Section Header了!!!
 }
 /*找出.rsrc Section.*/
 dirRoot = (IMAGE_RESOURCE_DIRECTORY*)(pSrcFile + rsrc_SectionHeader->PointerToRawData);
 /*找出第一个资源目录*/
 entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)((char*)dirRoot +sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
 /*找出.rsrc 中 Icon 的资源目录*/
 printf("There are the directory of the .rsrc Section./n");
 for(int j=0;jNumberOfIdEntries+dirRoot->NumberOfNamedEntries;j++,entry++)
 {
  printf("Resource Directory #%d: %d/n",j+1,entry->Name);
  if(entry->Name == 3)
   iconEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)((char*)dirRoot+entry->OffsetToDirectory);//找到 Icon 的资源目录了!!!
 }
 tempDir = (IMAGE_RESOURCE_DIRECTORY*)iconEntry;
 tempEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)((char*)tempDir+sizeof(IMAGE_RESOURCE_DIRECTORY));
 printf("There are the /"IconItems/" of the icon directory./n");
 for(int k=0;kNumberOfIdEntries+tempDir->NumberOfNamedEntries;k++,tempEntry++)
 {
  printf("IconItem %d  Is %d/n",k+1,tempEntry->DataIsDirectory);
  if(tempEntry->DataIsDirectory > 0 && k ==0 )
  {
   //拿到第一个图标的"Item"
   firstIconDir = (IMAGE_RESOURCE_DIRECTORY*)((char *)dirRoot+tempEntry->OffsetToDirectory);
   firstIconEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)((char*)firstIconDir+sizeof(IMAGE_RESOURCE_DIRECTORY));
   firstIconData = (IMAGE_RESOURCE_DATA_ENTRY*)((char*)dirRoot+firstIconEntry->OffsetToData);
  }
 }
 //得到第一个图标Item的图像数据的物理地址
 pFirstIcon = firstIconData->OffsetToData - rsrc_SectionHeader->VirtualAddress + (char*)dirRoot;
 //返回
 *size = firstIconData->Size;
 *pdata = (char*)malloc(firstIconData->Size);
 memcpy(*pdata,pFirstIcon,*size);
 
 /*释放资源.*/
 CloseHandle(hSrcFile);
 free(pSrcFile);

}


void WriteIconData(char *pfile,const char *pdata,DWORD size)
{
 HANDLE hSrcFile;
 DWORD dwFileSize;
 char *pSrcFile;
 DWORD dwReaded;
 IMAGE_DOS_HEADER *dosHeader;
 IMAGE_NT_HEADERS *ntHeader;

 IMAGE_SECTION_HEADER *sectionHeader;
 IMAGE_SECTION_HEADER *rsrc_SectionHeader;

 IMAGE_RESOURCE_DIRECTORY *dirRoot;

 IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
 IMAGE_RESOURCE_DIRECTORY_ENTRY *iconEntry;

 IMAGE_RESOURCE_DIRECTORY *tempDir;
 IMAGE_RESOURCE_DIRECTORY_ENTRY *tempEntry;

 IMAGE_RESOURCE_DIRECTORY *firstIconDir;
 IMAGE_RESOURCE_DIRECTORY_ENTRY *firstIconEntry;
 IMAGE_RESOURCE_DATA_ENTRY *firstIconData;

 char *pFirstIcon;

 /*将目标EXE文件读入内存(不同于操作系统的调用)*/
 hSrcFile = CreateFile(pfile,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
 if(hSrcFile == INVALID_HANDLE_VALUE)
 {
  printf("Can't open the %s file./n",pfile);return;
 }
 dwFileSize = GetFileSize(hSrcFile,NULL);
 pSrcFile = (char *)malloc(dwFileSize);
 ReadFile(hSrcFile,pSrcFile,dwFileSize,&dwReaded,NULL);
 //至此pSrcFile已是目标EXE文件在内存的首地址了.

 /*下一步就是找出Dos Header.*/
 dosHeader = (IMAGE_DOS_HEADER*)pSrcFile;
 /*根据dosHeader里面的一个成员找到PE Header.*/
 ntHeader = (IMAGE_NT_HEADERS*)(pSrcFile + dosHeader->e_lfanew);
 /*找出第一个Sesion Header.*/
 sectionHeader = (IMAGE_SECTION_HEADER*)((char*)ntHeader + sizeof(IMAGE_NT_HEADERS));
 /*找出.rsrc的Section Header.*/
 printf("There are the Section Header follow./n");
 for(int i=0;iFileHeader.NumberOfSections;i++,sectionHeader++)
 {
  printf("Section Header #%d: %s/n",i+1,sectionHeader->Name);
  if(strcmp((char*)sectionHeader->Name,".rsrc") == 0)
   rsrc_SectionHeader = sectionHeader;///找到.rsrc的Section Header了!!!
 }
 /*找出.rsrc Section.*/
 dirRoot = (IMAGE_RESOURCE_DIRECTORY*)(pSrcFile + rsrc_SectionHeader->PointerToRawData);
 /*找出第一个资源目录*/
 entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)((char*)dirRoot +sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
 /*找出.rsrc 中 Icon 的资源目录*/
 printf("There are the directory of the .rsrc Section./n");
 for(int j=0;jNumberOfIdEntries+dirRoot->NumberOfNamedEntries;j++,entry++)
 {
  printf("Resource Directory #%d: %d/n",j+1,entry->Name);
  if(entry->Name == 3)
   iconEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)((char*)dirRoot+entry->OffsetToDirectory);//找到 Icon 的资源目录了!!!
 }
 tempDir = (IMAGE_RESOURCE_DIRECTORY*)iconEntry;
 tempEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)((char*)tempDir+sizeof(IMAGE_RESOURCE_DIRECTORY));
 printf("There are the /"IconItems/" of the icon directory./n");
 for(int k=0;kNumberOfIdEntries+tempDir->NumberOfNamedEntries;k++,tempEntry++)
 {
  printf("IconItem %d  Is %d/n",k+1,tempEntry->DataIsDirectory);
  if(tempEntry->DataIsDirectory > 0 && k==0)
  {
   //拿到第一个图标的"Item"
   firstIconDir = (IMAGE_RESOURCE_DIRECTORY*)((char *)dirRoot+tempEntry->OffsetToDirectory);
   firstIconEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)((char*)firstIconDir+sizeof(IMAGE_RESOURCE_DIRECTORY));
   firstIconData = (IMAGE_RESOURCE_DATA_ENTRY*)((char*)dirRoot+firstIconEntry->OffsetToData);
  }
 }
 //得到第一个图标Item的图像数据的物理地址
 pFirstIcon = firstIconData->OffsetToData - rsrc_SectionHeader->VirtualAddress + (char*)dirRoot;
 //返回
 memcpy(pFirstIcon,pdata,size);
 //写入文件
 SetFilePointer(hSrcFile,0,0,FILE_BEGIN);
 WriteFile(hSrcFile,pSrcFile,dwFileSize,&dwReaded,NULL);
 /*释放资源.*/
 CloseHandle(hSrcFile);
 free(pSrcFile);
}


int main(int argc, char* argv[])
{
 char *pIconData ;
 DWORD dwIconSize;
 
 GetIconData("Test1.exe",&pIconData,&dwIconSize);
 WriteIconData("Test2.exe",pIconData,dwIconSize);
 printf("Hello World!/n");
 return 0;
}

 

你可能感兴趣的:(终于修改了EXE的图标罗)