exe文件内部是怎样存放它对应的ico图标的?

凌乱哥 2019-07-17 05:18:41
背景:每个exe生成都需要一个ico文件作为显示

过程:用十六进制工具比如UltraEdit打开一个exe及其对应的ico,在exe的尾部发现了和ico几乎雷同的数据。但是exe文件把ico文件拆分成了几个部分存放的,而且这几个部分之间还有若干个0x00

问题:请教一下这种机制是有什么规则可循吗?(如果知道这个规则后我就可以实现用代码替换exe的ico了,当然替换后还要改exe校验什么的)
...全文
429 15 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
「已注销」 2019-07-29
  • 打赏
  • 举报
回复
我的例子的确有问题,甚至 HANDLE 都写成了 HMODULE。
原来替换图标比我想得复杂一点,具体的代码网上有,和上面兄弟发的差不多:
https://social.msdn.microsoft.com/Forums/sqlserver/en-US/d1fc85aa-d296-43b8-b0df-d5da7d94dcb5/
https://www.codeproject.com/Articles/30644/
凌乱哥 2019-07-29
  • 打赏
  • 举报
回复
引用 13 楼 schlafenhamster 的回复:
参考
多谢,根据你这代码搜到了#14是可用代码

#include <windows.h>
#include <tchar.h>

typedef struct tagHEADER      
{      
    WORD idReserved;      
    WORD idType;      
    WORD idCount;      
}HEADER, *LPHEADER;      

typedef struct tagICONDIRENTRY      
{      
    BYTE bWidth;      
    BYTE bHeight;      
    BYTE bColorCount;      
    BYTE bReserved;      
    WORD wPlanes;      
    WORD wBitCount;      
    DWORD dwBytesInRes;      
    DWORD dwImageOffset;      
}ICONDIRENTRY, *LPICONDIRENTRY;      

#pragma pack( push )      
#pragma pack( 2 )      
typedef struct tagGRPICONDIRENTRY      
{      
    BYTE bWidth;      
    BYTE bHeight;      
    BYTE bColorCount;      
    BYTE bReserved;      
    WORD wPlanes;      
    WORD wBitCount;      
    DWORD dwBytesInRes;      
    WORD nID;      
}GRPICONDIRENTRY, *LPGRPICONDIRENTRY;;      

typedef struct tagGRPICONDIR      
{      
    WORD idReserved;      
    WORD idType;      
    WORD idCount;      
    GRPICONDIRENTRY idEntries[1];      
}GRPICONDIR, *LPGRPICONDIR;      
#pragma pack( pop )     
 
 
//.CPP文件中的主要代码:
//view plaincopy to clipboardprint?
void ChangeExeIcon(LPCTSTR lpIconFile, LPCTSTR lpExeName) 
{      
    LPICONDIRENTRY pIconDirEntry(NULL);      
    LPGRPICONDIR pGrpIconDir(NULL);      
    HEADER header;      
    LPBYTE pIconBytes(NULL);      
    HANDLE hIconFile(NULL);      
    DWORD dwRet(0), nSize(0), nGSize(0), dwReserved(0);      
    HANDLE hUpdate(NULL);      
    BOOL ret(FALSE);      
    WORD i(0);      
    
    //打开图标文件      
    hIconFile = CreateFile(lpIconFile, GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);      
    if (hIconFile == INVALID_HANDLE_VALUE)      
    {      
        return;      
    }      
    //读取文件头部信息      
    ret=ReadFile(hIconFile, &header, sizeof(HEADER), &dwReserved, NULL);      
    if (!ret)      
    {      
        CloseHandle(hIconFile);      
        return;      
    }      
    //建立每一个图标的目录信息存放区域      
    pIconDirEntry = (LPICONDIRENTRY)new BYTE[header.idCount*sizeof(ICONDIRENTRY)];      
    if (pIconDirEntry==NULL)      
    {      
        CloseHandle(hIconFile);      
        return;      
    }      
    //从Icon文件中读取每一个图标的目录信息      
    ret = ReadFile(hIconFile, pIconDirEntry, header.idCount*sizeof(ICONDIRENTRY), &dwReserved, NULL);      
    if (!ret)      
    {      
        delete[] pIconDirEntry;   
        CloseHandle(hIconFile);      
        return;      
    }      
    //建立EXE文件中RT_GROUP_ICON所需的数据结构存放区域      
    nGSize=sizeof(GRPICONDIR)+header.idCount*sizeof(ICONDIRENTRY);      
    pGrpIconDir=(LPGRPICONDIR)new BYTE[nGSize];   
    ZeroMemory(pGrpIconDir, nSize);
    //填充信息,这里相当于一个转换的过程      
    pGrpIconDir->idReserved=header.idReserved;      
    pGrpIconDir->idType=header.idType;      
    pGrpIconDir->idCount=header.idCount;      
    //复制信息并设置每一个图标对应的ID。ID为位置索引号      
    for(i=0;i<header.idCount;i++)      
    {      
        pGrpIconDir->idEntries[i].bWidth=pIconDirEntry[i].bWidth;      
        pGrpIconDir->idEntries[i].bHeight=pIconDirEntry[i].bHeight;      
        pGrpIconDir->idEntries[i].bColorCount=pIconDirEntry[i].bColorCount;      
        pGrpIconDir->idEntries[i].bReserved=pIconDirEntry[i].bReserved;      
        pGrpIconDir->idEntries[i].wPlanes=pIconDirEntry[i].wPlanes;      
        pGrpIconDir->idEntries[i].wBitCount=pIconDirEntry[i].wBitCount;      
        pGrpIconDir->idEntries[i].dwBytesInRes=pIconDirEntry[i].dwBytesInRes;      
        pGrpIconDir->idEntries[i].nID=i+1;    //id  == 0 是 RT_GROUP_ICON 的id,我这里替换的时候出现问题,所以就 + 1 了。  
    }      
    //开始更新EXE中的图标资源,ID定为最小0,如果原来存在0ID的图标信息则被替换为新的。      
    hUpdate = BeginUpdateResource(lpExeName, false);      
    if (hUpdate!=NULL)      
    {      
        HMODULE hMe= 0; // means load from this module

        if (FindResource( hMe, lpExeName, RT_GROUP_ICON))
        {
            //首先更新RT_GROUP_ICON信息       
            ret = UpdateResource(hUpdate, RT_GROUP_ICON, MAKEINTRESOURCE(0), MAKELANGID(LANG_CHINESE, SUBLANG_SYS_DEFAULT), (LPVOID)pGrpIconDir, nGSize);      
            if (!ret)      
            {       
                delete[] pIconDirEntry;
                delete[] pGrpIconDir;  
                CloseHandle(hIconFile);      
                return;      
            }      
        }

        //接着的是每一个Icon的信息存放      
        for(i=0;i<header.idCount;i++)      
        {      
            //Icon的字节数      
            nSize = pIconDirEntry[i].dwBytesInRes;      
            //偏移文件的指针到当前图标的开始处      
            dwRet=SetFilePointer(hIconFile, pIconDirEntry[i].dwImageOffset, NULL, FILE_BEGIN);      
            if (dwRet==INVALID_SET_FILE_POINTER)      
            {      
                break;      
            }      
            //准备pIconBytes来存放文件里的Byte信息用于更新到EXE中。
            
            delete[] pIconBytes;
            
            pIconBytes = new BYTE[nSize];  
            ZeroMemory(pIconBytes, nSize);
            ret = ReadFile(hIconFile, (LPVOID)pIconBytes, nSize, &dwReserved, NULL);      
            if(!ret)      
            {      
                break;      
            }      
            //更新每一个ID对应的RT_ICON信息      
            ret = UpdateResource(hUpdate, RT_ICON, MAKEINTRESOURCE(pGrpIconDir->idEntries[i].nID), MAKELANGID(LANG_CHINESE, SUBLANG_SYS_DEFAULT), (LPVOID)pIconBytes, nSize);      
            if(!ret)      
            {      
                break;      
            } 
        }      
        //结束EXE资源的更新操作      
        if (pIconBytes!=NULL)      
        {      
           delete[] pIconBytes;
        }      

        EndUpdateResource(hUpdate, false);      
    }    
    
    //清理资源并关闭Icon文件,到此更新操作结束!
    SAFE_ARRAY_DELETE(pGrpIconDir); 
    SAFE_ARRAY_DELETE(pIconDirEntry);       
    CloseHandle(hIconFile);      
} 
schlafenhamster 2019-07-29
  • 打赏
  • 举报
回复
参考

//////////////////////////////////////////////
//函数说明:修改EXE图标
//
//参 数:lpszIco 新图标文件
// lpszApp 被修改的EXE文件
//返回值: 成功为True,否则False
/////////////////////////////////////////////
bool ChangeExeIcon(LPCTSTR lpszApp, LPCTSTR lpszIco)
{
ICONDIR stID;
ICONDIRENTRY stIDE;
GRPICONDIR stGID;
HANDLE hFile;
DWORD nSize, nGSize, dwReserved;
HANDLE hUpdate;
PBYTE pIcon, pGrpIcon;
BOOL ret;
//
hFile = CreateFile(lpszIco, 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(lpszApp, false);
if(!hUpdate)
{
DWORD Err=GetLastError();// 2 ERROR_FILE_NOT_FOUND
}
ret = UpdateResource(hUpdate,RT_GROUP_ICON,MAKEINTRESOURCE(1),0,(LPVOID)pGrpIcon, nGSize);
if (!ret)
{
CloseHandle(hFile);
return false;
}
ret = UpdateResource(hUpdate, RT_ICON, MAKEINTRESOURCE(1),0,(LPVOID)pIcon, nSize);
if (!ret)
{
CloseHandle(hFile);
return false;
}
EndUpdateResource(hUpdate, false);
//
CloseHandle(hFile);
return true;
}
凌乱哥 2019-07-29
  • 打赏
  • 举报
回复
引用 11 楼 贾可 的回复:
简单示例:
HMODULE hUpdate = BeginUpdateResource(_T("test.exe"), FALSE); 
if (hUpdate != NULL) 
{
	BOOL bResult;
	HANDLE hFile;
	LARGE_INTERGER llLength;
	BYTE *pbIconData;
	DWORD cbIconData;
	DWORD cbReadData;

	hFile = CreateFile(pszIconFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	bResult = GetFileSizeEx(hFile, &llLength);
	cbIconData = llLength.LowPart;
	pbIconData = new BYTE[cbIconData]();
	bResult = ReadFile(hFile, pbIconData, cbIconData, &cbReadData, NULL);
	CloseHandle(hFile);

	// 修改为对应要更新的图标组 id 和语言
	bResult = UpdateResource(hUpdate, RT_GROUP_ICON, IDI_ICON, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), pbIconData, cbIconData);

	EndUpdateResource(hUpdate, FALSE);

	delete[] pbIconData;
}
请问下这段代码你验证过没,我试了下并没有用。我对你的代码做了以下3处改动: 1. test.exe改成我的目标exe全路径 2. pszIconFile改成我的目标ico全路径 3. IDI_ICON改成了MAKEINTRESOURCE(143) 修改前是这样: 修改后143好像没有了
「已注销」 2019-07-26
  • 打赏
  • 举报
回复
替换图标指定类型为 RT_GROUP_ICON 即可,即单个 ico 就行了。RT_ICON 枚举得到的是不同尺寸的单个图标。
「已注销」 2019-07-26
  • 打赏
  • 举报
回复
简单示例:
HMODULE hUpdate = BeginUpdateResource(_T("test.exe"), FALSE); 
if (hUpdate != NULL)
{
BOOL bResult;
HANDLE hFile;
LARGE_INTERGER llLength;
BYTE *pbIconData;
DWORD cbIconData;
DWORD cbReadData;

hFile = CreateFile(pszIconFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
bResult = GetFileSizeEx(hFile, &llLength);
cbIconData = llLength.LowPart;
pbIconData = new BYTE[cbIconData]();
bResult = ReadFile(hFile, pbIconData, cbIconData, &cbReadData, NULL);
CloseHandle(hFile);

// 修改为对应要更新的图标组 id 和语言
bResult = UpdateResource(hUpdate, RT_GROUP_ICON, IDI_ICON, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), pbIconData, cbIconData);

EndUpdateResource(hUpdate, FALSE);

delete[] pbIconData;
}
shilei87521 2019-07-19
  • 打赏
  • 举报
回复
嗯,看了后又又不少收获
Eleven 2019-07-19
  • 打赏
  • 举报
回复
解析EXE中的资源文件~
「已注销」 2019-07-18
  • 打赏
  • 举报
回复
不是有系列 API 可以直接替换吗,像 @zgl7903 所提到的,用 FindResource、UpdateResource 系列 API 就可以替换。至于可否通过修改 exe 内容的方式来替换,不确定。我建议还是不要去通过这种底层的方式来改动 exe,用 API 为宜。
schlafenhamster 2019-07-18
  • 打赏
  • 举报
回复
搜索 “PeIcons“
https://download.csdn.net/download/schlafenhamster/3011852
凌乱哥 2019-07-18
  • 打赏
  • 举报
回复
引用 3 楼 schlafenhamster 的回复:
搜索 “PeIcons“ https://download.csdn.net/download/schlafenhamster/3011852
感谢回复,例子不错能编译运行。实现了从exe读取图片资源,但是代码挺多,我要慢慢研究
凌乱哥 2019-07-18
  • 打赏
  • 举报
回复
引用 2 楼 hhhh63 的回复:
分几个部分,应该是一个文件中有几个图标吧,如果没有压缩的话,应该可以直接改。


感谢回复。是有好几个图标
凌乱哥 2019-07-18
  • 打赏
  • 举报
回复
引用 1 楼 zgl7903 的回复:
Using Resources
引用 4 楼 贾可 的回复:
不是有系列 API 可以直接替换吗,像 @zgl7903 所提到的,用 FindResource、UpdateResource 系列 API 就可以替换。至于可否通过修改 exe 内容的方式来替换,不确定。我建议还是不要去通过这种底层的方式来改动 exe,用 API 为宜。
感谢回复。但是我网上找了几个代码实现,都没有作用,比如以下2个链接: https://blog.csdn.net/longhaoyou/article/details/6243882 https://www.cnblogs.com/findumars/p/6002458.html 代码看起来挺靠谱,但是编译运行没有用
hhhh63 2019-07-17
  • 打赏
  • 举报
回复
分几个部分,应该是一个文件中有几个图标吧,如果没有压缩的话,应该可以直接改。
zgl7903 2019-07-17
  • 打赏
  • 举报
回复

15,980

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧