这些天研究怎样修改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;i
{
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
{
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
{
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
{
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
{
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
{
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;
}