微软官网UpdateResource 其它参考信息: https://msdn.microsoft.com/zh-cn/library/ms648008.aspx#_win32_Updating_Resources

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

===============================================

Delphi Code:

===============================================

//请自行添加到 Type 处
PICONDIRENTRY = ^ICONDIRENTRY;
ICONDIRENTRY = packed record
    bWidth: Byte;
    bHeight: Byte;
    bColorCount: Byte;
    bReserved: Byte;
    wPlanes: Word;
    wBitCount: Word;
    dwBytesInRes: DWORD;
    dwImageOffset: DWORD;
end;

PICONDIR = ^ICONDIR;
ICONDIR = packed record
    idReserved: Word;
    idType: Word;
    idCount: Word;
    idEntries: ICONDIRENTRY;
end;

PGRPICONDIRENTRY = ^GRPICONDIRENTRY;
GRPICONDIRENTRY = packed record
    bWidth: Byte;
    bHeight: Byte;
    bColorCount: Byte;
    bReserved: Byte;
    wPlanes: Word;
    wBitCount: Word;
    dwBytesInRes: DWORD;
    nID: Word;
end;

PGRPICONDIR = ^GRPICONDIR;
GRPICONDIR = packed record
    idReserved: Word;
    idType: Word;
    idCount: Word;
    idEntries: GRPICONDIRENTRY; 
end;

//
//函数说明:修改EXE图标
//
//参    数:IconFile 图标文件 
//              ExeFile 被修改的EXE文件
//
//返回值: 成功为True,否则False
/
function ChangeExeIcon(IcoFile, ExeFile: string): Boolean;
var
stID: ICONDIR;
stGID: GRPICONDIR;

pGrpIcon: PBYTE;
pIcon: PBYTE;
hUpdate: DWORD;
nSize, nGSize: DWORD; 
hFile: THandle;
dwReserved: DWORD; 
ret: Boolean;
begin
Result := False;

hFile := CreateFile(PChar(IcoFile), GENERIC_READ, 0, nil, OPEN_EXISTING,
                      FILE_ATTRIBUTE_NORMAL, 0);
if hFile = INVALID_HANDLE_VALUE then
    Exit;

try                      
    ReadFile(hFile, stID, Sizeof(ICONDIR), dwReserved, nil);

nSize := stID.idEntries.dwBytesInRes;
    GetMem(pIcon, nSize);
    SetFilePointer(hFile, stID.idEntries.dwImageOffset, nil, FILE_BEGIN);
    ReadFile(hFile, pIcon^, nSize, dwReserved, nil);

stGID.idType := 1;
    stGID.idCount := stID.idCount;
    stGID.idReserved := 0;
    CopyMemory(@stGID.idEntries.bWidth, @stID.idEntries.bWidth, 12);
    stGID.idEntries.nID := 0;

nGSize := Sizeof(GRPICONDIR);
    GetMem(pGrpIcon, nGSize);
    CopyMemory(pGrpIcon, @stGID, nGSize);

hUpdate := BeginUpdateResource(PChar(ExeFile), False);
    try
      ret := UpdateResource(hUpdate, RT_GROUP_ICON, MAKEINTRESOURCE(1), 0, pGrpIcon, nGSize);
      ret := UpdateResource(hUpdate, RT_ICON, MAKEINTRESOURCE(1), 0, pIcon, nSize);
    finally
      EndUpdateResource(hUpdate, False);
    end;
finally
    CloseHandle(hFile);
end;

Result := ret;
end;

===============================================

VB Code:

===============================================

Option Explicit

Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, lpSecurityAttributes As Any, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Private Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Any) As Long
Private Declare Function SetFilePointer Lib "kernel32" (ByVal hFile As Long, ByVal lDistanceToMove As Long, lpDistanceToMoveHigh As Long, ByVal dwMoveMethod As Long) As Long
Private Declare Function BeginUpdateResource Lib "kernel32" Alias "BeginUpdateResourceA" (ByVal pFileName As String, ByVal bDeleteExistingResources As Long) As Long
Private Declare Function UpdateResource Lib "kernel32" Alias "UpdateResourceA" (ByVal hUpdate As Long, ByVal lpType As Long, ByVal lpName As Long, ByVal wLanguage As Long, lpData As Any, ByVal cbData As Long) As Long
Private Declare Function EndUpdateResource Lib "kernel32" Alias "EndUpdateResourceA" (ByVal hUpdate As Long, ByVal fDiscard As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function GetLastError Lib "kernel32" () As Long

Private Const INVALID_HANDLE_VALUE = -1
Private Const GENERIC_READ = &H80000000
Private Const FILE_ATTRIBUTE_NORMAL = &H80
Private Const FILE_BEGIN = 0
Private Const OPEN_EXISTING = 3
Private Const RT_ICON = 3&
Private Const DIFFERENCE As Long = 11
Private Const RT_GROUP_ICON As Long = (RT_ICON + DIFFERENCE)

Private Type ICONDIRENTRY
    bWidth As Byte
    bHeight As Byte
    bColorCount As Byte
    bReserved As Byte
    wPlanes As Integer
    wBitCount As Integer
    dwBytesInRes As Long
    dwImageOffset As Long
End Type

Private Type ICONDIR
    idReserved As Integer
    idType As Integer
    idCount As Integer
    'idEntries As ICONDIRENTRY
End Type

Private Type GRPICONDIRENTRY
    bWidth As Byte
    bHeight As Byte
    bColorCount As Byte
    bReserved As Byte
    wPlanes As Integer
    wBitCount As Integer
    dwBytesInRes As Long
    nID As Integer
End Type

Private Type GRPICONDIR
    idReserved As Integer
    idType As Integer
    idCount As Integer
    idEntries As GRPICONDIRENTRY
End Type

'//
'//函数说明:修改EXE图标
'//
'//参    数:IconFile 图标文件
'//              ExeFile 被修改的EXE文件
'//
'//返回值: 成功为True,否则False
'/
Private Function ChangeExeIcon(ByVal IconFile As String, ByVal ExeFile As String) As Boolean
    On Error GoTo cw
    
    Dim stID As ICONDIR
    Dim stIDE As ICONDIRENTRY
    Dim stGID As GRPICONDIR
    
    Dim hFile As Long
    Dim pIcon() As Byte, pGrpIcon() As Byte
    Dim nSize As Long, nGSize As Long
    Dim dwReserved As Long
    Dim hUpdate As Long
    Dim ret As Long
    
    hFile = CreateFile(IconFile, GENERIC_READ, 0, ByVal 0&, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
    If hFile = INVALID_HANDLE_VALUE Then Exit Function

ret = ReadFile(hFile, stID, Len(stID), dwReserved, ByVal 0&)
    If ret = 0 Then GoTo cw
    
    ret = ReadFile(hFile, stIDE, Len(stIDE), dwReserved, ByVal 0&)

nSize = stIDE.dwBytesInRes
    ReDim pIcon(nSize - 1)
    SetFilePointer hFile, stIDE.dwImageOffset, ByVal 0&, FILE_BEGIN
    ret = ReadFile(hFile, pIcon(0), nSize, dwReserved, ByVal 0&)
    If ret = 0 Then GoTo cw
    
    With stGID
        .idType = 1
        .idCount = stID.idCount
        .idReserved = 0
        CopyMemory stGID.idEntries, stIDE, 12
        .idEntries.nID = 0
    End With
    
    nGSize = Len(stGID)
    ReDim pGrpIcon(nGSize - 1)
    CopyMemory pGrpIcon(0), stGID, nGSize
    
        
    hUpdate = BeginUpdateResource(ExeFile, False)
    ret = UpdateResource(hUpdate, RT_GROUP_ICON, 1, 0, pGrpIcon(0), nGSize)
    ret = UpdateResource(hUpdate, RT_ICON, 1, 0, pIcon(0), nSize)
    EndUpdateResource hUpdate, False

If ret = 0 Then GoTo cw
    ChangeExeIcon = True
    
cw:
    CloseHandle hFile
    
End Function

===============================================

VC++ Code:

===============================================

#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;
}

===============================================

ASM Code:

===============================================

.386
.model flat,stdcall
option casemap:none

include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib

ICONDIRENTRY STRUCT
    bWidth BYTE ?
    bHeight BYTE ?
    bColorCount BYTE ?
    bReserved BYTE ?
    wPlanes WORD ?
    wBitCount WORD ?
    dwBytesInRes DWORD ?
    dwImageOffset DWORD ?
ICONDIRENTRY ENDS

ICONDIR STRUCT
    idReserved WORD ?
    idType WORD ?
    idCount WORD ?
    ;idEntries ICONDIRENTRY <>
ICONDIR ENDS

GRPICONDIRENTRY STRUCT
    bWidth BYTE ?
    bHeight BYTE ?
    bColorCount BYTE ?
    bReserved BYTE ?
    wPlanes WORD ?
    wBitCount WORD ?
    dwBytesInRes DWORD ?
    nID   WORD ?
GRPICONDIRENTRY ENDS

GRPICONDIR STRUCT
    idReserved WORD ?
    idType WORD ?
    idCount WORD ?
    idEntries GRPICONDIRENTRY <>
GRPICONDIR ENDS

.data

szIcon   db 'a.ico', 0
szFile   db 'a.exe', 0

.code

//
//函数说明:修改EXE图标
//
//参    数:IconFile 图标文件 
//              ExeFile 被修改的EXE文件
//
//返回值: 成功为True,否则False
/

_ChangeExeIcon proc IconFile, ExeFile

local @stID:   ICONDIR
     local @stIDE:   ICONDIRENTRY
     local @stGID:   GRPICONDIR

local @hFile:   DWORD
     local @dwReserved: DWORD
     local @nSize:   DWORD
     local @nGSize:   DWORD
     local @pIcon:   DWORD
     local @pGrpIcon: DWORD
     local @hUpdate:   DWORD
      local @ret:   DWORD

invoke CreateFile, IconFile, GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
     mov @hFile, eax

.if eax == INVALID_HANDLE_VALUE
          xor eax, eax
          ret
     .endif

invoke RtlZeroMemory, addr @stID, sizeof @stID
     invoke ReadFile, @hFile, addr @stID, sizeof @stID, addr @dwReserved, NULL

invoke RtlZeroMemory, addr @stIDE, sizeof @stIDE
     invoke ReadFile, @hFile, addr @stIDE, sizeof @stIDE, addr @dwReserved, NULL

push @stIDE.dwBytesInRes
     pop @nSize

invoke GlobalAlloc, GPTR, @nSize 
     mov @pIcon, eax

invoke SetFilePointer, @hFile, @stIDE.dwImageOffset, NULL, FILE_BEGIN
     invoke ReadFile, @hFile, @pIcon, @nSize, addr @dwReserved, NULL
     cmp eax, 0
     je err

invoke RtlZeroMemory, addr @stGID, sizeof @stGID
     push @stID.idCount
     pop @stGID.idCount
     mov @stGID.idReserved, 0
     mov @stGID.idType, 1
     invoke RtlMoveMemory, addr @stGID.idEntries, addr @stIDE, 12
     mov @stGID.idEntries.nID, 0

mov @nGSize, sizeof @stGID
     invoke GlobalAlloc, GPTR, @nGSize
     mov @pGrpIcon, eax
     invoke RtlMoveMemory, @pGrpIcon, addr @stGID, @nGSize

;开始修改
     invoke BeginUpdateResource, ExeFile, FALSE
     mov @hUpdate, eax
     invoke UpdateResource, @hUpdate, RT_GROUP_ICON, 1, 0, @pGrpIcon, @nGSize
     invoke UpdateResource, @hUpdate, RT_ICON, 1, 0, @pIcon, @nSize
     mov @ret, eax
     invoke EndUpdateResource, @hUpdate, FALSE

.if @ret == FALSE
          jmp err
     .endif

;成功后到此一日游
     invoke GlobalFree, @pIcon
     invoke CloseHandle, @hFile
     mov eax, 1
ret

err:
     ;失败后到此一日游
     invoke GlobalFree, @pIcon
     invoke CloseHandle, @hFile
     xor eax, eax
     ret

_ChangeExeIcon endp

;==========================程序入口=============================
start:

invoke _ChangeExeIcon, offset szIcon, offset szFile
     invoke ExitProcess, NULL

end start

用UpdateResource修改EXE文件图标的多源码(已修正) 注:转帖请包函作者信息.(作者:菜新)相关推荐

  1. VC++编程实现修改EXE文件图标

    VC++编程实现修改EXE文件图标 刚才发现论坛上面有网友问:如何通过编程实现修改EXE文件的图标,类似于 熊猫烧香 的效果!自己也对这个比较感兴趣网上找了找,找到了两种方法,可以满足大家都要求了,这 ...

  2. qt 修改.exe文件图标_如何在没有错误的情况下更改压缩的.EXE文件上的图标

    qt 修改.exe文件图标 We've previously shown you how to modify the icon on an .EXE file, but if you've tried ...

  3. 机器狗写入到userinit.exe文件的下载者源码(c及汇编)

    机器狗源码(C语言的),将病毒体从资源中提取出来写入到第一个分区的指定文件中 // Test.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" ...

  4. 使用ICON动态修改exe文件图标

    前言:这两天为exe文件做一个随机图标的功能,要求每次运行后图标都动态改变,在网上找了很多代码,都有一部分缺陷,参考了一些文档后进行了修改,现在在此进行总结: 一个icon资源(可以是*.ico文件, ...

  5. Qt修改exe文件图标

    修改Qt生成exe的图标 1. 直接添加.ico 首先要注意的一点是,你的.ico文件不可以是直接用过jpg等图片格式直接修改后缀名形成的,必须是用转换工具来通过jpg转换成ico的格式,不然就会出现 ...

  6. 无源码修改exe文件图标

    将exe导入到Restorator里面解析,如果解析不了就用FixRes修复一下 然后导入自己的ico替换即可

  7. C#怎么修改生成的EXE文件图标

    C#怎么修改生成的EXE文件图标 工具/原料 1.VS,Visual Studio 2013或其他版本 2-ico的图标文件一个 方法/步骤 1.打开你的项目文件,如下图,选择release选项 2. ...

  8. C#上位机开发—— 修改窗口图标和exe文件图标

    一.准备应用程序图标 首先寻找一个好看的应用程序图标图片,然后使用在线工具转换为 .ico格式: 二.修改窗口图标 在窗口的属性中找到Icon项,选择要设置的图标即可: 运行后即可看到窗口图标被修改: ...

  9. 修改exe文件的图标

    修改exe文件的图标: 点击项目的属性,找到图标和清单,修改图标就ok,但是图标必须是ico格式的,如下图: jpg转ico: 把jpg格式的图片先用系统自带的画图工具打开,可以调整属性,然后另存为b ...

最新文章

  1. 【实验报告】四恶意代码实验
  2. RocketMQ 核心
  3. R语言与Shapiro正态性检验
  4. 牛客网 【每日一题】6月11日题目精讲 背包
  5. K8S Learning(4)——Namespace
  6. tensorflow gpu安装_tensorflow-gpu安装配置
  7. werkzeug routing.Map
  8. SharePoint中文WiKi
  9. ubuntu GIT 安装与使用
  10. mysql查询4-6_MySQL学习(四)查询
  11. git clone 遇到的坑
  12. 各厂商服务器存储默认管理口登录信息(默认IP、用户名、密码)收集
  13. MFC中窗口类、句柄的获取
  14. ❄️全网最详细的Python入门基础教程,Python最全教程(非常详细,整理而来)
  15. 【趣味学取证】电子数据取证现场勘验知多少?
  16. oracle imp 跳过表,关于oracle imp 导入避开若干表
  17. oracle创建用户并授权管理员,Oracle创建用户并授权【数据库】
  18. ios申请企业开发者账号的代理_2020年苹果ios企业开发者账号的申请流程攻略(最专业详细)...
  19. Druid java.sql.SQLException: 违反协议 / Oracle连接报错生违反协议
  20. 记录CTF命令执行练习中遇到的几道题(一些PHP命令过滤的绕过方法)

热门文章

  1. php实现远程升级,教你如何用php实现LOL数据远程获取
  2. 聊聊BI做表Sop!
  3. 在一张纸上打印多幅Powerpoint幻灯片
  4. 微信小程序中怎么使用阿里图标库中的图标
  5. python3 爬虫数据处理 爬取华为应用市场 APP应用评论(二)根据评论生成词云——学霸君
  6. setInterval()方法的调用和停止。
  7. C++: POD, Plain old data, 朴素老数据,别别扭扭
  8. 聊聊大数据(一)——大数据的存储
  9. 【思科CCNA理论专题:10】--ACL实验扩展-晁海江-专题视频课程
  10. Linux/Ubuntu 中卸载软件的几种命令