无忧启动论坛

 找回密码
 注册
搜索

[更新376#2825]PECMD2012.1.80.13_Win32_64.多窗口多线程.裸机系统2.3.3.1+18M酷M...

查看数: 2517916 | 评论数: 19510 | 收藏 230
关灯 | 提示:支持键盘翻页<-左 右->
    组图打开中,请稍候......
发布时间: 2012-1-22 08:30

正文摘要:

本帖最后由 mdyblog 于 2021-5-13 15:53 编辑 PECMD2012.1.77.0-Win32_64多窗口多线程(已升级) + 裸机系统2.3.4 + 18M-COOL MiniPE(已升级) ***已通过启动PE测试*** 功能特点: 多窗口 异形COOL窗口 ...

回复

阿弥陀佛 发表于 2014-5-24 12:07:48
mdyblog 发表于 2014-5-24 08:08
麻烦 试试 最新版(重新下载)

PART -super -up -swap:4    2#1

还是无效啊

点评

阿阿退休了?好久不见。  详情 回复 发表于 2018-10-19 20:29
你那U盘是 磁盘 #2吗? 一般是#1 如果这样,应改为: PART -super -up -swap:4 1#1 part -ahup hupdate 1 part -gui -usb //读卡器+SD卡刷新磁盘 ??  详情 回复 发表于 2014-5-24 13:55
2012bzsb 发表于 2014-6-24 18:57:38
哦,可能不同系统代码不同吧.
+空格, 可以出来

就这样吧
2010hktk 发表于 2014-7-12 13:58:50
PECMD2012.1.88.02.00-140625.多窗口线程稳定版_win32_64新设计.sfx.zip
这个版本在哪里有下载??
527104427 发表于 2014-7-17 22:08:11
mdyblog 发表于 2014-7-17 22:01
去掉空格
[Maxtor 6Y120L0                          ]
变成 [Maxtor6Y120L0]

WinHex 获取的型号,中间有个空格。
Diskgen 获取的型号,中间没空格。
不知道哪个更准确?

1.png (93.64 KB, 下载次数: 4545)

1.png

2.png (153 KB, 下载次数: 4426)

2.png

点评

硬盘上存储的本来有个空格。而且一般用空格填满整个剩余空间。 有些人去掉空格是, 简单地“碰到空格”。 还是【最好只去掉前后的空格,中间应该保留】吧。  详情 回复 发表于 2014-7-17 22:12
527104427 发表于 2014-7-17 20:07:45
mdyblog 发表于 2014-7-17 19:46
用局部PE变量,(或先设为空变量)

注意:不是所有磁盘都支持读硬件序列号。此时返回空。

我的是两个本地硬盘。原来还是有限制的

点评

》》两个本地硬盘 两个本地硬盘 都能拿回来 -devidx吗?  详情 回复 发表于 2014-7-17 20:10
527104427 发表于 2014-7-13 12:51:28
mdyblog 发表于 2014-7-13 12:37
>>这样也失败,有没有办法不展开变量%systemroot%?

OK
singel 发表于 2014-7-13 00:53:03
M大,网盘里1.88版怎么没了呢?

点评

同上。 怎么让飞行的子弹停住: 网络没缴费。 传上了。  详情 回复 发表于 2014-7-13 10:45
527104427 发表于 2014-7-17 22:03:35
mdyblog 发表于 2014-7-17 22:01
去掉空格
[Maxtor 6Y120L0                          ]
变成 [Maxtor6Y120L0]

最好只去掉前后的空格,中间应该保留吧

点评

试试这个 Disk[0] Mod[Maxtor 6Y120] SN[Y36MNBRE]  详情 回复 发表于 2014-7-17 22:21
阿弥陀佛 发表于 2014-7-17 13:41:02
tabs右边的边框是白色的,在win7下看不清楚。

点评

那是微软自己画的, 不同系统上不一样。 那是MS立体感。 左边是阴面,叫暗,右边是阳面,白亮白亮的。  详情 回复 发表于 2014-7-17 15:00
527104427 发表于 2014-7-17 11:48:59

点评

辛苦了  发表于 2024-7-31 21:37
新版: PART -devidx 支持拿到硬盘的物理序列号。 是磁盘本身的。 结果:  详情 回复 发表于 2014-7-17 14:27

评分

参与人数 1无忧币 +2 收起 理由
yyz2191958 + 2 赞一个!

查看全部评分

红毛樱木 发表于 9 小时前
Zap 发表于 2025-11-7 13:03
呼叫古希腊掌管代码的神

牛逼,你要双休吗
Zap 发表于 9 小时前
本帖最后由 Zap 于 2025-11-7 13:04 编辑
红毛樱木 发表于 2025-11-6 19:59
想翻译成PECMD,自己研究的代码要用C语言,不能用C++,不然不好翻译的。 PECMD我感觉是类似C风格的

呼叫古希腊掌管代码的神
  1. //返回程序第一个图标名
  2. #include <windows.h>
  3. #include <shlwapi.h>
  4. #include <wchar.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <io.h>      // 用于_setmode
  8. #include <fcntl.h>   // 用于_O_U16TEXT

  9. #pragma comment(lib, "shlwapi.lib")

  10. // 全局资源名称数组及计数
  11. wchar_t** g_resourceNames = NULL;
  12. int g_resourceCount = 0;

  13. // 资源枚举回调函数:正确处理整数ID和字符串名称
  14. BOOL CALLBACK EnumResNameProc(HMODULE hModule, LPCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam) {
  15.     wchar_t* resName = NULL;
  16.     if (IS_INTRESOURCE(lpszName)) {
  17.         // 处理整数ID(资源ID是16位无符号整数)
  18.         WORD id = (WORD)(UINT_PTR)lpszName;  // 正确转换资源ID
  19.         resName = (wchar_t*)malloc(64 * sizeof(wchar_t));  // 扩大缓冲区避免溢出
  20.         if (!resName) return FALSE;  // 检查内存分配失败
  21.         // 格式化整数ID为 "#数字"(例如#1000)
  22.         if (swprintf_s(resName, 64, L"#%u", id) < 0) {  // 使用%u匹配WORD(无符号)
  23.             free(resName);
  24.             return FALSE;
  25.         }
  26.     } else {
  27.         // 处理字符串名称(例如ICO_MYCOMPUTER)
  28.         size_t nameLen = wcslen(lpszName);
  29.         resName = (wchar_t*)malloc((nameLen + 1) * sizeof(wchar_t));
  30.         if (!resName) return FALSE;  // 检查内存分配失败
  31.         wcscpy_s(resName, nameLen + 1, lpszName);
  32.     }

  33.     // 扩展资源名称数组
  34.     wchar_t** newArray = (wchar_t**)realloc(g_resourceNames, (g_resourceCount + 1) * sizeof(wchar_t*));
  35.     if (!newArray) {
  36.         free(resName);
  37.         return FALSE;
  38.     }
  39.     g_resourceNames = newArray;
  40.     g_resourceNames[g_resourceCount++] = resName;
  41.     return TRUE;
  42. }

  43. // 释放资源名称数组内存
  44. void FreeResourceNames() {
  45.     for (int i = 0; i < g_resourceCount; i++) {
  46.         if (g_resourceNames[i]) free(g_resourceNames[i]);
  47.     }
  48.     free(g_resourceNames);
  49.     g_resourceNames = NULL;
  50.     g_resourceCount = 0;
  51. }

  52. // 显示帮助信息
  53. void ShowHelp(const wchar_t* programName) {
  54.     wprintf(L"用法: %ls <目标程序路径>\n", programName);
  55.     wprintf(L"示例: %ls C:\\Windows\\explorer.exe\n", programName);
  56. }

  57. int wmain(int argc, wchar_t* argv[]) {
  58.     // 设置控制台宽字符模式(确保中文和宽字符正常显示)
  59.     _setmode(_fileno(stdout), _O_U16TEXT);
  60.     _setmode(_fileno(stderr), _O_U16TEXT);

  61.     // 参数检查
  62.     if (argc != 2) {
  63.         ShowHelp(argv[0]);
  64.         return -1;
  65.     }

  66.     wchar_t targetPath[MAX_PATH];
  67.     wcscpy_s(targetPath, MAX_PATH, argv[1]);

  68.     // 检查目标文件是否存在
  69.     if (!PathFileExistsW(targetPath)) {
  70.         fwprintf(stderr, L"错误: 文件不存在 - %ls\n", argv[1]);
  71.         return -2;
  72.     }

  73.     // 加载目标程序作为资源文件(仅读取资源,不执行代码)
  74.     HMODULE hModule = LoadLibraryExW(targetPath, NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
  75.     if (!hModule) {
  76.         fwprintf(stderr, L"错误: 无法加载文件资源 (错误码: %d)\n", GetLastError());
  77.         return -3;
  78.     }

  79.     // 枚举所有图标组资源(RT_GROUP_ICON是图标组的资源类型)
  80.     FreeResourceNames();
  81.     if (!EnumResourceNamesW(hModule, RT_GROUP_ICON, EnumResNameProc, 0)) {
  82.         fwprintf(stderr, L"错误: 枚举图标资源失败 (错误码: %d)\n", GetLastError());
  83.         FreeLibrary(hModule);
  84.         FreeResourceNames();
  85.         return -3;
  86.     }

  87.     // 输出第一个图标组名称(修复格式符错误)
  88.     if (g_resourceCount > 0 && g_resourceNames[0]) {
  89.         // 修复:用%ls打印宽字符字符串(wchar_t*),而非%s
  90.         wprintf(L"%ls\n", g_resourceNames[0]);
  91.     } else {
  92.         fwprintf(stderr, L"错误: 未找到图标组资源\n");
  93.         FreeLibrary(hModule);
  94.         FreeResourceNames();
  95.         return -3;
  96.     }

  97.     // 清理资源
  98.     FreeLibrary(hModule);
  99.     FreeResourceNames();
  100.     return 0;
  101. }
复制代码

点评

牛逼,你要双休吗  详情 回复 发表于 9 小时前
5315929 发表于 昨天 20:11
感谢分享。
红毛樱木 发表于 昨天 19:59

想翻译成PECMD,自己研究的代码要用C语言,不能用C++,不然不好翻译的。 PECMD我感觉是类似C风格的

点评

Zap
呼叫古希腊掌管代码的神  详情 回复 发表于 9 小时前
Zap 发表于 昨天 18:02
红毛樱木 发表于 2025-11-6 12:45
你第一次给的C++源码,我都帮你翻译完了。而且你代码里的逻辑不对,我也帮你改了。  还要咋样呀。。。我 ...

PECMD太难了

点评

想翻译成PECMD,自己研究的代码要用C语言,不能用C++,不然不好翻译的。 PECMD我感觉是类似C风格的  详情 回复 发表于 昨天 19:59
红毛樱木 发表于 昨天 12:45
Zap 发表于 2025-11-6 12:13
你咋不一次改成  我这今天才研究出来,大前天还不会

你第一次给的C++源码,我都帮你翻译完了。而且你代码里的逻辑不对,我也帮你改了。  还要咋样呀。。。我都不知道你代码的原理

点评

Zap
PECMD太难了  详情 回复 发表于 昨天 18:02
Zap 发表于 昨天 12:34
527104427 发表于 2025-11-6 12:29
你没发现你把一个括号改丢了吗?

丢不丢都一样了 因为错不在这 前面都截胡了
快去请掌管代码的神@mdyblog

点评

你牛逼,你来请  发表于 昨天 12:40
527104427 发表于 昨天 12:29
Zap 发表于 2025-11-6 12:13
你咋不一次改成  我这今天才研究出来,大前天还不会


你没发现你把一个括号改丢了吗?



点评

Zap
丢不丢都一样了 因为错不在这 前面都截胡了 快去请掌管代码的神@mdyblog  详情 回复 发表于 昨天 12:34
Zap 发表于 昨天 12:13
红毛樱木 发表于 2025-11-6 11:07
太费劲了,帖代码咋不一次帖完。   不想看不想研究,你自己改吧

你咋不一次改成  我这今天才研究出来,大前天还不会

点评

你第一次给的C++源码,我都帮你翻译完了。而且你代码里的逻辑不对,我也帮你改了。 还要咋样呀。。。我都不知道你代码的原理  详情 回复 发表于 昨天 12:45
你没发现你把一个括号改丢了吗? [attachimg]567152[/attachimg]  详情 回复 发表于 昨天 12:29
红毛樱木 发表于 昨天 11:07

太费劲了,帖代码咋不一次帖完。   不想看不想研究,你自己改吧

点评

Zap
你咋不一次改成 我这今天才研究出来,大前天还不会  详情 回复 发表于 昨天 12:13
Zap 发表于 昨天 11:05
  1. #include <windows.h>
  2. #include <vector>
  3. #include <string>
  4. #include <fstream>
  5. #include <cstdlib>
  6. #include <iostream>
  7. #include <iomanip>
  8. #include <sstream>
  9. #include <algorithm>

  10. // 全局向量存储资源名称(替代 AutoIt 的 $aEN 数组)
  11. std::vector<std::wstring> g_resourceNames;

  12. // 资源枚举回调函数(替代 AutoIt 的 ___EnumResNameProc)
  13. BOOL CALLBACK EnumResNameProc(HMODULE hModule, LPCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam) {
  14.     if (IS_INTRESOURCE(lpszName)) {
  15.         // ★ 处理整数型资源 ID(如 #123)
  16.         WORD id = static_cast<WORD>(reinterpret_cast<ULONG_PTR>(lpszName));
  17.         std::wstringstream wss;
  18.         wss << L"#" << id;
  19.         g_resourceNames.push_back(wss.str());
  20.     } else {
  21.         // ★ 处理字符串型资源名称
  22.         g_resourceNames.push_back(lpszName);
  23.     }
  24.     return TRUE; // 继续枚举
  25. }

  26. int wmain(int argc, wchar_t* argv[]) {
  27.     // ===== 1. 命令行参数处理 =====
  28.     if (argc != 4) {
  29.         std::wcerr << L"用法: " << argv[0] << L" <文件> <索引> <输出文件>\n";
  30.         return -1;
  31.     }

  32.     std::wstring file = argv[1];
  33.     int index = _wtoi(argv[2]);       // 转换索引参数
  34.     std::wstring outputFile = argv[3];

  35.     // ===== 2. 文件存在性检查 =====
  36.     if (!PathFileExistsW(file.c_str())) {
  37.         wchar_t sysDir[MAX_PATH];
  38.         // 获取系统目录路径
  39.         UINT sysDirLen = GetSystemDirectoryW(sysDir, MAX_PATH);
  40.         if (sysDirLen == 0 || sysDirLen > MAX_PATH) {
  41.             std::wcerr << L"错误: 无法获取系统目录\n";
  42.             return -2;
  43.         }
  44.         // 尝试在系统目录中查找
  45.         std::wstring sysFile = std::wstring(sysDir) + L"\" + file;
  46.         if (!PathFileExistsW(sysFile.c_str())) {
  47.             std::wcerr << argv[1] << L" 未找到\n";
  48.             return -2;
  49.         }
  50.         file = sysFile; // 使用系统目录中的文件
  51.     }

  52.     // ===== 3. 加载目标文件为数据文件 =====
  53.     HMODULE hModule = LoadLibraryExW(
  54.         file.c_str(),
  55.         NULL,
  56.         LOAD_LIBRARY_AS_DATAFILE // 重要:仅作为资源加载
  57.     );
  58.     if (!hModule) {
  59.         std::wcerr << L"错误: 无法加载文件资源\n";
  60.         return -3;
  61.     }

  62.     // ===== 4. 枚举图标组资源 =====
  63.     g_resourceNames.clear();
  64.     if (!EnumResourceNamesW(
  65.         hModule,
  66.         RT_GROUP_ICON,       // 图标组资源类型
  67.         EnumResNameProc,     // 回调函数
  68.         0                    // 回调参数
  69.     )) {
  70.         FreeLibrary(hModule);
  71.         std::wcerr << L"错误: 枚举资源失败\n";
  72.         return -3;
  73.     }

  74.     // ===== 5. 验证并选择图标索引 =====
  75.     int absIndex = abs(index); // 处理负索引
  76.     if (absIndex < 1 || absIndex > static_cast<int>(g_resourceNames.size())) {
  77.         FreeLibrary(hModule);
  78.         std::wcerr << L"错误: 无效的图标索引\n";
  79.         return -3;
  80.     }
  81.     std::wstring resName = g_resourceNames[absIndex - 1]; // 转换为0-based索引

  82.     // ===== 6. 准备资源标识符 =====
  83.     LPCWSTR lpResName;
  84.     if (resName[0] == L'#') {
  85.         // ★ 转换 "#数字" 格式为资源ID
  86.         int id = std::wcstol(resName.substr(1).c_str(), nullptr, 10);
  87.         lpResName = MAKEINTRESOURCEW(id);
  88.     } else {
  89.         // ★ 直接使用字符串资源名
  90.         lpResName = resName.c_str();
  91.     }

  92.     // ===== 7. 加载图标组资源 =====
  93.     HRSRC hGroupRes = FindResourceW(hModule, lpResName, RT_GROUP_ICON);
  94.     if (!hGroupRes) {
  95.         FreeLibrary(hModule);
  96.         std::wcerr << L"错误: 未找到图标组资源\n";
  97.         return -3;
  98.     }

  99.     // 获取资源大小
  100.     DWORD groupSize = SizeofResource(hModule, hGroupRes);
  101.     if (groupSize < 6) { // 最小头尺寸检查
  102.         FreeLibrary(hModule);
  103.         return -3;
  104.     }

  105.     // 加载并锁定资源
  106.     HGLOBAL hGroupData = LoadResource(hModule, hGroupRes);
  107.     if (!hGroupData) {
  108.         FreeLibrary(hModule);
  109.         return -3;
  110.     }
  111.     BYTE* pGroupData = static_cast<BYTE*>(LockResource(hGroupData));
  112.     if (!pGroupData) {
  113.         FreeLibrary(hModule);
  114.         return -3;
  115.     }

  116.     // ===== 8. 解析图标组头信息 =====
  117.     WORD reserved = *reinterpret_cast<WORD*>(pGroupData);      // 保留字段 (应为0)
  118.     WORD type = *reinterpret_cast<WORD*>(pGroupData + 2);      // 资源类型 (应为1)
  119.     WORD count = *reinterpret_cast<WORD*>(pGroupData + 4);     // 图标数量

  120.     // 验证图标组头
  121.     if (reserved != 0 || type != 1 || groupSize < 6 + 14 * count) {
  122.         FreeLibrary(hModule);
  123.         std::wcerr << L"错误: 无效的图标组格式\n";
  124.         return -3;
  125.     }

  126.     // ===== 9. 创建输出ICO文件 =====
  127.     std::ofstream outFile(outputFile, std::ios::binary);
  128.     if (!outFile.is_open()) {
  129.         FreeLibrary(hModule);
  130.         std::wcerr << L"错误: 无法创建输出文件\n";
  131.         return -3;
  132.     }

  133.     // ===== 10. 写入ICO文件头 =====
  134.     DWORD offset = 6 + 16 * count; // 计算首个图标数据偏移量
  135.     outFile.write(reinterpret_cast<char*>(pGroupData), 6); // 写入ICO头
  136.     if (!outFile) {
  137.         outFile.close();
  138.         FreeLibrary(hModule);
  139.         return -3;
  140.     }

  141.     // ===== 11. 处理每个图标条目 =====
  142.     for (WORD i = 0; i < count; ++i) {
  143.         BYTE* pEntry = pGroupData + 6 + 14 * i; // 当前图标条目指针
  144.         
  145.         // 修改条目中的偏移量字段
  146.         outFile.write(reinterpret_cast<char*>(pEntry), 12); // 写入前12字节
  147.         outFile.write(reinterpret_cast<char*>(&offset), 4); // 写入新计算的偏移量
  148.         
  149.         if (!outFile) {
  150.             outFile.close();
  151.             FreeLibrary(hModule);
  152.             return -3;
  153.         }
  154.         
  155.         // 更新下一个图标的偏移量
  156.         DWORD iconSize = *reinterpret_cast<DWORD*>(pEntry + 8);
  157.         offset += iconSize;
  158.     }

  159.     // ===== 12. 写入图标数据 =====
  160.     for (WORD i = 0; i < count; ++i) {
  161.         BYTE* pEntry = pGroupData + 6 + 14 * i;
  162.         WORD iconId = *reinterpret_cast<WORD*>(pEntry + 12); // 获取图标ID
  163.         
  164.         // 加载单个图标资源
  165.         HRSRC hIconRes = FindResourceW(hModule, MAKEINTRESOURCEW(iconId), RT_ICON);
  166.         if (!hIconRes) {
  167.             outFile.close();
  168.             FreeLibrary(hModule);
  169.             std::wcerr << L"错误: 未找到图标资源\n";
  170.             return -3;
  171.         }

  172.         // 获取图标数据
  173.         DWORD iconSize = SizeofResource(hModule, hIconRes);
  174.         HGLOBAL hIconData = LoadResource(hModule, hIconRes);
  175.         if (!hIconData || iconSize == 0) {
  176.             outFile.close();
  177.             FreeLibrary(hModule);
  178.             return -3;
  179.         }
  180.         
  181.         BYTE* pIconData = static_cast<BYTE*>(LockResource(hIconData));
  182.         if (!pIconData) {
  183.             outFile.close();
  184.             FreeLibrary(hModule);
  185.             return -3;
  186.         }

  187.         // 写入图标数据到文件
  188.         outFile.write(reinterpret_cast<char*>(pIconData), iconSize);
  189.         if (!outFile) {
  190.             outFile.close();
  191.             FreeLibrary(hModule);
  192.             return -3;
  193.         }
  194.     }

  195.     // ===== 13. 清理资源 =====
  196.     outFile.close();
  197.     FreeLibrary(hModule);
  198.     std::wcout << L"图标成功导出至: " << outputFile << std::endl;
  199.     return 0; // 成功退出
  200. }
复制代码

点评

太费劲了,帖代码咋不一次帖完。 不想看不想研究,你自己改吧  详情 回复 发表于 昨天 11:07
Zap 发表于 昨天 11:00
红毛樱木 发表于 2025-11-5 23:36
更正后的代码。
C++源码你自己改吧....

换个程序就不行了
Zap 发表于 昨天 10:53
又不行了
  1. //LOGS * %&CurDir%\log.log
  2. ENVI^ ENVIMODE=1

  3. ENVI &exePath=D:\软件\BCompare\BCompare.exe   //C:\Windows\explorer.exe //C:\Windows\System32\calc.exe
  4. CALL GetFirstIconGroupID "%&exePath%" &iconId
  5. MESS. 第一个图标ID:%&iconId%@
  6. exit

  7. _SUB GetFirstIconGroupID
  8.     ENVI-ret %~2=0
  9.     ENVI &&exePath=%~1
  10.     ENVI &&GENERIC_READ=0x80000000
  11.     ENVI &&FILE_SHARE_READ=0x00000001
  12.     ENVI &&OPEN_EXISTING=3
  13.     ENVI &&INVALID_HANDLE_VALUE=-1
  14.     CALL$--qd --ret:&&hFile Kernel32.dll,CreateFileW,$%&exePath%,#%&GENERIC_READ%,#%&FILE_SHARE_READ%,#0,#%&OPEN_EXISTING%,#0,#0       // C中的NULL就是0,在PECMD中用数值 #0
  15.     IFEX #%&hFile%=%&INVALID_HANDLE_VALUE%,
  16.     {*
  17.         ENVI-ret %~2=0
  18.         EXIT _SUB
  19.     }
  20.     CALL$--qd --ret:&&fileSize Kernel32.dll,GetFileSize,#%&hFile%,#0
  21.     ENVI &&PAGE_READONLY=0x02
  22.     CALL$--qd --ret:&&hMap Kernel32.dll,CreateFileMappingW,#%&hFile%,#0,#%&PAGE_READONLY%,#0,#%&fileSize%,0     //CreateFileMapping 要用实际的 CreateFileMappingW
  23.     ENVI &&FILE_MAP_READ=0x0004
  24.     CALL$--qd --16 --ret:&&pBase Kernel32.dll,MapViewOfFile,#%&hMap%,#%&FILE_MAP_READ%,#0,#0,#0
  25.     IFEX #%&pBase%=0,
  26.     {*
  27.         CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  28.         CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  29.         ENVI-ret %~2=0
  30.         EXIT _SUB
  31.     }
  32.     // PIMAGE_DOS_HEADER 的结构体 IMAGE_DOS_HEADER  64字节
  33.     //SET$# &dos=*64 0
  34.     SET-mkfixdummy &dos=%&pBase%@0;*64
  35.     SET?longs dos=&&dos.e_lfanew:60
  36.     //MESS. %&dos.e_lfanew%@&dos.e_lfanew
  37.     // PIMAGE_NT_HEADERS 的结构体(64位为 IMAGE_NT_HEADERS64 大小 264字节)(32位为 IMAGE_NT_HEADERS32 大小 248字节)
  38.     IFEX #0,    //判断错误,应该直接判断PE文件头是32位还是64位。
  39.     {*
  40.     IFEX #%&bX64%=3,
  41.     {*
  42.         //SET$# &nt=*264 0
  43.         SET-mkfixdummy &nt=(%&pBase%+%&dos.e_lfanew%)@0;*264
  44.     }!
  45.     {*
  46.         //SET$# &nt=*248 0
  47.         SET-mkfixdummy &nt=(%&pBase%+%&dos.e_lfanew%)@0;*248
  48.     }
  49.     }
  50.     ENVI &&IMAGE_NT_OPTIONAL_HDR32_MAGIC=0x10b      //32位
  51.     ENVI &&IMAGE_NT_OPTIONAL_HDR64_MAGIC=0x20b      //64位
  52.     SET?short (%&pBase%+%&dos.e_lfanew%)=&&nt.OptionalHeader.Magic:24
  53.     //MESS. %&nt.OptionalHeader.Magic%@&nt.OptionalHeader.Magic
  54.     IFEX #%&nt.OptionalHeader.Magic%=%&IMAGE_NT_OPTIONAL_HDR32_MAGIC%,
  55.     {*
  56.         SET-mkfixdummy &nt=(%&pBase%+%&dos.e_lfanew%)@0;*248
  57.     }!
  58.     {*
  59.         IFEX #%&nt.OptionalHeader.Magic%=%&IMAGE_NT_OPTIONAL_HDR64_MAGIC%,
  60.         {*
  61.             SET-mkfixdummy &nt=(%&pBase%+%&dos.e_lfanew%)@0;*264
  62.         }!
  63.         {*
  64.             CALL$--qd --bool --ret:&&UnmapViewOfFileRet Kernel32.dll,UnmapViewOfFile,#%&pBase%;
  65.             CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  66.             CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  67.             ENVI-ret %~2=0
  68.             EXIT _SUB
  69.         }
  70.     }
  71.     //GETF &nt,0#*,&&nt_Hex
  72.     //MESS. %&nt_Hex%@&nt_Hex
  73.     SET?long nt=&&nt.Signature:0
  74.     //MESS. %&nt.Signature%@&nt.Signature
  75.     ENVI &&IMAGE_NT_SIGNATURE=0x00004550  // PE00
  76.     IFEX #%&nt.Signature%<>%&IMAGE_NT_SIGNATURE%,
  77.     {*
  78.         CALL$--qd --bool --ret:&&UnmapViewOfFileRet Kernel32.dll,UnmapViewOfFile,#%&pBase%;
  79.         CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  80.         CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  81.         ENVI-ret %~2=0
  82.         EXIT _SUB
  83.     }

  84.     // 定位资源目录
  85.     // auto& resDir = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
  86.     ENVI &&IMAGE_DIRECTORY_ENTRY_RESOURCE=2   // Resource Directory
  87.     //ENVI &&IMAGE_DIRECTORY_ENTRY_RESOURCE=0     // 测试
  88.     IFEX #0,
  89.     {*
  90.     IFEX #%&bX64%=3,
  91.     {*
  92.         SET-mkfixdummy &resDir=&nt@(4+20+112+(8*%&IMAGE_DIRECTORY_ENTRY_RESOURCE%));*8
  93.     }!
  94.     {*
  95.         SET-mkfixdummy &resDir=&nt@(4+20+96+(8*%&IMAGE_DIRECTORY_ENTRY_RESOURCE%));*8
  96.     }
  97.     }
  98.     IFEX #%&nt.OptionalHeader.Magic%=%&IMAGE_NT_OPTIONAL_HDR32_MAGIC%,
  99.     {*
  100.         SET-mkfixdummy &resDir=&nt@(4+20+96+(8*%&IMAGE_DIRECTORY_ENTRY_RESOURCE%));*8
  101.     }!
  102.     {*
  103.         IFEX #%&nt.OptionalHeader.Magic%=%&IMAGE_NT_OPTIONAL_HDR64_MAGIC%,
  104.         {*
  105.             SET-mkfixdummy &resDir=&nt@(4+20+112+(8*%&IMAGE_DIRECTORY_ENTRY_RESOURCE%));*8
  106.         }!
  107.         {*
  108.             CALL$--qd --bool --ret:&&UnmapViewOfFileRet Kernel32.dll,UnmapViewOfFile,#%&pBase%;
  109.             CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  110.             CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  111.             ENVI-ret %~2=0
  112.             EXIT _SUB
  113.         }
  114.    
  115.     //GETF &resDir,0#*,&&resDir_Hex
  116.     //MESS. %&resDir_Hex%@&resDir_Hex
  117.     SET?long resDir=&&resDir.VirtualAddress:0
  118.     //MESS. %&resDir.VirtualAddress%@&resDir.VirtualAddress

  119.     // 定位资源节(.rsrc)
  120.     ENVI &&i=0
  121.     SET?shorts nt=&&nt.FileHeader.NumberOfSections:(4+2)    //WORD 2 字节,用short和wchar都可以
  122.     //MESS. %&nt.FileHeader.NumberOfSections%@&nt.FileHeader.NumberOfSections
  123.     SET?shorts nt=&&nt.FileHeader.SizeOfOptionalHeader:(4+2+2+4+4+4)
  124.     //MESS. %&nt.FileHeader.SizeOfOptionalHeader%@&nt.FileHeader.SizeOfOptionalHeader
  125.     //SET-mkfixdummy &section=&nt

  126.     LOOP #%&i%<%&nt.FileHeader.NumberOfSections%,
  127.     {*
  128.         //#define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER) ((ULONG_PTR)(ntheader) + FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + ((ntheader))->FileHeader.SizeOfOptionalHeader ))
  129.         SET-mkfixdummy &section=(%&pBase%+%&dos.e_lfanew%+(4+20+%&nt.FileHeader.SizeOfOptionalHeader%))@(40*%&i%);*40        // 相当于 section++
  130.         //GETF &section,0#40,&&section_Hex
  131.         //MESS. %&section_Hex%@&section_Hex
  132.         SET?long section=&&section.VirtualAddress:12
  133.         //MESS. &section.VirtualAddress:%&section.VirtualAddress%@%&i%
  134.         SET?long section=&&section.Misc.VirtualSize:8
  135.         //MESS. IFEX #[ ( %&resDir.VirtualAddress% >= %&section.VirtualAddress% ) & ( %&resDir.VirtualAddress% < ( %&section.VirtualAddress% + %&section.Misc.VirtualSize% ) ) ],@%&i%
  136.         //IFEX #[ ( %&resDir.VirtualAddress% >= %&section.VirtualAddress% ) & ( %&resDir.VirtualAddress% < ( %&section.VirtualAddress% + %&section.Misc.VirtualSize% ) ) ],     // IFEX 存在BUG,不能这样嵌套使用,先算出来吧。
  137.         IFEX #%&resDir.VirtualAddress% >= %&section.VirtualAddress%,
  138.         {*
  139.             CALC &&Fix=%&section.VirtualAddress% + %&section.Misc.VirtualSize%
  140.             IFEX #%&resDir.VirtualAddress% < %&Fix%,
  141.             {*
  142.                 EXIT LOOP
  143.             }
  144.         }
  145.         CALC #&i=%&i% + 1
  146.     }
  147.     // 计算资源目录在文件中的实际偏移
  148.     SET?long section=&&section.PointerToRawData:20
  149.     CALC #&&resOffset=%&resDir.VirtualAddress% - %&section.VirtualAddress% + %&section.PointerToRawData%
  150.     //MESS. %&resOffset%<&i:%&i%><CALC #&&resOffset=%&resDir.VirtualAddress% - %&section.VirtualAddress% + %&section.PointerToRawData%>@&resOffset
  151.     SET-mkfixdummy &rootDir=(%&pBase%+%&resOffset%)@0;*16
  152.     SET?short rootDir=&&rootDir.NumberOfIdEntries:(4+4+2+2+2)
  153.     //MESS. %&rootDir.NumberOfIdEntries%@&rootDir.NumberOfIdEntries

  154.     // 遍历资源类型,找到 RT_GROUP_ICON(ID=14)
  155.     //SET-mkfixdummy &typeEntry=(%&pBase%+%&resOffset%)@16;*8
  156.     //GETF &typeEntry,0#8,&&typeEntry_Hex
  157.     //MESS. %&typeEntry_Hex%@&typeEntry_Hex

  158.     ENVI &&i=0
  159.     LOOP #%&i%<%&rootDir.NumberOfIdEntries%,
  160.     {*
  161.         SET-mkfixdummy &typeEntry=(%&pBase%+%&resOffset%)@(16+(8*%&i%));*8
  162.         SET?short typeEntry=&&typeEntry.Id:0
  163.         //MESS. %&typeEntry.Id%@%&i%
  164.         IFEX #%&typeEntry.Id%=14,       // RT_GROUP_ICON = 14
  165.         {*
  166.             // 获取第一个图标ID(进入ID目录的第一个条目)
  167.             SET?long typeEntry=&&typeEntry.OffsetToDirectory:4
  168.             CALC #&typeEntry.OffsetToDirectory=%&typeEntry.OffsetToDirectory% & 0x7FFFFFFF
  169.             SET-mkfixdummy &iconDir=(%&pBase%+%&resOffset%)@%&typeEntry.OffsetToDirectory%;*16
  170.             SET-mkfixdummy &iconIdEntry=(%&pBase%+%&resOffset%)@(%&typeEntry.OffsetToDirectory%+16);*8
  171.             SET?short iconIdEntry=&&iconIdEntry.Id:0

  172.             // 判断条目类型 (高位为1表示命名条目)
  173.             IFEX #%&iconIdEntry.Id% >= 0x0,
  174.             {*
  175.                 // 命名条目处理
  176.                 CALC #&&nameOffset=%&iconIdEntry.Id% & 0x7FFF
  177.                 SET-mkfixdummy &nameHeader=(%&pBase%+%&resOffset%+%&nameOffset%)@0;*2
  178.                 SET?short nameHeader=&&nameHeader.Length:0

  179.                 // 读取Unicode字符串
  180.                 CALC #&strAddr=%&resOffset% + %&nameOffset% + 2
  181.                 GETF "%&exePath%",%&strAddr%#(%&nameHeader.Length%+14),&buffer
  182.                           
  183.                 SET#% a=%&buffer%
  184.                 CODE *,%a%,**-UNICODE,UNI
  185.                
  186.                 mess %&pBase% + %&resOffset% + %&nameOffset% + 2\n%&strAddr% %&nameHeader.Length%\n%UNI%
  187.                 ENVI-ret~ %~2=UNI
  188.             }!
  189.             {*
  190.                 // ID条目处理
  191.                 ENVI-ret~ %~2=%&iconIdEntry.Id%
  192.             }

  193.             CALL$--qd --bool --ret:&&UnmapViewOfFileRet Kernel32.dll,UnmapViewOfFile,#%&pBase%;
  194.             CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  195.             CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  196.             EXIT _SUB
  197.         }
  198.         CALC #&i=%&i% + 1
  199.     }
  200.     CALL$--qd --bool --ret:&&UnmapViewOfFileRet Kernel32.dll,UnmapViewOfFile,#%&pBase%;
  201.     CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  202.     CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  203.     ENVI-ret %~2=0
  204. _END
复制代码
Zap 发表于 昨天 09:45
红毛樱木 发表于 2025-11-5 23:36
更正后的代码。
C++源码你自己改吧....

搞不定
  1. //LOGS * %&CurDir%\log.log
  2. ENVI^ ENVIMODE=1
  3. ENVI &exePath=C:\Windows\explorer.exe

  4. CALL GetFirstIconGroupID "%&exePath%" &iconId
  5. MESS. 第一个图标ID: %&iconId%@
  6. exit

  7. _SUB GetFirstIconGroupID
  8.     ENVI-ret %~2=0
  9.     ENVI &&exePath=%~1
  10.     ENVI &&GENERIC_READ=0x80000000
  11.     ENVI &&FILE_SHARE_READ=0x00000001
  12.     ENVI &&OPEN_EXISTING=3
  13.     ENVI &&INVALID_HANDLE_VALUE=-1
  14.     CALL$--qd --ret:&&hFile Kernel32.dll,CreateFileW,$%&exePath%,#%&GENERIC_READ%,#%&FILE_SHARE_READ%,#0,#%&OPEN_EXISTING%,#0,#0
  15.     IFEX #%&hFile%=%&INVALID_HANDLE_VALUE%,
  16.     {*
  17.         ENVI-ret %~2=0
  18.         EXIT _SUB
  19.     }
  20.     CALL$--qd --ret:&&fileSize Kernel32.dll,GetFileSize,#%&hFile%,#0
  21.     ENVI &&PAGE_READONLY=0x02
  22.     CALL$--qd --ret:&&hMap Kernel32.dll,CreateFileMappingW,#%&hFile%,#0,#%&PAGE_READONLY%,#0,#%&fileSize%,0
  23.     ENVI &&FILE_MAP_READ=0x0004
  24.     CALL$--qd --16 --ret:&&pBase Kernel32.dll,MapViewOfFile,#%&hMap%,#%&FILE_MAP_READ%,#0,#0,#0
  25.     IFEX #%&pBase%=0,
  26.     {*
  27.         CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  28.         CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  29.         ENVI-ret %~2=0
  30.         EXIT _SUB
  31.     }
  32.    
  33.     SET-mkfixdummy &dos=%&pBase%@0;*64
  34.     SET?longs dos=&&dos.e_lfanew:60
  35.    
  36.     ENVI &&IMAGE_NT_OPTIONAL_HDR32_MAGIC=0x10b
  37.     ENVI &&IMAGE_NT_OPTIONAL_HDR64_MAGIC=0x20b
  38.     SET?short (%&pBase%+%&dos.e_lfanew%)=&&nt.OptionalHeader.Magic:24
  39.    
  40.     IFEX #%&nt.OptionalHeader.Magic%=%&IMAGE_NT_OPTIONAL_HDR32_MAGIC%,
  41.     {*
  42.         SET-mkfixdummy &nt=(%&pBase%+%&dos.e_lfanew%)@0;*248
  43.     }!
  44.     {*
  45.         IFEX #%&nt.OptionalHeader.Magic%=%&IMAGE_NT_OPTIONAL_HDR64_MAGIC%,
  46.         {*
  47.             SET-mkfixdummy &nt=(%&pBase%+%&dos.e_lfanew%)@0;*264
  48.         }!
  49.         {*
  50.             CALL$--qd --bool --ret:&&UnmapViewOfFileRet Kernel32.dll,UnmapViewOfFile,#%&pBase%;
  51.             CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  52.             CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  53.             ENVI-ret %~2=0
  54.             EXIT _SUB
  55.         }
  56.     }
  57.    
  58.     SET?long nt=&&nt.Signature:0
  59.     ENVI &&IMAGE_NT_SIGNATURE=0x00004550
  60.     IFEX #%&nt.Signature%<>%&IMAGE_NT_SIGNATURE%,
  61.     {*
  62.         CALL$--qd --bool --ret:&&UnmapViewOfFileRet Kernel32.dll,UnmapViewOfFile,#%&pBase%;
  63.         CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  64.         CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  65.         ENVI-ret %~2=0
  66.         EXIT _SUB
  67.     }

  68.     ENVI &&IMAGE_DIRECTORY_ENTRY_RESOURCE=2
  69.     IFEX #%&nt.OptionalHeader.Magic%=%&IMAGE_NT_OPTIONAL_HDR32_MAGIC%,
  70.     {*
  71.         SET-mkfixdummy &resDir=&nt@(4+20+96+(8*%&IMAGE_DIRECTORY_ENTRY_RESOURCE%));*8
  72.     }!
  73.     {*
  74.         SET-mkfixdummy &resDir=&nt@(4+20+112+(8*%&IMAGE_DIRECTORY_ENTRY_RESOURCE%));*8
  75.     }
  76.    
  77.     SET?long resDir=&&resDir.VirtualAddress:0
  78.    
  79.     ENVI &&i=0
  80.     SET?shorts nt=&&nt.FileHeader.NumberOfSections:(4+2)
  81.     SET?shorts nt=&&nt.FileHeader.SizeOfOptionalHeader:(4+2+2+4+4+4)
  82.    
  83.     LOOP #%&i%<%&nt.FileHeader.NumberOfSections%,
  84.     {*
  85.         SET-mkfixdummy &section=(%&pBase%+%&dos.e_lfanew%+(4+20+%&nt.FileHeader.SizeOfOptionalHeader%))@(40*%&i%);*40
  86.         SET?long section=&&section.VirtualAddress:12
  87.         SET?long section=&&section.Misc.VirtualSize:8
  88.         IFEX #%&resDir.VirtualAddress% >= %&section.VirtualAddress%,
  89.         {*
  90.             CALC &&Fix=%&section.VirtualAddress% + %&section.Misc.VirtualSize%
  91.             IFEX #%&resDir.VirtualAddress% < %&Fix%,
  92.             {*
  93.                 EXIT LOOP
  94.             }
  95.         }
  96.         CALC #&i=%&i% + 1
  97.     }
  98.    
  99.     SET?long section=&&section.PointerToRawData:20
  100.     CALC #&&resOffset=%&resDir.VirtualAddress% - %&section.VirtualAddress% + %&section.PointerToRawData%
  101.     SET-mkfixdummy &rootDir=(%&pBase%+%&resOffset%)@0;*16
  102.     SET?short rootDir=&&rootDir.NumberOfIdEntries:(4+4+2+2+2)
  103.    
  104.     ENVI &&i=0
  105.     LOOP #%&i%<%&rootDir.NumberOfIdEntries%,
  106.     {*
  107.         SET-mkfixdummy &typeEntry=(%&pBase%+%&resOffset%)@(16+(8*%&i%));*8
  108.         SET?short typeEntry=&&typeEntry.Id:0
  109.         
  110.         IFEX #%&typeEntry.Id%=14,  // RT_GROUP_ICON
  111.         {*
  112.             SET?long typeEntry=&&typeEntry.OffsetToDirectory:4
  113.             CALC #&typeEntry.OffsetToDirectory=%&typeEntry.OffsetToDirectory% & 0x7FFFFFFF
  114.             SET-mkfixdummy &iconDir=(%&pBase%+%&resOffset%)@%&typeEntry.OffsetToDirectory%;*16
  115.             
  116.             // 获取第一个条目(可能是命名或ID条目)
  117.             SET-mkfixdummy &iconIdEntry=(%&pBase%+%&resOffset%+%&typeEntry.OffsetToDirectory%+16)@0;*8
  118.             SET?short iconIdEntry=&&iconIdEntry.Id:0
  119.             
  120.             // 判断条目类型 (高位为1表示命名条目)
  121.             IFEX #%&iconIdEntry.Id% >= 0x8000,
  122.             {*
  123.                 // 命名条目处理
  124.                 CALC #&&nameOffset=%&iconIdEntry.Id% & 0x7FFF
  125.                 SET-mkfixdummy &nameHeader=(%&pBase%+%&resOffset%+%&nameOffset%)@0;*2
  126.                 SET?short nameHeader=&&nameHeader.Length:0
  127.                
  128.                 // 读取Unicode字符串
  129.                 SET $ &buffer=0
  130.                 CALC #&strAddr=%&pBase% + %&resOffset% + %&nameOffset% + 2
  131.                 CALL $--ret:&buffer --wid %&strAddr%, %&nameHeader.Length%
  132.                
  133.                 ENVI-ret~ %~2=%&buffer%
  134.             }!
  135.             {*
  136.                 // ID条目处理
  137.                 ENVI-ret~ %~2=%&iconIdEntry.Id%
  138.             }
  139.             
  140.             CALL$--qd --bool --ret:&&UnmapViewOfFileRet Kernel32.dll,UnmapViewOfFile,#%&pBase%;
  141.             CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  142.             CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  143.             EXIT _SUB
  144.         }
  145.         CALC #&i=%&i% + 1
  146.     }
  147.     CALL$--qd --bool --ret:&&UnmapViewOfFileRet Kernel32.dll,UnmapViewOfFile,#%&pBase%;
  148.     CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  149.     CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  150.     ENVI-ret %~2=0
  151. _END
复制代码
Zap 发表于 昨天 00:40
红毛樱木 发表于 2025-11-5 23:36
更正后的代码。
C++源码你自己改吧....

是哦 以C:\Windows\explorer.exe为例 第一个是名称ICO_MYCOMPUTER 应该转换为字符
红毛樱木 发表于 前天 23:36
本帖最后由 红毛樱木 于 2025-11-5 23:46 编辑
红毛樱木 发表于 2025-11-5 16:19
这代码应该还有地方有偏移地址计算错的。   ENVI &&IMAGE_DIRECTORY_ENTRY_RESOURCE=0  才可以,实际看源 ...

更正后的代码。
C++源码你自己改吧....



  1. //LOGS * %&CurDir%\log.log
  2. ENVI^ ENVIMODE=1
  3. // PECMD2012 内部本身就是宽字符Unicode。路径\\可以直接写真实路径\,自动转义。
  4. ENVI &exePath=D:\软件\Photoshop\Photoshop.exe
  5. CALL GetFirstIconGroupID "%&exePath%" &iconId
  6. MESS. 第一个图标ID: %&iconId%@

  7. _SUB GetFirstIconGroupID
  8.     ENVI-ret %~2=0
  9.     ENVI &&exePath=%~1
  10.     ENVI &&GENERIC_READ=0x80000000
  11.     ENVI &&FILE_SHARE_READ=0x00000001
  12.     ENVI &&OPEN_EXISTING=3
  13.     ENVI &&INVALID_HANDLE_VALUE=-1
  14.     CALL$--qd --ret:&&hFile Kernel32.dll,CreateFileW,$%&exePath%,#%&GENERIC_READ%,#%&FILE_SHARE_READ%,#0,#%&OPEN_EXISTING%,#0,#0       // C中的NULL就是0,在PECMD中用数值 #0
  15.     IFEX #%&hFile%=%&INVALID_HANDLE_VALUE%,
  16.     {*
  17.         ENVI-ret %~2=0
  18.         EXIT _SUB
  19.     }
  20.     CALL$--qd --ret:&&fileSize Kernel32.dll,GetFileSize,#%&hFile%,#0
  21.     ENVI &&PAGE_READONLY=0x02
  22.     CALL$--qd --ret:&&hMap Kernel32.dll,CreateFileMappingW,#%&hFile%,#0,#%&PAGE_READONLY%,#0,#%&fileSize%,0     //CreateFileMapping 要用实际的 CreateFileMappingW
  23.     ENVI &&FILE_MAP_READ=0x0004
  24.     CALL$--qd --16 --ret:&&pBase Kernel32.dll,MapViewOfFile,#%&hMap%,#%&FILE_MAP_READ%,#0,#0,#0
  25.     //MESS. %&pBase%@&pBase
  26.     IFEX #%&pBase%=0,
  27.     {*
  28.         CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  29.         CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  30.         ENVI-ret %~2=0
  31.         EXIT _SUB
  32.     }
  33.     // PIMAGE_DOS_HEADER 的结构体 IMAGE_DOS_HEADER  64字节
  34.     //SET$# &dos=*64 0
  35.     SET-mkfixdummy &dos=%&pBase%@0;*64
  36.     SET?longs dos=&&dos.e_lfanew:60
  37.     //MESS. %&dos.e_lfanew%@&dos.e_lfanew
  38.     // PIMAGE_NT_HEADERS 的结构体(64位为 IMAGE_NT_HEADERS64 大小 264字节)(32位为 IMAGE_NT_HEADERS32 大小 248字节)
  39.     IFEX #0,    //判断错误,应该直接判断PE文件头是32位还是64位。
  40.     {*
  41.     IFEX #%&bX64%=3,
  42.     {*
  43.         //SET$# &nt=*264 0
  44.         SET-mkfixdummy &nt=(%&pBase%+%&dos.e_lfanew%)@0;*264
  45.     }!  
  46.     {*
  47.         //SET$# &nt=*248 0
  48.         SET-mkfixdummy &nt=(%&pBase%+%&dos.e_lfanew%)@0;*248
  49.     }
  50.     }
  51.     ENVI &&IMAGE_NT_OPTIONAL_HDR32_MAGIC=0x10b      //32位
  52.     ENVI &&IMAGE_NT_OPTIONAL_HDR64_MAGIC=0x20b      //64位
  53.     SET?short (%&pBase%+%&dos.e_lfanew%)=&&nt.OptionalHeader.Magic:24
  54.     //MESS. %&nt.OptionalHeader.Magic%@&nt.OptionalHeader.Magic
  55.     IFEX #%&nt.OptionalHeader.Magic%=%&IMAGE_NT_OPTIONAL_HDR32_MAGIC%,
  56.     {*
  57.         SET-mkfixdummy &nt=(%&pBase%+%&dos.e_lfanew%)@0;*248
  58.     }!  
  59.     {*
  60.         IFEX #%&nt.OptionalHeader.Magic%=%&IMAGE_NT_OPTIONAL_HDR64_MAGIC%,
  61.         {*
  62.             SET-mkfixdummy &nt=(%&pBase%+%&dos.e_lfanew%)@0;*264
  63.         }!  
  64.         {*
  65.             CALL$--qd --bool --ret:&&UnmapViewOfFileRet Kernel32.dll,UnmapViewOfFile,#%&pBase%;
  66.             CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  67.             CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  68.             ENVI-ret %~2=0
  69.             EXIT _SUB
  70.         }
  71.     }
  72.     //GETF &nt,0#*,&&nt_Hex
  73.     //MESS. %&nt_Hex%@&nt_Hex
  74.     SET?long nt=&&nt.Signature:0
  75.     //MESS. %&nt.Signature%@&nt.Signature
  76.     ENVI &&IMAGE_NT_SIGNATURE=0x00004550  // PE00
  77.     IFEX #%&nt.Signature%<>%&IMAGE_NT_SIGNATURE%,
  78.     {*
  79.         CALL$--qd --bool --ret:&&UnmapViewOfFileRet Kernel32.dll,UnmapViewOfFile,#%&pBase%;
  80.         CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  81.         CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  82.         ENVI-ret %~2=0
  83.         EXIT _SUB
  84.     }
  85.    
  86.     // 定位资源目录
  87.     // auto& resDir = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
  88.     ENVI &&IMAGE_DIRECTORY_ENTRY_RESOURCE=2   // Resource Directory
  89.     //ENVI &&IMAGE_DIRECTORY_ENTRY_RESOURCE=0     // 测试
  90.     IFEX #0,
  91.     {*
  92.     IFEX #%&bX64%=3,
  93.     {*
  94.         SET-mkfixdummy &resDir=&nt@(4+20+112+(8*%&IMAGE_DIRECTORY_ENTRY_RESOURCE%));*8
  95.     }!  
  96.     {*
  97.         SET-mkfixdummy &resDir=&nt@(4+20+96+(8*%&IMAGE_DIRECTORY_ENTRY_RESOURCE%));*8
  98.     }
  99.     }
  100.     IFEX #%&nt.OptionalHeader.Magic%=%&IMAGE_NT_OPTIONAL_HDR32_MAGIC%,
  101.     {*
  102.         SET-mkfixdummy &resDir=&nt@(4+20+96+(8*%&IMAGE_DIRECTORY_ENTRY_RESOURCE%));*8
  103.     }!  
  104.     {*
  105.         IFEX #%&nt.OptionalHeader.Magic%=%&IMAGE_NT_OPTIONAL_HDR64_MAGIC%,
  106.         {*
  107.             SET-mkfixdummy &resDir=&nt@(4+20+112+(8*%&IMAGE_DIRECTORY_ENTRY_RESOURCE%));*8
  108.         }!  
  109.         {*
  110.             CALL$--qd --bool --ret:&&UnmapViewOfFileRet Kernel32.dll,UnmapViewOfFile,#%&pBase%;
  111.             CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  112.             CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  113.             ENVI-ret %~2=0
  114.             EXIT _SUB
  115.         }
  116.     }
  117.     //GETF &resDir,0#*,&&resDir_Hex
  118.     //MESS. %&resDir_Hex%@&resDir_Hex
  119.     SET?long resDir=&&resDir.VirtualAddress:0
  120.     //MESS. %&resDir.VirtualAddress%@&resDir.VirtualAddress
  121.    
  122.     // 定位资源节(.rsrc)
  123.     ENVI &&i=0
  124.     SET?shorts nt=&&nt.FileHeader.NumberOfSections:(4+2)    //WORD 2 字节,用short和wchar都可以
  125.     //MESS. %&nt.FileHeader.NumberOfSections%@&nt.FileHeader.NumberOfSections
  126.     SET?shorts nt=&&nt.FileHeader.SizeOfOptionalHeader:(4+2+2+4+4+4)
  127.     //MESS. %&nt.FileHeader.SizeOfOptionalHeader%@&nt.FileHeader.SizeOfOptionalHeader
  128.     //SET-mkfixdummy &section=&nt
  129.    
  130.     LOOP #%&i%<%&nt.FileHeader.NumberOfSections%,
  131.     {*
  132.         //#define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER) ((ULONG_PTR)(ntheader) + FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + ((ntheader))->FileHeader.SizeOfOptionalHeader ))
  133.         SET-mkfixdummy &section=(%&pBase%+%&dos.e_lfanew%+(4+20+%&nt.FileHeader.SizeOfOptionalHeader%))@(40*%&i%);*40        // 相当于 section++
  134.         //GETF &section,0#40,&&section_Hex
  135.         //MESS. %&section_Hex%@&section_Hex
  136.         SET?long section=&&section.VirtualAddress:12
  137.         //MESS. &section.VirtualAddress:%&section.VirtualAddress%@%&i%
  138.         SET?long section=&&section.Misc.VirtualSize:8
  139.         //MESS. IFEX #[ ( %&resDir.VirtualAddress% >= %&section.VirtualAddress% ) & ( %&resDir.VirtualAddress% < ( %&section.VirtualAddress% + %&section.Misc.VirtualSize% ) ) ],@%&i%
  140.         //IFEX #[ ( %&resDir.VirtualAddress% >= %&section.VirtualAddress% ) & ( %&resDir.VirtualAddress% < ( %&section.VirtualAddress% + %&section.Misc.VirtualSize% ) ) ],     // IFEX 存在BUG,不能这样嵌套使用,先算出来吧。
  141.         IFEX #%&resDir.VirtualAddress% >= %&section.VirtualAddress%,
  142.         {*
  143.             CALC &&Fix=%&section.VirtualAddress% + %&section.Misc.VirtualSize%
  144.             IFEX #%&resDir.VirtualAddress% < %&Fix%,
  145.             {*
  146.                 EXIT LOOP
  147.             }
  148.         }
  149.         CALC #&i=%&i% + 1
  150.     }
  151.     // 计算资源目录在文件中的实际偏移
  152.     SET?long section=&&section.PointerToRawData:20
  153.     CALC #&&resOffset=%&resDir.VirtualAddress% - %&section.VirtualAddress% + %&section.PointerToRawData%
  154.     //MESS. %&resOffset%<&i:%&i%><CALC #&&resOffset=%&resDir.VirtualAddress% - %&section.VirtualAddress% + %&section.PointerToRawData%>@&resOffset
  155.     SET-mkfixdummy &rootDir=(%&pBase%+%&resOffset%)@0;*16
  156.     SET?short rootDir=&&rootDir.NumberOfIdEntries:(4+4+2+2+2)
  157.     //MESS. %&rootDir.NumberOfIdEntries%@&rootDir.NumberOfIdEntries
  158.    
  159.     // 遍历资源类型,找到 RT_GROUP_ICON(ID=14)
  160.     //SET-mkfixdummy &typeEntry=(%&pBase%+%&resOffset%)@16;*8
  161.     //GETF &typeEntry,0#8,&&typeEntry_Hex
  162.     //MESS. %&typeEntry_Hex%@&typeEntry_Hex
  163.    
  164.     ENVI &&i=0
  165.     LOOP #%&i%<%&rootDir.NumberOfIdEntries%,
  166.     {*
  167.         SET-mkfixdummy &typeEntry=(%&pBase%+%&resOffset%)@(16+(8*%&i%));*8
  168.         SET?short typeEntry=&&typeEntry.Id:0
  169.         //MESS. %&typeEntry.Id%@%&i%
  170.         IFEX #%&typeEntry.Id%=14,       // RT_GROUP_ICON = 14
  171.         {*
  172.             // 获取第一个图标ID(进入ID目录的第一个条目)
  173.             SET?long typeEntry=&&typeEntry.OffsetToDirectory:4
  174.             CALC #&typeEntry.OffsetToDirectory=%&typeEntry.OffsetToDirectory% & 0x7FFFFFFF
  175.             SET-mkfixdummy &iconDir=(%&pBase%+%&resOffset%)@%&typeEntry.OffsetToDirectory%;*16
  176.             SET-mkfixdummy &iconIdEntry=(%&pBase%+%&resOffset%)@(%&typeEntry.OffsetToDirectory%+16);*8
  177.             SET?short iconIdEntry=&&iconIdEntry.Id:0
  178.             CALC &&firstIconId=%&iconIdEntry.Id%        // 不知道源码这里为什么用DWORD计算WORD
  179.             //MESS. %&firstIconId%@
  180.             
  181.             CALL$--qd --bool --ret:&&UnmapViewOfFileRet Kernel32.dll,UnmapViewOfFile,#%&pBase%;
  182.             CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  183.             CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  184.             ENVI-ret~ %~2=&firstIconId
  185.             EXIT _SUB
  186.         }
  187.         CALC #&i=%&i% + 1
  188.     }
  189.     CALL$--qd --bool --ret:&&UnmapViewOfFileRet Kernel32.dll,UnmapViewOfFile,#%&pBase%;
  190.     CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  191.     CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  192.     ENVI-ret %~2=0
  193. _END


  194. EXIT FILE

  195. typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
  196.     union {
  197.         struct {
  198.             DWORD NameOffset:31;
  199.             DWORD NameIsString:1;
  200.         } DUMMYSTRUCTNAME;
  201.         DWORD   Name;
  202.         WORD    Id;
  203.     } DUMMYUNIONNAME;
  204.     union {
  205.         DWORD   OffsetToData;
  206.         struct {
  207.             DWORD   OffsetToDirectory:31;
  208.             DWORD   DataIsDirectory:1;
  209.         } DUMMYSTRUCTNAME2;
  210.     } DUMMYUNIONNAME2;
  211. } IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;     //8b

  212. typedef struct _IMAGE_RESOURCE_DIRECTORY {
  213.     DWORD   Characteristics;
  214.     DWORD   TimeDateStamp;
  215.     WORD    MajorVersion;
  216.     WORD    MinorVersion;
  217.     WORD    NumberOfNamedEntries;
  218.     WORD    NumberOfIdEntries;
  219. //  IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[];
  220. } IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;     /16b

  221. typedef struct _IMAGE_SECTION_HEADER {
  222.     BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];
  223.     union {
  224.             DWORD   PhysicalAddress;
  225.             DWORD   VirtualSize;
  226.     } Misc;
  227.     DWORD   VirtualAddress;
  228.     DWORD   SizeOfRawData;
  229.     DWORD   PointerToRawData;
  230.     DWORD   PointerToRelocations;
  231.     DWORD   PointerToLinenumbers;
  232.     WORD    NumberOfRelocations;
  233.     WORD    NumberOfLinenumbers;
  234.     DWORD   Characteristics;
  235. } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;     //40b

  236. typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
  237.     WORD   e_magic;                     // Magic number
  238.     WORD   e_cblp;                      // Bytes on last page of file
  239.     WORD   e_cp;                        // Pages in file
  240.     WORD   e_crlc;                      // Relocations
  241.     WORD   e_cparhdr;                   // Size of header in paragraphs
  242.     WORD   e_minalloc;                  // Minimum extra paragraphs needed
  243.     WORD   e_maxalloc;                  // Maximum extra paragraphs needed
  244.     WORD   e_ss;                        // Initial (relative) SS value
  245.     WORD   e_sp;                        // Initial SP value
  246.     WORD   e_csum;                      // Checksum
  247.     WORD   e_ip;                        // Initial IP value
  248.     WORD   e_cs;                        // Initial (relative) CS value
  249.     WORD   e_lfarlc;                    // File address of relocation table
  250.     WORD   e_ovno;                      // Overlay number
  251.     WORD   e_res[4];                    // Reserved words
  252.     WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
  253.     WORD   e_oeminfo;                   // OEM information; e_oemid specific
  254.     WORD   e_res2[10];                  // Reserved words
  255.     LONG   e_lfanew;                    // File address of new exe header
  256.   } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;       //64b

  257. typedef struct _IMAGE_FILE_HEADER {
  258.     WORD    Machine;
  259.     WORD    NumberOfSections;
  260.     DWORD   TimeDateStamp;
  261.     DWORD   PointerToSymbolTable;
  262.     DWORD   NumberOfSymbols;
  263.     WORD    SizeOfOptionalHeader;
  264.     WORD    Characteristics;
  265. } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;       //20b

  266. typedef struct _IMAGE_DATA_DIRECTORY {
  267.     DWORD   VirtualAddress;
  268.     DWORD   Size;
  269. } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;     //8b

  270. typedef struct _IMAGE_OPTIONAL_HEADER {
  271.     //
  272.     // Standard fields.
  273.     //

  274.     WORD    Magic;
  275.     BYTE    MajorLinkerVersion;
  276.     BYTE    MinorLinkerVersion;
  277.     DWORD   SizeOfCode;
  278.     DWORD   SizeOfInitializedData;
  279.     DWORD   SizeOfUninitializedData;
  280.     DWORD   AddressOfEntryPoint;
  281.     DWORD   BaseOfCode;
  282.     DWORD   BaseOfData;

  283.     //
  284.     // NT additional fields.
  285.     //

  286.     DWORD   ImageBase;
  287.     DWORD   SectionAlignment;
  288.     DWORD   FileAlignment;
  289.     WORD    MajorOperatingSystemVersion;
  290.     WORD    MinorOperatingSystemVersion;
  291.     WORD    MajorImageVersion;
  292.     WORD    MinorImageVersion;
  293.     WORD    MajorSubsystemVersion;
  294.     WORD    MinorSubsystemVersion;
  295.     DWORD   Win32VersionValue;
  296.     DWORD   SizeOfImage;
  297.     DWORD   SizeOfHeaders;
  298.     DWORD   CheckSum;
  299.     WORD    Subsystem;
  300.     WORD    DllCharacteristics;
  301.     DWORD   SizeOfStackReserve;
  302.     DWORD   SizeOfStackCommit;
  303.     DWORD   SizeOfHeapReserve;
  304.     DWORD   SizeOfHeapCommit;
  305.     DWORD   LoaderFlags;
  306.     DWORD   NumberOfRvaAndSizes;
  307.     IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];       //偏移地址  96b
  308. } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

  309. typedef struct _IMAGE_OPTIONAL_HEADER64 {
  310.     WORD        Magic;
  311.     BYTE        MajorLinkerVersion;
  312.     BYTE        MinorLinkerVersion;
  313.     DWORD       SizeOfCode;
  314.     DWORD       SizeOfInitializedData;
  315.     DWORD       SizeOfUninitializedData;
  316.     DWORD       AddressOfEntryPoint;
  317.     DWORD       BaseOfCode;
  318.     ULONGLONG   ImageBase;
  319.     DWORD       SectionAlignment;
  320.     DWORD       FileAlignment;
  321.     WORD        MajorOperatingSystemVersion;
  322.     WORD        MinorOperatingSystemVersion;
  323.     WORD        MajorImageVersion;
  324.     WORD        MinorImageVersion;
  325.     WORD        MajorSubsystemVersion;
  326.     WORD        MinorSubsystemVersion;
  327.     DWORD       Win32VersionValue;
  328.     DWORD       SizeOfImage;
  329.     DWORD       SizeOfHeaders;
  330.     DWORD       CheckSum;
  331.     WORD        Subsystem;
  332.     WORD        DllCharacteristics;
  333.     ULONGLONG   SizeOfStackReserve;
  334.     ULONGLONG   SizeOfStackCommit;
  335.     ULONGLONG   SizeOfHeapReserve;
  336.     ULONGLONG   SizeOfHeapCommit;
  337.     DWORD       LoaderFlags;
  338.     DWORD       NumberOfRvaAndSizes;
  339.     IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];       //偏移地址  112b
  340. } IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;

  341. typedef struct _IMAGE_NT_HEADERS64 {
  342.     DWORD Signature;
  343.     IMAGE_FILE_HEADER FileHeader;
  344.     IMAGE_OPTIONAL_HEADER64 OptionalHeader;
  345. } IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;

  346. typedef struct _IMAGE_NT_HEADERS {
  347.     DWORD Signature;
  348.     IMAGE_FILE_HEADER FileHeader;
  349.     IMAGE_OPTIONAL_HEADER32 OptionalHeader;
  350. } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

  351. #include <windows.h>
  352. #include <stdio.h>

  353. DWORD GetFirstIconGroupID(LPCWSTR exePath) {
  354.     HANDLE hFile = CreateFileW(exePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
  355.     if (hFile == INVALID_HANDLE_VALUE) return 0;

  356.     DWORD fileSize = GetFileSize(hFile, NULL);
  357.     HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, fileSize, NULL);
  358.     LPVOID pBase = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
  359.     if (!pBase) { CloseHandle(hMap); CloseHandle(hFile); return 0; }

  360.     PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)pBase;
  361.     PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((BYTE*)pBase + dos->e_lfanew);
  362.     if (nt->Signature != IMAGE_NT_SIGNATURE) { UnmapViewOfFile(pBase); CloseHandle(hMap); CloseHandle(hFile); return 0; }

  363.     // 定位资源目录
  364.     auto& resDir = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
  365.     if (resDir.VirtualAddress == 0) { UnmapViewOfFile(pBase); CloseHandle(hMap); CloseHandle(hFile); return 0; }

  366.     // 定位资源节(.rsrc)
  367.     PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(nt);
  368.     for (int i = 0; i < nt->FileHeader.NumberOfSections; i++, section++) {
  369.         if (resDir.VirtualAddress >= section->VirtualAddress &&
  370.             resDir.VirtualAddress < section->VirtualAddress + section->Misc.VirtualSize) break;
  371.     }

  372.     // 计算资源目录在文件中的实际偏移
  373.     DWORD resOffset = resDir.VirtualAddress - section->VirtualAddress + section->PointerToRawData;
  374.     PIMAGE_RESOURCE_DIRECTORY rootDir = (PIMAGE_RESOURCE_DIRECTORY)((BYTE*)pBase + resOffset);

  375.     // 遍历资源类型,找到 RT_GROUP_ICON(ID=14)
  376.     PIMAGE_RESOURCE_DIRECTORY_ENTRY typeEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(rootDir + 1);
  377.     for (DWORD i = 0; i < rootDir->NumberOfIdEntries; i++, typeEntry++) {
  378.         if (typeEntry->Id == 14) { // RT_GROUP_ICON = 14
  379.             // 获取第一个图标ID(进入ID目录的第一个条目)
  380.             PIMAGE_RESOURCE_DIRECTORY iconDir = (PIMAGE_RESOURCE_DIRECTORY)((BYTE*)rootDir + typeEntry->OffsetToDirectory);
  381.             PIMAGE_RESOURCE_DIRECTORY_ENTRY iconIdEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(iconDir + 1);
  382.             DWORD firstIconId = iconIdEntry->Id;

  383.             UnmapViewOfFile(pBase);
  384.             CloseHandle(hMap);
  385.             CloseHandle(hFile);
  386.             return firstIconId;
  387.         }
  388.     }

  389.     UnmapViewOfFile(pBase);
  390.     CloseHandle(hMap);
  391.     CloseHandle(hFile);
  392.     return 0;
  393. }

  394. // 调用示例:获取 Photoshop.exe 的第一个图标ID
  395. int main() {
  396.     LPCWSTR exePath = L"D:\\软件\\Photoshop\\Photoshop.exe";
  397.     DWORD iconId = GetFirstIconGroupID(exePath);
  398.     printf("第一个图标ID: %u\n", iconId); // 输出:1000 或 1 等
  399.     return 0;
  400. }

复制代码


点评

Zap
换个程序就不行了  详情 回复 发表于 昨天 11:00
Zap
搞不定  详情 回复 发表于 昨天 09:45
Zap
是哦 以C:\Windows\explorer.exe为例 第一个是名称ICO_MYCOMPUTER 应该转换为字符  详情 回复 发表于 昨天 00:40
527104427 发表于 前天 17:50
红毛樱木 发表于 2025-11-5 16:14
这玩意写的太累人了。坐了一天,快点给钱吧

牛逼!目测这代码值一千块钱
红毛樱木 发表于 前天 16:19
红毛樱木 发表于 2025-11-5 16:14
这玩意写的太累人了。坐了一天,快点给钱吧

这代码应该还有地方有偏移地址计算错的。   ENVI &&IMAGE_DIRECTORY_ENTRY_RESOURCE=0  才可以,实际看源码是 ENVI &&IMAGE_DIRECTORY_ENTRY_RESOURCE=2。  你看看自己能不能解决吧,解决不了  回头我再看看。

点评

更正后的代码。 C++源码你自己改吧....  详情 回复 发表于 前天 23:36
红毛樱木 发表于 前天 16:14
本帖最后由 红毛樱木 于 2025-11-5 16:16 编辑
Zap 发表于 2025-11-3 23:07
获取程序图标组中第一个图标的ID
    定位 RT_GROUP_ICON(类型ID=14)的资源目录,跳过无关资源类型。
  ...


  1. //LOGS * %&CurDir%\log.log
  2. ENVI^ ENVIMODE=1
  3. // PECMD2012 内部本身就是宽字符Unicode。路径\\可以直接写真实路径\,自动转义。
  4. ENVI &exePath=D:\软件\Photoshop\Photoshop.exe
  5. CALL GetFirstIconGroupID "%&exePath%" &iconId
  6. MESS. 第一个图标ID: %&iconId%@

  7. _SUB GetFirstIconGroupID
  8.     ENVI &&exePath=%~1
  9.     ENVI &&GENERIC_READ=0x80000000
  10.     ENVI &&FILE_SHARE_READ=0x00000001
  11.     ENVI &&OPEN_EXISTING=3
  12.     ENVI &&INVALID_HANDLE_VALUE=-1
  13.     CALL$--qd --ret:&&hFile Kernel32.dll,CreateFileW,$%&exePath%,#%&GENERIC_READ%,#%&FILE_SHARE_READ%,#0,#%&OPEN_EXISTING%,#0,#0       // C中的NULL就是0,在PECMD中用数值 #0
  14.     IFEX #%&hFile%=%&INVALID_HANDLE_VALUE%,
  15.     {*
  16.         EXIT= 0
  17.         EXIT _SUB
  18.     }
  19.     CALL$--qd --ret:&&fileSize Kernel32.dll,GetFileSize,#%&hFile%,#0
  20.     ENVI &&PAGE_READONLY=0x02
  21.     CALL$--qd --ret:&&hMap Kernel32.dll,CreateFileMappingW,#%&hFile%,#0,#%&PAGE_READONLY%,#0,#%&fileSize%,0     //CreateFileMapping 要用实际的 CreateFileMappingW
  22.     ENVI &&FILE_MAP_READ=0x0004
  23.     CALL$--qd --16 --ret:&&pBase Kernel32.dll,MapViewOfFile,#%&hMap%,#%&FILE_MAP_READ%,#0,#0,#0
  24.     //MESS. %&pBase%@&pBase
  25.     IFEX #%&pBase%=0,
  26.     {*
  27.         CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  28.         CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  29.         ENVI-ret %~2=0
  30.         EXIT _SUB
  31.     }
  32.     // PIMAGE_DOS_HEADER 的结构体 IMAGE_DOS_HEADER  64字节
  33.     //SET$# &dos=*64 0
  34.     SET-mkfixdummy &dos=%&pBase%@0;*64
  35.     SET?longs dos=&&dos.e_lfanew:60
  36.     //MESS. %&dos.e_lfanew%@&dos.e_lfanew
  37.     // PIMAGE_NT_HEADERS 的结构体(64位为 IMAGE_NT_HEADERS64 大小 264字节)(32位为 IMAGE_NT_HEADERS32 大小 248字节)
  38.     IFEX #%&bX64%=3,
  39.     {*
  40.         //SET$# &nt=*264 0
  41.         SET-mkfixdummy &nt=(%&pBase%+%&dos.e_lfanew%)@0;*264
  42.     }!  
  43.     {*
  44.         //SET$# &nt=*248 0
  45.         SET-mkfixdummy &nt=(%&pBase%+%&dos.e_lfanew%)@0;*248
  46.     }
  47.     //GETF &nt,0#*,&&nt_Hex
  48.     //MESS. %&nt_Hex%@&nt_Hex
  49.     SET?long nt=&&nt.Signature:0
  50.     //MESS. %&nt.Signature%@&nt.Signature
  51.     ENVI &&IMAGE_NT_SIGNATURE=0x00004550  // PE00
  52.     IFEX #%&nt.Signature%<>%&IMAGE_NT_SIGNATURE%,
  53.     {*
  54.         CALL$--qd --bool --ret:&&UnmapViewOfFileRet Kernel32.dll,UnmapViewOfFile,#%&pBase%;
  55.         CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  56.         CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  57.         ENVI-ret %~2=0
  58.         EXIT _SUB
  59.     }
  60.    
  61.     // 定位资源目录
  62.     // auto& resDir = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
  63.     //ENVI &&IMAGE_DIRECTORY_ENTRY_RESOURCE=2   // Resource Directory
  64.     ENVI &&IMAGE_DIRECTORY_ENTRY_RESOURCE=0     // 测试
  65.     IFEX #%&bX64%=3,
  66.     {*
  67.         SET-mkfixdummy &resDir=&nt@(4+20+112+(8*%&IMAGE_DIRECTORY_ENTRY_RESOURCE%));*8
  68.     }!  
  69.     {*
  70.         SET-mkfixdummy &resDir=&nt@(4+20+96+(8*%&IMAGE_DIRECTORY_ENTRY_RESOURCE%));*8
  71.     }
  72.     //GETF &resDir,0#*,&&resDir_Hex
  73.     //MESS. %&resDir_Hex%@&resDir_Hex
  74.     SET?long resDir=&&resDir.VirtualAddress:0
  75.     //MESS. %&resDir.VirtualAddress%@&resDir.VirtualAddress
  76.    
  77.     // 定位资源节(.rsrc)
  78.     ENVI &&i=0
  79.     SET?shorts nt=&&nt.FileHeader.NumberOfSections:(4+2)    //WORD 2 字节,用short和wchar都可以
  80.     //MESS. %&nt.FileHeader.NumberOfSections%@&nt.FileHeader.NumberOfSections
  81.     SET?shorts nt=&&nt.FileHeader.SizeOfOptionalHeader:(4+2+2+4+4+4)
  82.     //MESS. %&nt.FileHeader.SizeOfOptionalHeader%@&nt.FileHeader.SizeOfOptionalHeader
  83.     //SET-mkfixdummy &section=&nt
  84.    
  85.     LOOP #%&i%<%&nt.FileHeader.NumberOfSections%,
  86.     {*
  87.         //#define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER) ((ULONG_PTR)(ntheader) + FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + ((ntheader))->FileHeader.SizeOfOptionalHeader ))
  88.         SET-mkfixdummy &section=(%&pBase%+%&dos.e_lfanew%+(4+20+%&nt.FileHeader.SizeOfOptionalHeader%))@(40*%&i%);*40        // 相当于 section++
  89.         //GETF &section,0#40,&&section_Hex
  90.         //MESS. %&section_Hex%@&section_Hex
  91.         SET?long section=&&section.VirtualAddress:12
  92.         //MESS. &section.VirtualAddress:%&section.VirtualAddress%@%&i%
  93.         SET?long section=&&section.Misc.VirtualSize:8
  94.         //MESS. IFEX #[ ( %&resDir.VirtualAddress% >= %&section.VirtualAddress% ) & ( %&resDir.VirtualAddress% < ( %&section.VirtualAddress% + %&section.Misc.VirtualSize% ) ) ],@%&i%
  95.         //IFEX #[ ( %&resDir.VirtualAddress% >= %&section.VirtualAddress% ) & ( %&resDir.VirtualAddress% < ( %&section.VirtualAddress% + %&section.Misc.VirtualSize% ) ) ],     // IFEX 存在BUG,不能这样嵌套使用,先算出来吧。
  96.         IFEX #%&resDir.VirtualAddress% >= %&section.VirtualAddress%,
  97.         {*
  98.             CALC &&Fix=%&section.VirtualAddress% + %&section.Misc.VirtualSize%
  99.             IFEX #%&resDir.VirtualAddress% < %&Fix%,
  100.             {*
  101.                 EXIT LOOP
  102.             }
  103.         }
  104.         CALC #&i=%&i% + 1
  105.     }
  106.     // 计算资源目录在文件中的实际偏移
  107.     SET?long section=&&section.PointerToRawData:20
  108.     CALC #&&resOffset=%&resDir.VirtualAddress% - %&section.VirtualAddress% + %&section.PointerToRawData%
  109.     //MESS. %&resOffset%<&i:%&i%><CALC #&&resOffset=%&resDir.VirtualAddress% - %&section.VirtualAddress% + %&section.PointerToRawData%>@&resOffset
  110.     SET-mkfixdummy &rootDir=(%&pBase%+%&resOffset%)@0;*16
  111.     SET?short rootDir=&&rootDir.NumberOfIdEntries:(4+4+2+2+2)
  112.     //MESS. %&rootDir.NumberOfIdEntries%@&rootDir.NumberOfIdEntries
  113.    
  114.     // 遍历资源类型,找到 RT_GROUP_ICON(ID=14)
  115.     //SET-mkfixdummy &typeEntry=(%&pBase%+%&resOffset%)@16;*8
  116.     //GETF &typeEntry,0#8,&&typeEntry_Hex
  117.     //MESS. %&typeEntry_Hex%@&typeEntry_Hex
  118.    
  119.     ENVI &&i=0
  120.     LOOP #%&i%<%&rootDir.NumberOfIdEntries%,
  121.     {*
  122.         SET-mkfixdummy &typeEntry=(%&pBase%+%&resOffset%)@(16+(8*%&i%));*8
  123.         SET?short typeEntry=&&typeEntry.Id:0
  124.         //MESS. %&typeEntry.Id%@%&i%
  125.         IFEX #%&typeEntry.Id%=14,       // RT_GROUP_ICON = 14
  126.         {*
  127.             // 获取第一个图标ID(进入ID目录的第一个条目)
  128.             SET?long typeEntry=&&typeEntry.OffsetToDirectory:4
  129.             CALC #&typeEntry.OffsetToDirectory=%&typeEntry.OffsetToDirectory% & 0x7FFFFFFF
  130.             SET-mkfixdummy &iconDir=(%&pBase%+%&resOffset%)@%&typeEntry.OffsetToDirectory%;*16
  131.             SET-mkfixdummy &iconIdEntry=(%&pBase%+%&resOffset%)@(%&typeEntry.OffsetToDirectory%+16);*8
  132.             SET?short iconIdEntry=&&iconIdEntry.Id:0
  133.             CALC &&firstIconId=%&iconIdEntry.Id%        // 不知道源码这里为什么用DWORD计算WORD
  134.             //MESS. %&firstIconId%@
  135.             
  136.             CALL$--qd --bool --ret:&&UnmapViewOfFileRet Kernel32.dll,UnmapViewOfFile,#%&pBase%;
  137.             CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  138.             CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  139.             ENVI-ret~ %~2=&firstIconId
  140.             EXIT _SUB
  141.         }
  142.         CALC #&i=%&i% + 1
  143.     }
  144.     CALL$--qd --bool --ret:&&UnmapViewOfFileRet Kernel32.dll,UnmapViewOfFile,#%&pBase%;
  145.     CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hMap%
  146.     CALL$--qd --bool --ret:&&CloseHandleRet Kernel32.dll,CloseHandle,#%&hFile%
  147.     ENVI-ret %~2=0
  148. _END


  149. EXIT FILE

  150. typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
  151.     union {
  152.         struct {
  153.             DWORD NameOffset:31;
  154.             DWORD NameIsString:1;
  155.         } DUMMYSTRUCTNAME;
  156.         DWORD   Name;
  157.         WORD    Id;
  158.     } DUMMYUNIONNAME;
  159.     union {
  160.         DWORD   OffsetToData;
  161.         struct {
  162.             DWORD   OffsetToDirectory:31;
  163.             DWORD   DataIsDirectory:1;
  164.         } DUMMYSTRUCTNAME2;
  165.     } DUMMYUNIONNAME2;
  166. } IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;     //8b

  167. typedef struct _IMAGE_RESOURCE_DIRECTORY {
  168.     DWORD   Characteristics;
  169.     DWORD   TimeDateStamp;
  170.     WORD    MajorVersion;
  171.     WORD    MinorVersion;
  172.     WORD    NumberOfNamedEntries;
  173.     WORD    NumberOfIdEntries;
  174. //  IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[];
  175. } IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;     /16b

  176. typedef struct _IMAGE_SECTION_HEADER {
  177.     BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];
  178.     union {
  179.             DWORD   PhysicalAddress;
  180.             DWORD   VirtualSize;
  181.     } Misc;
  182.     DWORD   VirtualAddress;
  183.     DWORD   SizeOfRawData;
  184.     DWORD   PointerToRawData;
  185.     DWORD   PointerToRelocations;
  186.     DWORD   PointerToLinenumbers;
  187.     WORD    NumberOfRelocations;
  188.     WORD    NumberOfLinenumbers;
  189.     DWORD   Characteristics;
  190. } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;     //40b

  191. typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
  192.     WORD   e_magic;                     // Magic number
  193.     WORD   e_cblp;                      // Bytes on last page of file
  194.     WORD   e_cp;                        // Pages in file
  195.     WORD   e_crlc;                      // Relocations
  196.     WORD   e_cparhdr;                   // Size of header in paragraphs
  197.     WORD   e_minalloc;                  // Minimum extra paragraphs needed
  198.     WORD   e_maxalloc;                  // Maximum extra paragraphs needed
  199.     WORD   e_ss;                        // Initial (relative) SS value
  200.     WORD   e_sp;                        // Initial SP value
  201.     WORD   e_csum;                      // Checksum
  202.     WORD   e_ip;                        // Initial IP value
  203.     WORD   e_cs;                        // Initial (relative) CS value
  204.     WORD   e_lfarlc;                    // File address of relocation table
  205.     WORD   e_ovno;                      // Overlay number
  206.     WORD   e_res[4];                    // Reserved words
  207.     WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
  208.     WORD   e_oeminfo;                   // OEM information; e_oemid specific
  209.     WORD   e_res2[10];                  // Reserved words
  210.     LONG   e_lfanew;                    // File address of new exe header
  211.   } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;       //64b

  212. typedef struct _IMAGE_FILE_HEADER {
  213.     WORD    Machine;
  214.     WORD    NumberOfSections;
  215.     DWORD   TimeDateStamp;
  216.     DWORD   PointerToSymbolTable;
  217.     DWORD   NumberOfSymbols;
  218.     WORD    SizeOfOptionalHeader;
  219.     WORD    Characteristics;
  220. } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;       //20b

  221. typedef struct _IMAGE_DATA_DIRECTORY {
  222.     DWORD   VirtualAddress;
  223.     DWORD   Size;
  224. } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;     //8b

  225. typedef struct _IMAGE_OPTIONAL_HEADER {
  226.     //
  227.     // Standard fields.
  228.     //

  229.     WORD    Magic;
  230.     BYTE    MajorLinkerVersion;
  231.     BYTE    MinorLinkerVersion;
  232.     DWORD   SizeOfCode;
  233.     DWORD   SizeOfInitializedData;
  234.     DWORD   SizeOfUninitializedData;
  235.     DWORD   AddressOfEntryPoint;
  236.     DWORD   BaseOfCode;
  237.     DWORD   BaseOfData;

  238.     //
  239.     // NT additional fields.
  240.     //

  241.     DWORD   ImageBase;
  242.     DWORD   SectionAlignment;
  243.     DWORD   FileAlignment;
  244.     WORD    MajorOperatingSystemVersion;
  245.     WORD    MinorOperatingSystemVersion;
  246.     WORD    MajorImageVersion;
  247.     WORD    MinorImageVersion;
  248.     WORD    MajorSubsystemVersion;
  249.     WORD    MinorSubsystemVersion;
  250.     DWORD   Win32VersionValue;
  251.     DWORD   SizeOfImage;
  252.     DWORD   SizeOfHeaders;
  253.     DWORD   CheckSum;
  254.     WORD    Subsystem;
  255.     WORD    DllCharacteristics;
  256.     DWORD   SizeOfStackReserve;
  257.     DWORD   SizeOfStackCommit;
  258.     DWORD   SizeOfHeapReserve;
  259.     DWORD   SizeOfHeapCommit;
  260.     DWORD   LoaderFlags;
  261.     DWORD   NumberOfRvaAndSizes;
  262.     IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];       //偏移地址  96b
  263. } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

  264. typedef struct _IMAGE_OPTIONAL_HEADER64 {
  265.     WORD        Magic;
  266.     BYTE        MajorLinkerVersion;
  267.     BYTE        MinorLinkerVersion;
  268.     DWORD       SizeOfCode;
  269.     DWORD       SizeOfInitializedData;
  270.     DWORD       SizeOfUninitializedData;
  271.     DWORD       AddressOfEntryPoint;
  272.     DWORD       BaseOfCode;
  273.     ULONGLONG   ImageBase;
  274.     DWORD       SectionAlignment;
  275.     DWORD       FileAlignment;
  276.     WORD        MajorOperatingSystemVersion;
  277.     WORD        MinorOperatingSystemVersion;
  278.     WORD        MajorImageVersion;
  279.     WORD        MinorImageVersion;
  280.     WORD        MajorSubsystemVersion;
  281.     WORD        MinorSubsystemVersion;
  282.     DWORD       Win32VersionValue;
  283.     DWORD       SizeOfImage;
  284.     DWORD       SizeOfHeaders;
  285.     DWORD       CheckSum;
  286.     WORD        Subsystem;
  287.     WORD        DllCharacteristics;
  288.     ULONGLONG   SizeOfStackReserve;
  289.     ULONGLONG   SizeOfStackCommit;
  290.     ULONGLONG   SizeOfHeapReserve;
  291.     ULONGLONG   SizeOfHeapCommit;
  292.     DWORD       LoaderFlags;
  293.     DWORD       NumberOfRvaAndSizes;
  294.     IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];       //偏移地址  112b
  295. } IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;

  296. typedef struct _IMAGE_NT_HEADERS64 {
  297.     DWORD Signature;
  298.     IMAGE_FILE_HEADER FileHeader;
  299.     IMAGE_OPTIONAL_HEADER64 OptionalHeader;
  300. } IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;

  301. typedef struct _IMAGE_NT_HEADERS {
  302.     DWORD Signature;
  303.     IMAGE_FILE_HEADER FileHeader;
  304.     IMAGE_OPTIONAL_HEADER32 OptionalHeader;
  305. } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

  306. #include <windows.h>
  307. #include <stdio.h>

  308. DWORD GetFirstIconGroupID(LPCWSTR exePath) {
  309.     HANDLE hFile = CreateFileW(exePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
  310.     if (hFile == INVALID_HANDLE_VALUE) return 0;

  311.     DWORD fileSize = GetFileSize(hFile, NULL);
  312.     HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, fileSize, NULL);
  313.     LPVOID pBase = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
  314.     if (!pBase) { CloseHandle(hMap); CloseHandle(hFile); return 0; }

  315.     PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)pBase;
  316.     PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((BYTE*)pBase + dos->e_lfanew);
  317.     if (nt->Signature != IMAGE_NT_SIGNATURE) { UnmapViewOfFile(pBase); CloseHandle(hMap); CloseHandle(hFile); return 0; }

  318.     // 定位资源目录
  319.     auto& resDir = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
  320.     if (resDir.VirtualAddress == 0) { UnmapViewOfFile(pBase); CloseHandle(hMap); CloseHandle(hFile); return 0; }

  321.     // 定位资源节(.rsrc)
  322.     PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(nt);
  323.     for (int i = 0; i < nt->FileHeader.NumberOfSections; i++, section++) {
  324.         if (resDir.VirtualAddress >= section->VirtualAddress &&
  325.             resDir.VirtualAddress < section->VirtualAddress + section->Misc.VirtualSize) break;
  326.     }

  327.     // 计算资源目录在文件中的实际偏移
  328.     DWORD resOffset = resDir.VirtualAddress - section->VirtualAddress + section->PointerToRawData;
  329.     PIMAGE_RESOURCE_DIRECTORY rootDir = (PIMAGE_RESOURCE_DIRECTORY)((BYTE*)pBase + resOffset);

  330.     // 遍历资源类型,找到 RT_GROUP_ICON(ID=14)
  331.     PIMAGE_RESOURCE_DIRECTORY_ENTRY typeEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(rootDir + 1);
  332.     for (DWORD i = 0; i < rootDir->NumberOfIdEntries; i++, typeEntry++) {
  333.         if (typeEntry->Id == 14) { // RT_GROUP_ICON = 14
  334.             // 获取第一个图标ID(进入ID目录的第一个条目)
  335.             PIMAGE_RESOURCE_DIRECTORY iconDir = (PIMAGE_RESOURCE_DIRECTORY)((BYTE*)rootDir + typeEntry->OffsetToDirectory);
  336.             PIMAGE_RESOURCE_DIRECTORY_ENTRY iconIdEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(iconDir + 1);
  337.             DWORD firstIconId = iconIdEntry->Id;

  338.             UnmapViewOfFile(pBase);
  339.             CloseHandle(hMap);
  340.             CloseHandle(hFile);
  341.             return firstIconId;
  342.         }
  343.     }

  344.     UnmapViewOfFile(pBase);
  345.     CloseHandle(hMap);
  346.     CloseHandle(hFile);
  347.     return 0;
  348. }

  349. // 调用示例:获取 Photoshop.exe 的第一个图标ID
  350. int main() {
  351.     LPCWSTR exePath = L"D:\\软件\\Photoshop\\Photoshop.exe";
  352.     DWORD iconId = GetFirstIconGroupID(exePath);
  353.     printf("第一个图标ID: %u\n", iconId); // 输出:1000 或 1 等
  354.     return 0;
  355. }

复制代码
这玩意写的太累人了。坐了一天,快点给钱吧

点评

牛逼!目测这代码值一千块钱  详情 回复 发表于 前天 17:50
这代码应该还有地方有偏移地址计算错的。 ENVI &&IMAGE_DIRECTORY_ENTRY_RESOURCE=0 才可以,实际看源码是 ENVI &&IMAGE_DIRECTORY_ENTRY_RESOURCE=2。 你看看自己能不能解决吧,解决不了 回头我再看看。  详情 回复 发表于 前天 16:19
红毛樱木 发表于 前天 10:33
Zap 发表于 2025-11-3 23:07
获取程序图标组中第一个图标的ID
    定位 RT_GROUP_ICON(类型ID=14)的资源目录,跳过无关资源类型。
  ...

这里有几个结构体,要用PECMD搞,太烦了。
5315929 发表于 3 天前
谢谢楼主分享
Zap 发表于 4 天前
获取程序图标组中第一个图标的ID
    定位 RT_GROUP_ICON(类型ID=14)的资源目录,跳过无关资源类型。
    简化偏移计算,利用PE文件的 IMAGE_DATA_DIRECTORY 直接定位资源节。
求翻译PECMD怎样写

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

  3. DWORD GetFirstIconGroupID(LPCWSTR exePath) {
  4.     HANDLE hFile = CreateFileW(exePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
  5.     if (hFile == INVALID_HANDLE_VALUE) return 0;

  6.     DWORD fileSize = GetFileSize(hFile, NULL);
  7.     HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, fileSize, NULL);
  8.     LPVOID pBase = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
  9.     if (!pBase) { CloseHandle(hMap); CloseHandle(hFile); return 0; }

  10.     PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)pBase;
  11.     PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((BYTE*)pBase + dos->e_lfanew);
  12.     if (nt->Signature != IMAGE_NT_SIGNATURE) { UnmapViewOfFile(pBase); CloseHandle(hMap); CloseHandle(hFile); return 0; }

  13.     // 定位资源目录
  14.     auto& resDir = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
  15.     if (resDir.VirtualAddress == 0) { UnmapViewOfFile(pBase); CloseHandle(hMap); CloseHandle(hFile); return 0; }

  16.     // 定位资源节(.rsrc)
  17.     PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(nt);
  18.     for (int i = 0; i < nt->FileHeader.NumberOfSections; i++, section++) {
  19.         if (resDir.VirtualAddress >= section->VirtualAddress &&
  20.             resDir.VirtualAddress < section->VirtualAddress + section->Misc.VirtualSize) break;
  21.     }

  22.     // 计算资源目录在文件中的实际偏移
  23.     DWORD resOffset = resDir.VirtualAddress - section->VirtualAddress + section->PointerToRawData;
  24.     PIMAGE_RESOURCE_DIRECTORY rootDir = (PIMAGE_RESOURCE_DIRECTORY)((BYTE*)pBase + resOffset);

  25.     // 遍历资源类型,找到 RT_GROUP_ICON(ID=14)
  26.     PIMAGE_RESOURCE_DIRECTORY_ENTRY typeEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(rootDir + 1);
  27.     for (DWORD i = 0; i < rootDir->NumberOfIdEntries; i++, typeEntry++) {
  28.         if (typeEntry->Id == 14) { // RT_GROUP_ICON = 14
  29.             // 获取第一个图标ID(进入ID目录的第一个条目)
  30.             PIMAGE_RESOURCE_DIRECTORY iconDir = (PIMAGE_RESOURCE_DIRECTORY)((BYTE*)rootDir + typeEntry->OffsetToDirectory);
  31.             PIMAGE_RESOURCE_DIRECTORY_ENTRY iconIdEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(iconDir + 1);
  32.             DWORD firstIconId = iconIdEntry->Id;

  33.             UnmapViewOfFile(pBase);
  34.             CloseHandle(hMap);
  35.             CloseHandle(hFile);
  36.             return firstIconId;
  37.         }
  38.     }

  39.     UnmapViewOfFile(pBase);
  40.     CloseHandle(hMap);
  41.     CloseHandle(hFile);
  42.     return 0;
  43. }

  44. // 调用示例:获取 Photoshop.exe 的第一个图标ID
  45. int main() {
  46.     LPCWSTR exePath = L"D:\\软件\\Photoshop\\Photoshop.exe";
  47.     DWORD iconId = GetFirstIconGroupID(exePath);
  48.     printf("第一个图标ID: %u\n", iconId); // 输出:1000 或 1 等
  49.     return 0;
  50. }
复制代码

点评

这玩意写的太累人了。坐了一天,快点给钱吧  详情 回复 发表于 前天 16:14
这里有几个结构体,要用PECMD搞,太烦了。  详情 回复 发表于 前天 10:33
a66 发表于 2025-10-16 16:31:44
经典资源,收藏备用
a66 发表于 2025-10-16 16:31:33
正需要,很不错
a66 发表于 2025-10-16 16:31:20
支持大佬,收下备用!
a66 发表于 2025-10-16 16:30:38
干货满满!很给力~
a66 发表于 2025-10-16 13:30:58
测试
a66 发表于 2025-10-16 13:30:38
好东西  
a66 发表于 2025-10-16 12:17:54
多看多学习,支持一下!
a66 发表于 2025-10-16 12:17:21
多窗口

小黑屋|手机版|Archiver|捐助支持|无忧启动 ( 闽ICP备05002490号-1 )

闽公网安备 35020302032614号

GMT+8, 2025-11-7 23:00

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表