您的位置:首页 > 其它

终于修改了EXE的图标罗

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

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

为什么要减去 VirtualAddress 呢?

最后看了张正秋的<<Windows应用程序捆绑核心编程 >>网上试读的文章,才明白了些.

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

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

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

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

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

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

Dos HeaderDos StubPE HeaderSection Header 1Section Header ……Section Header nSection 1Section ……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;i<ntHeader->FileHeader.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;j<dirRoot->NumberOfIdEntries+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;k<tempDir->NumberOfIdEntries+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;i<ntHeader->FileHeader.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;j<dirRoot->NumberOfIdEntries+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;k<tempDir->NumberOfIdEntries+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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: