方法一:通过API编程实现:
这个问题以前在CSDN上解答过,但是当时只是提了提几个要用到的函数,自己并没有去动手写实现。前几天和某人讨论这个问题,他认为只有通过PE内部的资源偏移才好改,熊猫烧香就是这么搞的,而我坚持API也可以的观点。后来我想了想觉得这个问题值得记住,并自己亲手把它写出来并试验成功。贴出代码来给大家分享:
EnableDebugPrivilge(SE_DEBUG_NAME,TRUE);
HGLOBAL hResLoad(NULL);
HANDLE hExe(NULL);
HRSRC hRes(NULL);
HANDLE hUpdateRes(NULL);
char * lpResLock;
BOOL result;
hExe = LoadLibrary(_TEXT("D:\\Src.exe"));
if (hExe == NULL)
{
AfxMessageBox("加载Src.exe失败.",0,0);
}
hRes = FindResource((HMODULE)hExe, (LPCSTR)1, RT_ICON);
if (hRes == NULL)
{
AfxMessageBox("不能定位Src.exe中的第一个图标");
}
hResLoad = LoadResource((HMODULE)hExe, hRes);
if (hResLoad == NULL)
{
AfxMessageBox("不能加载该图标资源");
}
lpResLock =(char *)LockResource(hResLoad);
if (lpResLock == NULL)
{
AfxMessageBox("不能锁定该资源.");
}
hUpdateRes = BeginUpdateResource("G:\\Target.exe", FALSE);
if (hUpdateRes == NULL)
{
AfxMessageBox("不能打开Target.exe准备写.");
}
result =UpdateResource((HMODULE)hUpdateRes , RT_ICON,
(LPCSTR)1, 0, lpResLock, SizeofResource((HMODULE)hExe, hRes));
if (result == FALSE)
{
AfxMessageBox("添加资源失败.");
}
if (!EndUpdateResource(hUpdateRes, FALSE))
{
AfxMessageBox("不能向目标EXE中写入改动结束资源更新");
}
if (!FreeLibrary((HMODULE)hExe))
{
AfxMessageBox("不能释放Src的句柄.");
}
有人说编程靠思路和套路,这个套路可真是够长的,这么多的函数必须按顺序配套使用,不能有差错。其实按照讨论的VC编程还有很多啊,比如CreateFile、CreateFileMapping、MapViewOfFile、UnmapViewOfFile这也是一个典型套路。
至于EnableDebugPrivilge函数,是提升本进程的权限为DEBUG级别,代码网上有,大家可以自己找找!
方法二:通过PE文件的图标偏移地址实现:
一年前初学VB时我对这个API就特感兴趣,听说这个API可以更改图标资源,就更感兴趣了,后来试了试,发现修改其它资源貌似没多大问题,唯独修改图标时无果,我发现所修改的图虽说已经写入到资源文件中了,但是就是无法显示。后来到网上查了下,发现用UpdateResource修改EXE图标的没一个成功的,大致都是发生成功写入,无法正常显示的问题。罢矣,当时就琢磨着把该问题先放放,等日后有时间再好好折腾。
无奈时间过得太快,忽忽悠悠就过了一年了,前几天,在整理去年的一些源码时发现了这个遗留在硬盘中的代码,一年前无奈自己所学浅溥,啥都不知道,但现在已经对API有了较深厚的认识,再加上对汇编的一些了解,我想此时不解决更待何时。
在折腾这个API的期间也发生不少问题,最让我自责的就是差点被 CreateFile 这个API给Game Over,这个小伟知道(又是小伟?没办法啊,谁要咱和小伟太有缘了~)。还好自己最终醒悟,否则真的要好好鄙视鄙视自己。最初修改时还是和一年前一个样,这时我一直在回想一样年遇到这个问题的问题:所写图标的数据是不是完整的写到了资源文件中?想到此,我用eXeScope(一个PE资源文件查看工具)看了下写入到资源文件中的十六进制,又用UltraEdit-32以十六进制查看ico文件中的数据,发现没问题啊?一字节一字节都对得上,那问题出在哪了?没法,继续在Google游荡,终于找了一份有效的资料(网址现在不知扔哪去了),全E文,看得难受,不过大致的意思是说ICON是由一个结构组成,同PE那些什么NT头,DOS头的差不多,而所显示的图像数据包函于ICON类型结构的dwImageOffset偏移处。呵,这下总算搞明白为什么直接把ICON文件写入到资源文件中显示不了的问题了,也就是说在dwImageOffset偏移位置处才是咱所需要的图像数据,这不就啥都OK了么,爷爷的,原来咱从一开始就被ICON文件整得稀里糊涂,靠MS,当然也鄙视下自己的无知。另外还好找到的那份资料有点人性,把结构给咱标出来了,那么现在一切都顺理成章,不说多了,上代码:
- #include <stdio.h>
- #include <windows.h>
- #include <tchar.h>
- struct ICONDIRENTRY
- {
- BYTE bWidth;
- BYTE bHeight;
- BYTE bColorCount;
- BYTE bReserved;
- WORD wPlanes;
- WORD wBitCount;
- DWORD dwBytesInRes;
- DWORD dwImageOffset;
- };
- struct ICONDIR
- {
- WORD idReserved;
- WORD idType;
- WORD idCount;
- //ICONDIRENTRY idEntries;
- };
- struct GRPICONDIRENTRY
- {
- BYTE bWidth;
- BYTE bHeight;
- BYTE bColorCount;
- BYTE bReserved;
- WORD wPlanes;
- WORD wBitCount;
- DWORD dwBytesInRes;
- WORD nID;
- };
- struct GRPICONDIR
- {
- WORD idReserved;
- WORD idType;
- WORD idCount;
- GRPICONDIRENTRY idEntries;
- };
- //////////////////////////////////////////////
- //函数说明:修改EXE图标
- //
- //参 数:IconFile 图标文件
- // ExeFile 被修改的EXE文件
- //
- //返回值: 成功为True,否则False
- /////////////////////////////////////////////
- bool ChangeExeIcon(LPWSTR IconFile, LPWSTR ExeFile)
- {
- ICONDIR stID;
- ICONDIRENTRY stIDE;
- GRPICONDIR stGID;
- HANDLE hFile;
- DWORD nSize, nGSize, dwReserved;
- HANDLE hUpdate;
- PBYTE pIcon, pGrpIcon;
- BOOL ret;
- hFile = CreateFile(IconFile, GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if (hFile == INVALID_HANDLE_VALUE)
- {
- return false;
- }
- ZeroMemory(&stID, sizeof(ICONDIR));
- ret = ReadFile(hFile, &stID, sizeof(ICONDIR), &dwReserved, NULL);
- ZeroMemory(&stIDE, sizeof(ICONDIRENTRY));
- ret = ReadFile(hFile, &stIDE, sizeof(ICONDIRENTRY), &dwReserved, NULL);
- nSize = stIDE.dwBytesInRes;
- pIcon = (PBYTE)malloc(nSize);
- SetFilePointer(hFile, stIDE.dwImageOffset, NULL, FILE_BEGIN);
- ret = ReadFile(hFile, (LPVOID)pIcon, nSize, &dwReserved, NULL);
- if (!ret)
- {
- CloseHandle(hFile);
- return false;
- }
- ZeroMemory(&stGID, sizeof(GRPICONDIR));
- stGID.idCount = stID.idCount;
- stGID.idReserved = 0;
- stGID.idType = 1;
- CopyMemory(&stGID.idEntries, &stIDE, 12);
- stGID.idEntries.nID = 0;
- nGSize = sizeof(GRPICONDIR);
- pGrpIcon = (PBYTE)malloc(nGSize);
- CopyMemory(pGrpIcon, &stGID, nGSize);
- hUpdate = BeginUpdateResource(ExeFile, false);
- ret = UpdateResource(hUpdate, RT_GROUP_ICON, MAKEINTRESOURCE(1), 0, (LPVOID)pGrpIcon, nGSize);
- ret = UpdateResource(hUpdate, RT_ICON, MAKEINTRESOURCE(1), 0, (LPVOID)pIcon, nSize);
- EndUpdateResource(hUpdate, false);
- if (!ret)
- {
- CloseHandle(hFile);
- return false;
- }
- CloseHandle(hFile);
- return true;
- }