刚才发现论坛上面有网友问:如何通过编程实现修改EXE文件的图标,类似于 熊猫烧香 的效果!自己也对这个比较感兴趣网上找了找,找到了两种方法,可以满足大家都要求了,这里面收集转载过来,大家可以实践下,看看好不好用,起码有代码可以参考:

方法一:通过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,当然也鄙视下自己的无知。另外还好找到的那份资料有点人性,把结构给咱标出来了,那么现在一切都顺理成章,不说多了,上代码:

  1. #include <stdio.h>
  2. #include <windows.h>
  3. #include <tchar.h>

  4. struct ICONDIRENTRY
  5. {
  6.     BYTE bWidth;
  7.     BYTE bHeight;
  8.     BYTE bColorCount;
  9.     BYTE bReserved;
  10.     WORD wPlanes;
  11.     WORD wBitCount;
  12.     DWORD dwBytesInRes;
  13.     DWORD dwImageOffset;
  14. };

  15. struct ICONDIR
  16. {
  17.     WORD idReserved;
  18.     WORD idType;
  19.     WORD idCount;
  20.     //ICONDIRENTRY idEntries;
  21. };

  22. struct GRPICONDIRENTRY
  23. {
  24.     BYTE bWidth;
  25.     BYTE bHeight;
  26.     BYTE bColorCount;
  27.     BYTE bReserved;
  28.     WORD wPlanes;
  29.     WORD wBitCount;
  30.     DWORD dwBytesInRes;
  31.     WORD nID;
  32. };
  33. struct GRPICONDIR
  34. {
  35.     WORD idReserved;
  36.     WORD idType;
  37.     WORD idCount;
  38.     GRPICONDIRENTRY idEntries;
  39. };

  40. //////////////////////////////////////////////
  41. //函数说明:修改EXE图标
  42. //
  43. //参    数:IconFile 图标文件
  44. //              ExeFile 被修改的EXE文件
  45. //
  46. //返回值: 成功为True,否则False
  47. /////////////////////////////////////////////
  48. bool ChangeExeIcon(LPWSTR IconFile, LPWSTR ExeFile)
  49. {
  50.     ICONDIR stID;
  51.     ICONDIRENTRY stIDE;
  52.     GRPICONDIR stGID;
  53.     HANDLE hFile;
  54.     DWORD nSize, nGSize, dwReserved;
  55.     HANDLE hUpdate;
  56.     PBYTE pIcon, pGrpIcon;
  57.     BOOL ret;
  58.     hFile = CreateFile(IconFile, GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  59.     if (hFile == INVALID_HANDLE_VALUE)
  60.     {
  61.        return false;
  62.     }
  63.     ZeroMemory(&stID, sizeof(ICONDIR));
  64.     ret = ReadFile(hFile, &stID, sizeof(ICONDIR), &dwReserved, NULL);
  65.     ZeroMemory(&stIDE, sizeof(ICONDIRENTRY));
  66.     ret = ReadFile(hFile, &stIDE, sizeof(ICONDIRENTRY), &dwReserved, NULL);
  67.     nSize = stIDE.dwBytesInRes;
  68.     pIcon = (PBYTE)malloc(nSize);
  69.     SetFilePointer(hFile, stIDE.dwImageOffset, NULL, FILE_BEGIN);
  70.     ret = ReadFile(hFile, (LPVOID)pIcon, nSize, &dwReserved, NULL);
  71.     if (!ret)
  72.     {
  73.        CloseHandle(hFile);
  74.        return false;
  75.     }
  76.     ZeroMemory(&stGID, sizeof(GRPICONDIR));
  77.     stGID.idCount = stID.idCount;
  78.     stGID.idReserved = 0;
  79.     stGID.idType = 1;
  80.     CopyMemory(&stGID.idEntries, &stIDE, 12);
  81.     stGID.idEntries.nID = 0;
  82.     nGSize = sizeof(GRPICONDIR);
  83.     pGrpIcon = (PBYTE)malloc(nGSize);
  84.     CopyMemory(pGrpIcon, &stGID, nGSize);

  85.     hUpdate = BeginUpdateResource(ExeFile, false);
  86.     ret = UpdateResource(hUpdate, RT_GROUP_ICON, MAKEINTRESOURCE(1), 0, (LPVOID)pGrpIcon, nGSize);
  87.     ret = UpdateResource(hUpdate, RT_ICON, MAKEINTRESOURCE(1), 0, (LPVOID)pIcon, nSize);
  88. EndUpdateResource(hUpdate, false);
  89.     if (!ret)
  90.     {
  91.        CloseHandle(hFile);
  92.        return false;
  93.     }
  94.     CloseHandle(hFile);
  95.     return true;
  96. }


 

posted on 2011-03-15 14:33  maxweii  阅读(7118)  评论(2编辑  收藏  举报