PE Icon Replacer(PE 图标替换专家)
在不重新编译、不改代码段的前提下,给 Windows PE 文件(EXE/DLL)添加或替换图标资源。
核心做法:
> 复制原来的资源树,加入新的 RT_ICON / RT_GROUP_ICON,序列化成一个新的资源节,追加到文件末尾;再让 PE 的资源数据目录指向新节,最后修正节表、镜像大小、调试目录指针和校验和。
代码段、导入表、入口点、重定位都不改,所以不需要源代码,也不需要编译器。
功能
- 加图标:目标 EXE/DLL 原本没有
RT_GROUP_ICON时,自动新增组 ID1。 - 换图标:已有图标组时,默认替换排序后的第一组(通常就是资源管理器显示的那一组)。
- 保留旧资源:其他资源类型、其他图标组、旧图标图像全部保留。
- 任意路径:EXE、ICO、输出文件都可以是绝对路径或相对路径;支持空格、中文路径。
- 原地修改:不写
--output时直接修改目标文件,并自动生成<文件名>.bak。 - 多尺寸 ICO:一个 ICO 里有 16/32/48/64 多个帧时,会生成多个
RT_ICON,组数据逐一对应。 - 完整验证:
verify_icon.py会检查校验和、原有节数据、非图标资源、旧图标、新图标字节和 overlay。 - 安全处理签名:不会破坏文件结构,但会明确提示 Authenticode / catalog 签名失效。
环境依赖
- Python 3.8+
pefile
pip install pefile
也可以使用本 skill 的 requirements.txt(在 pe-icon-skill 根目录执行):
pip install -r requirements.txt
工具本身解析 .ico,不需要 PIL。pe_icon.py 可以在 Windows / Linux / macOS 上编辑 PE;图标在资源管理器里的显示效果建议在 Windows 上验证。
获取
从 SkillHub 安装本技能,或把整个 pe-icon-skill 目录复制到你的技能目录。然后:
cd pe-icon-skill\scripts
python pe_icon.py --help
快速使用
1. 给 EXE 加图标 / 换图标
python .\pe_icon.py `
"D:\程序\我的应用.exe" `
"D:\图标\新图标.ico" `
--output "D:\程序\我的应用_new.exe"
先输出到新文件,确认能启动、图标正确后再替换原文件,是最稳妥的用法。
2. 原地修改
python .\pe_icon.py "D:\程序\我的应用.exe" "D:\图标\新图标.ico"
会生成 D:\程序\我的应用.exe.bak。如果 .bak 已存在,不会覆盖旧备份。
3. 替换所有已有图标组
python .\pe_icon.py "D:\程序\我的应用.exe" "D:\图标\新图标.ico" --all-groups
默认只替换第一组;程序有多个图标组、或者按 ID 加载图标时,可以用 --all-groups。
4. 相对路径
cd /d D:\work
python "C:\Tools\pe-icon-skill\scripts\pe_icon.py" `
.\demo.exe .\demo.ico --output .\demo_with_icon.exe
相对路径按当前工作目录解析,不是按脚本所在目录解析。
5. 多尺寸 ICO
直接把多帧 .ico 传给工具即可,例如 16/32/48/64 四帧:
python .\pe_icon.py .\demo.exe .\multi-size.ico --output .\demo_with_icon.exe
验证结果
verify_icon.py 会执行一次注入并检查结果,适合在批量处理前验证样本:
# 默认输出到 %TEMP%\pe_icon_verify\<原名>_with_icon.exe
python .\verify_icon.py "D:\程序\我的应用.exe" "D:\图标\新图标.ico"
# 指定输出文件
python .\verify_icon.py `
"D:\程序\我的应用.exe" "D:\图标\新图标.ico" `
--output "D:\程序\我的应用_new.exe"
# 验证后启动输出(仅适合会自动退出的控制台程序)
python .\verify_icon.py `
"D:\程序\我的应用.exe" "D:\图标\新图标.ico" --run
验证内容:
- PE 校验和是否有效;
- 原有各节的代码/数据是否逐字节一致(只允许调试目录
PointerToRawData变化); - 非图标资源类型、语言、代码页是否保留;
- 旧
RT_ICON是否保留且字节不变; - 新
RT_GROUP_ICON的 ID 和每个RT_ICON是否与 ICO 对应帧一致; - 文件末尾的 overlay 是否完整保留;
- 使用
--force-expand-headers时,头部是否确实扩展且未覆盖第一个节。
不加参数运行 verify_icon.py 只显示帮助,不会自动执行任何操作。
参数
pe_icon.py
| 参数 | 说明 |
|---|---|
EXE |
输入 EXE/DLL,绝对或相对路径 |
ICON |
输入 .ico,绝对或相对路径 |
--output PATH |
输出文件;默认原地修改 |
--all-groups |
替换所有已有 RT_GROUP_ICON 组 |
--no-backup |
原地修改时不生成 .bak |
--force-expand-headers |
强制走“扩展 PE 头”路径,主要用于测试;空间不足时会报错 |
verify_icon.py
| 参数 | 说明 |
|---|---|
EXE |
输入 EXE/DLL |
ICON |
输入 .ico |
--output PATH |
输出文件;默认写入 %TEMP%\pe_icon_verify |
--run |
启动输出并要求退出码为 0 |
--all-groups |
替换所有已有图标组 |
--force-expand-headers |
强制扩展 PE 头 |
两个脚本都支持 --help。不传参数时:
pe_icon.py显示用法并报错(EXE、ICON是必填参数);verify_icon.py显示帮助和示例,不会执行注入。
工作流程
- 解析 PE 资源目录树,读出所有类型 / 名称 / 语言 / 数据。
- 解析 ICO 的目录和每个图像帧。
- 为每个 ICO 帧分配未占用的
RT_ICONID,生成RT_GROUP_ICON数据。 - 把完整资源树序列化成新的
.rsrcN节(若.rsrc已存在,则用.rsrc2、.rsrc3…)。 - 在最后一个节之后追加新节,保留原文件末尾的 overlay。
- 修正资源数据目录、节表、
SizeOfImage、SizeOfInitializedData、调试目录PointerToRawData、证书表偏移和 PE 校验和。 - 输出新文件;
verify_icon.py再按上述规则逐项验证。
为什么要追加新节
直接改旧 .rsrc 需要移动其中所有数据、重算所有内部偏移,容易破坏其他资源。追加新节只改资源目录指针和节表,旧资源树原样复制,风险更低。
头部空间不足时
新增节需要在节表末尾写一个 40 字节的节头。如果 SizeOfHeaders 不够,工具会:
- 把
SizeOfHeaders增加一个FileAlignment; - 在旧头部末尾插入零字节;
- 把后续所有节的文件偏移整体后移;
- 修正调试目录、证书表、符号表等文件偏移字段。
扩展后的头部不能超过第一个节的 RVA,否则会覆盖第一个节,Windows 会拒绝加载;工具会直接报错,不生成坏文件。
输入要求
- EXE/DLL:标准 PE32 或 PE32+ 文件,资源目录结构完整。加壳/压缩过的文件请先脱壳。
- ICO:至少包含 1 个图像帧;推荐 16/32/48/64 多尺寸。
- ICO 里的 256×256 尺寸按格式规定存为
0;工具按原始字段复制。 - 支持 PNG 压缩帧(按原始字节写入
RT_ICON)。 - 目标文件可以原本没有资源节,工具会从零创建。
注意事项
- 签名会失效:修改任何字节后,嵌入式 Authenticode 签名和 catalog 签名都不再有效。这是 PE 修改的固有结果,工具会在输出时提示。
- 备份只在原地修改时生成:使用
--output时原文件不动,不会额外生成.bak。 - 旧图标不删除:默认保留旧
RT_ICON,避免破坏其他图标组或程序中按 ID 加载图标的逻辑。 - 资源管理器图标缓存:替换成功后如果还看到旧图标,可能是系统图标缓存;重启
explorer.exe或清理图标缓存后再看。 - 程序自己缓存的图标:有些程序启动后自己缓存图标,需要重启程序或重新登录。
--force-expand-headers不是万能:如果第一个节 RVA 太小,扩展头会覆盖代码,工具会明确拒绝。- 不要直接修改系统文件:先复制到临时目录验证,确认后再替换。
故障排查
| 现象 | 原因 | 处理 |
|---|---|---|
pefile is required |
缺少依赖 | pip install pefile |
target not found |
EXE 路径不存在 | 检查路径;相对路径要基于当前工作目录 |
icon not found |
ICO 路径不存在 | 检查路径和引号 |
not a valid .ico file |
不是 ICO,或目录损坏 | 用画图/图标工具重新导出 ICO |
output directory not found |
输出目录不存在 | 先创建目录,或改用绝对路径 |
cannot expand headers |
头部扩展会覆盖第一个节 | 不要加 --force-expand-headers;或换一个头部空间足够的文件 |
| 输出文件打不开 | 输入 PE 本身损坏/加壳 | 先在原文件上验证能运行,再尝试注入 |
| 资源管理器仍显示旧图标 | 系统图标缓存 | 重启 explorer.exe,或清理图标缓存 |
| 程序仍显示旧图标 | 程序按 ID 加载或自身缓存 | 用 --all-groups,重启程序 |
checksum invalid |
输出被其他工具改动/截断 | 重新生成;不要让其他工具二次改写 |
| 杀毒软件拦截 | 修改后的 PE 无签名/行为可疑 | 使用可信来源文件;必要时对输出重新签名 |
文件结构
pe-icon-skill/
├── SKILL.md ← 本文件
├── requirements.txt ← Python 依赖
├── assets/
│ ├── icon.png ← 技能图标(1024×1024)
│ ├── icon-512.png ← 512×512
│ └── icon.ico ← 16–256 多尺寸图标
├── scripts/
│ ├── pe_icon.py ← 注入工具
│ └── verify_icon.py ← 注入并验证
└── examples/
├── README.md ← 示例说明
└── sample.ico ← 64×64 测试图标
分支根目录的 README.md 提供快速上手和分支约定。
使用示例
# 给任意 EXE 加图标
python .\pe_icon.py "C:\Tools\demo.exe" "C:\Icons\demo.ico" `
--output "C:\Tools\demo_new.exe"
# 原地替换,自动生成 demo.exe.bak
python .\pe_icon.py "C:\Tools\demo.exe" "C:\Icons\demo.ico"
# 先验证再批量处理
python .\verify_icon.py "C:\Tools\demo.exe" "C:\Icons\demo.ico"
# 多尺寸 ICO + 替换所有图标组
python .\pe_icon.py "C:\Tools\demo.exe" "C:\Icons\multi.ico" `
--all-groups --output "C:\Tools\demo_new.exe"
已验证场景
- PE32、原本无图标的 EXE:新增组
1、图像1,原.text/.data/.rsrc逐字节一致。 - PE32+、已有命名图标组(如
IDI_APPICON)的 EXE:使用--all-groups后组名保留,新图像 ID 追加,类型3/14/16/24保留。 - 16/32/48/64 多帧 ICO:生成 4 个
RT_ICON,每个图像与 ICO 对应帧字节一致。 - 带尾部 overlay 的 EXE:overlay 原样保留在文件末尾,且只出现一次。
--force-expand-headers:SizeOfHeaders成功扩展,旧节数据只允许调试目录PointerToRawData变化。
许可
MIT License