动态修改PE文件图标(使用UpdateResource API函数)
PE文件的图标存储在资源文件中,而操作资源要用到的API函数就是UpdateResource
首先我们需要先了解一下ICO格式,参考资料:http://www.moon-soft.com/program/FORMAT/windows/icons.htm
ICO格式不复杂,就是由数据头、数据目录、数据三个部分组成
一个.ico文件中可能含有若干个图标,我们需要将数据目录和数据解析出来。简单地写了个单元
- unit Icons;
- interface
- uses
- Winapi.Windows, System.SysUtils, System.Classes;
- type
- { 用于ICO图标文件 }
- TIconDirEntry = packed record
- bWidth: Byte;
- bHeight: Byte;
- bColorCount: Byte;
- bReserved: Byte;
- wPlanes: Word;
- wBitCount: Word;
- dwBytesInRes: DWORD;
- dwImageOffset: DWORD;
- end;
- PIconDirEntry = ^TIconDirEntry;
- TIconDir = packed record
- idReserved: Word;
- idType: Word;
- idCount: Word;
- idEntries: array [0..0] of TIconDirEntry;
- end;
- PIconDir = ^TIconDir;
- { 用于PE文件中的图标 }
- TGroupIconDirEntry = packed record
- bWidth: Byte;
- bHeight: Byte;
- bColorCount: Byte;
- bReserved: Byte;
- wPlanes: Word;
- wBitCount: Word;
- dwBytesInRes: DWORD;
- nID: Word;
- end;
- TGroupIconDir = packed record
- idReserved: Word;
- idType: Word;
- idCount: Word;
- idEntries: array [0 .. 0] of TGroupIconDirEntry;
- end;
- PGroupIconDir = ^TGroupIconDir;
- { ICO图标文件 }
- TIcoFile = class
- public
- IconStream: TMemoryStream;
- IconDir: PIconDir;
- IconDirSize: DWORD;
- constructor Create; overload;
- constructor Create(const FileName: string); overload;
- destructor Destroy; override;
- // 加载ICO数据
- procedure LoadFromFile(const FileName: string);
- procedure LoadFromStream(Stream: TStream);
- end;
- implementation
- { TIcoFile }
- constructor TIcoFile.Create;
- begin
- IconStream := TMemoryStream.Create;
- IconDir := nil;
- IconDirSize := 0;
- end;
- constructor TIcoFile.Create(const FileName: string);
- begin
- Create;
- LoadFromFile(FileName);
- end;
- destructor TIcoFile.Destroy;
- begin
- FreeMem(IconDir);
- FreeAndNil(IconStream);
- inherited;
- end;
- procedure TIcoFile.LoadFromFile(const FileName: string);
- var
- MS: TMemoryStream;
- begin
- MS := TMemoryStream.Create;
- try
- MS.LoadFromFile(FileName);
- LoadFromStream(MS);
- finally
- FreeAndNil(MS);
- end;
- end;
- procedure TIcoFile.LoadFromStream(Stream: TStream);
- var
- Dir: TIconDir;
- begin
- Stream.Position := 0;
- IconStream.Clear;
- IconStream.CopyFrom(Stream, Stream.Size);
- IconStream.Position := 0;
- IconStream.ReadBuffer(Dir, SizeOf(Dir));
- FreeMem(IconDir);
- IconDirSize := SizeOf(TIconDirEntry) * (Dir.idCount - 1) + SizeOf(TIconDir);
- IconDir := AllocMem(IconDirSize);
- IconStream.Position := 0;
- IconStream.ReadBuffer(IconDir^, IconDirSize);
- end;
- end.
这里要注意一个问题,ICO文件中的TIconDirEntry结构和PE文件中的TGroupIconDirEntry结构是不同的
不同处在最后一个参数,ICO文件中表示的是图像数据偏移地址,是DWORD类型。而PE文件中表示的是图像数据的索引,是WORD类型,少了2个字节
替换图标需要写入2个部分:RT_GROUP_ICON 和 RT_ICON
RT_GROUP_ICON也就是ICO的数据头部分,RT_ICON就是图像数据部分了
数据部分直接写入即可,不用转换什么的。但是数据头需要稍微处理一下,因为前面说了,这个替换过程是把ICO文件写到PE文件中
而他们数据头部分结构略有不同(PE文件中每个数据头比起ICO数据头要少2字节),只用把这里处理下就行了
最后写个函数就可以替换PE文件图标了
- function TMainForm.UpdatePeIcon(IcoFile, PeFile: string): Boolean;
- var
- Ico: TIcoFile;
- I: Integer;
- hRes: THandle;
- GroupIconDir: PGroupIconDir;
- GroupIconDirSize: DWORD;
- Data: TBytes;
- begin
- Result := False;
- hRes := BeginUpdateResource(PChar(PeFile), False);
- if hRes <> 0 then
- begin
- Ico := TIcoFile.Create(IcoFile);
- // TGroupIconDirEntry结构要比TIconDirEntry结构少2字节
- GroupIconDirSize := Ico.IconDirSize - Ico.IconDir^.idCount * 2;
- GroupIconDir := AllocMem(GroupIconDirSize);
- GroupIconDir^.idReserved := 0;
- GroupIconDir^.idType := 1;
- GroupIconDir^.idCount := Ico.IconDir.idCount;
- for I := 0 to Ico.IconDir.idCount - 1 do
- begin
- CopyMemory(@GroupIconDir^.idEntries[I], @Ico.IconDir^.idEntries[I],
- SizeOf(TGroupIconDirEntry));
- // 索引从1开始
- GroupIconDir^.idEntries[I].nID := I + 1;
- // 写入图标数据
- SetLength(Data, Ico.IconDir^.idEntries[I].dwBytesInRes);
- Ico.IconStream.Position := Ico.IconDir^.idEntries[I].dwImageOffset;
- Ico.IconStream.ReadBuffer(Data[0], Length(Data));
- UpdateResource(hRes, RT_ICON, MakeIntResource(I + 1), 0, @Data[0], Length(Data));
- end;
- // 写入 RT_GROUP_ICON
- UpdateResource(hRes, RT_GROUP_ICON, MakeIntResource('MAINICON'), 0, GroupIconDir, GroupIconDirSize);
- FreeMem(GroupIconDir);
- FreeAndNil(Ico);
- EndUpdateResource(hRes, False);
- Result := True;
- end;
- end;
http://blog.csdn.net/aqtata/article/details/7710720
动态修改PE文件图标(使用UpdateResource API函数)的更多相关文章
- 替换应用程序exe图标,主要使用BeginUpdateResource,UpdateResource API函数
替换应用程序exe图标,主要使用的API函数是BeginUpdateResource(),UpdateResource(),EndUpdateResource()来使用自定义的ico文件类替换exe程 ...
- 修改PE文件的入口函数OEP
修改入口函数地址.这个是最省事的办法,在原PE文件中新增加一个节,计算新节的RVA,然后修改入口代码,使其指向新增加的节.当然,如果.text节空隙足够大的话,不用添加新节也可以. BOOL Chan ...
- maven 根据P参数值打包动态修改properties文件中值或一定properties
需求:由于最近开发clover项目 ,没有使用spring,更没有使用任何框架,而使用J2EE的web工程,所以连接ZK和MongoDB.Redis等服务器需用指定properties文件, 而目前公 ...
- Dll注入:修改PE文件 IAT注入
PE原理就不阐述了, 这个注入是PE感染的一种,通过添加一个新节注入,会改变PE文件的大小,将原有的导入表复制到新节中,并添加自己的导入表描述符,最后将数据目录项中指向的导入表的入口指向新节. 步骤: ...
- 用UpdateResource修改EXE文件图标(已修正)
//请自行添加到 Type 处PICONDIRENTRY = ^ICONDIRENTRY;ICONDIRENTRY = packed record bWidth: Byte; bHeight: Byt ...
- 动态修改css文件中,具体的class中的个别属性值。
function setStyleSheetObjCssClassProperty(pStyleSheetObj, pSelectorText, pProperty, pValue) { var pS ...
- BS Web窗体 动态修改WebConfig文件参数及数据库链接串
WebConfig操作帮助类 /// /// ConfigurationOperator 的摘要说明 /// public class ConfigurationOperator : IDisposa ...
- 应用程序加载外部字体文件(使用AddFontResource API函数指定字体)
/* MSDN: Any application that adds or removes fonts from the system font table should notify other w ...
- 打开并锁定一个文件(使用LockFile API函数)
var aHandle : THandle; aFileSize : Integer; aFileName : String; procedure TForm1.Button3Click(Sender ...
随机推荐
- Vmware Briged方式使虚拟机上网
1.禁用掉在网络连接VMware Network Adapter VMnet1和VMware Network Adapter VMnet8 (在bridged这种方式下不需要这两个连接,如下图) 2. ...
- 网页制作之html基础学习2-标签
一.html结构组成 <html> --开始标签 <head> 网页上的控制信息 <title>页面标题</title> </head> & ...
- 转载python并行运算实例
Python的并发处理能力臭名昭著.先撇开线程以及GIL方面的问题不说,我觉得多线程问题的根源不在技术上而在于理念.大部分关于Pyhon线程和多进程的资料虽然都很不错,但却过于细节.这些资料讲的都是虎 ...
- 我的Python成长之路---第一天---Python基础(作业2:三级菜单)---2015年12月26日(雾霾)
作业二:三级菜单 三级菜单 可一次进入各个子菜单 思路: 这个题看似不难,难点在于三层循环的嵌套,我的思路就是通过flag的真假来控制每一层的循环的,简单来说就是就是通过给每一层循环一个单独的布尔变量 ...
- 新的 Windows Azure 网络安全性白皮书
下载新的 Windows Azure 网络安全性白皮书. Windows Azure 网络提供了将虚拟机安全连接到其他虚拟机所需的基础结构,以及云和内部部署数据中心之间的网桥. 本白皮书旨在挖掘这些内 ...
- cocos2d-x游戏开发系列教程-坦克大战游戏之所有坦克之间的碰撞检测
上篇我们完成了简单的AI编写,但是各个坦克移动时之间是可以重合的, 这节课我们来完成坦克之间的碰撞检测,还是在上篇的EnemyAI中完成. 1.我先现在坦克类Tank中添加两个成员变量: CC_SYN ...
- [置顶] 编程模仿boost::function和boost::bind
boost::function和boost::bind结合使用是非常强大的,他可以将成员函数和非成员函数绑定对一个对象上,实现了类似C#的委托机制.委托在许多时候可以替代C++里面的继承,实现对象解耦 ...
- 物理Data Guard主备切换步骤
物理Data Guard角色转换步骤 Step 1 验证主库是否能执行角色转换到备库(原主库执行) SQL> SELECT SWITCHOVER_STATUS FROM V$DATAB ...
- Eclipse 优化方法(经典收藏)
第一步: 取消自动validationvalidation有一堆,什么xml.jsp.jsf.js等等,我们没有必要全部都去自动校验一下,只是需要的时候才会手工校验一下! 取消方法:windows–& ...
- 基于visual Studio2013解决C语言竞赛题之1022最大数最小数
题目 解决代码及点评 /************************************************************************/ ...