PE文件的图标资源是储存在资源表中的,其中图标ID为3 图标组ID为14 只要遍历图标组得到图标头数据对应图标ID 再根据图标ID遍历资源表得到图标数据 然后合成完整图标数据就可以了,以下为具体实现代码…

#include "stdafx.h"
#include <stdio.h>
#include <Windows.h>
#include <iostream>
using namespace std;
//根据内存偏移地址RVA得到文件偏移地址
DWORD RvaToOffset(PIMAGE_NT_HEADERS pNtHeader, DWORD rva)
{//PE节IMAGE_SECTION_HEADER * p_Section_Header;//获得Pe节数目DWORD sectionSum = pNtHeader->FileHeader.NumberOfSections;//第一个节表项p_Section_Header = (IMAGE_SECTION_HEADER *)((DWORD)pNtHeader + (DWORD)sizeof(IMAGE_NT_HEADERS));for (int i = 0; i < sectionSum; i++){//printf_s("%s\n", p_Section_Header->Name);//virtualAddress节区的RVA地址//sizeofrawdata节区对齐后的尺寸//PointerToRawData节区起始数据在文件中的偏移if (p_Section_Header->VirtualAddress <= rva && rva < p_Section_Header->VirtualAddress + p_Section_Header->SizeOfRawData){return rva - p_Section_Header->VirtualAddress + p_Section_Header->PointerToRawData;}p_Section_Header++;}return 0x00000;
}
//char*转wchar_t*
wchar_t * AnsiToUnicode(const char* szStr)
{int nLen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szStr, -1, NULL, 0);if (nLen == 0){return NULL;}wchar_t* pResult = new wchar_t[nLen];MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szStr, -1, pResult, nLen);return pResult;
}
//根据ID得到图标资源
PIMAGE_RESOURCE_DATA_ENTRY ExtractIcoByID(PIMAGE_RESOURCE_DIRECTORY pImageResourceDirectoryRoot, PIMAGE_DOS_HEADER pImageDosHeader, PIMAGE_NT_HEADERS pImageNtHeader, int ID)
{
//遍历资源表根目录for (int i = 0; i < pImageResourceDirectoryRoot->NumberOfIdEntries + pImageResourceDirectoryRoot->NumberOfNamedEntries; i++){//depth == 2PIMAGE_RESOURCE_DIRECTORY_ENTRY pImageResourceDirectoryEntrySec = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((DWORD)pImageResourceDirectoryRoot + sizeof(IMAGE_RESOURCE_DIRECTORY)) + i;//图标资源if (pImageResourceDirectoryEntrySec->Id == 3){PIMAGE_RESOURCE_DIRECTORY pImageResourceDirectorySec = (PIMAGE_RESOURCE_DIRECTORY)((DWORD)pImageResourceDirectoryRoot + pImageResourceDirectoryEntrySec->OffsetToDirectory);for (int r = 0; r < pImageResourceDirectorySec->NumberOfIdEntries + pImageResourceDirectorySec->NumberOfNamedEntries; r++){//depth == 3PIMAGE_RESOURCE_DIRECTORY_ENTRY pImageResourceDirectoryEntryTir = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((DWORD)pImageResourceDirectorySec + sizeof(IMAGE_RESOURCE_DIRECTORY)) + r;//根据图标ID获得图标数据if (pImageResourceDirectoryEntryTir->Id == ID){PIMAGE_RESOURCE_DIRECTORY pImageResourceDirectoryTir = (PIMAGE_RESOURCE_DIRECTORY)((DWORD)pImageResourceDirectoryRoot + pImageResourceDirectoryEntryTir->OffsetToDirectory);for (int t = 0; t < pImageResourceDirectoryTir->NumberOfIdEntries + pImageResourceDirectoryTir->NumberOfNamedEntries; t++){//depth == 4PIMAGE_RESOURCE_DIRECTORY_ENTRY pImageResourceDirectoryEntryFour = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((DWORD)pImageResourceDirectoryTir + sizeof(IMAGE_RESOURCE_DIRECTORY)) + t;PIMAGE_RESOURCE_DATA_ENTRY pImageResourceDataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)((DWORD)pImageResourceDirectoryRoot + pImageResourceDirectoryEntryFour->OffsetToData);return pImageResourceDataEntry;}}}}}return NULL;
}
//图标提取方法
void ExtractIco(PIMAGE_RESOURCE_DIRECTORY pImageResourceDirectoryRoot, PIMAGE_DOS_HEADER pImageDosHeader, PIMAGE_NT_HEADERS pImageNtHeader)
{int sizeOfIcoGroup;DWORD pIcoData;DWORD pIcoGroupData;//遍历资源表根目录for (int i = 0; i < pImageResourceDirectoryRoot->NumberOfIdEntries + pImageResourceDirectoryRoot->NumberOfNamedEntries; i++){//depth == 2PIMAGE_RESOURCE_DIRECTORY_ENTRY pImageResourceDirectoryEntrySec = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((DWORD)pImageResourceDirectoryRoot + sizeof(IMAGE_RESOURCE_DIRECTORY)) + i;//图标资源if (pImageResourceDirectoryEntrySec->Id == 3){PIMAGE_RESOURCE_DIRECTORY pImageResourceDirectorySec = (PIMAGE_RESOURCE_DIRECTORY)((DWORD)pImageResourceDirectoryRoot + pImageResourceDirectoryEntrySec->OffsetToDirectory);}//图标组if (pImageResourceDirectoryEntrySec->Id == 14){PIMAGE_RESOURCE_DIRECTORY pImageResourceDirectorySec = (PIMAGE_RESOURCE_DIRECTORY)((DWORD)pImageResourceDirectoryRoot + pImageResourceDirectoryEntrySec->OffsetToDirectory);for (int r = 0; r < pImageResourceDirectorySec->NumberOfIdEntries + pImageResourceDirectorySec->NumberOfNamedEntries; r++){//depth == 3PIMAGE_RESOURCE_DIRECTORY_ENTRY pImageResourceDirectoryEntryTir = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((DWORD)pImageResourceDirectorySec + sizeof(IMAGE_RESOURCE_DIRECTORY)) + r;PIMAGE_RESOURCE_DIRECTORY pImageResourceDirectoryTir = (PIMAGE_RESOURCE_DIRECTORY)((DWORD)pImageResourceDirectoryRoot + pImageResourceDirectoryEntryTir->OffsetToDirectory);for (int t = 0; t < pImageResourceDirectoryTir->NumberOfIdEntries + pImageResourceDirectoryTir->NumberOfNamedEntries; t++){//depth == 4PIMAGE_RESOURCE_DIRECTORY_ENTRY pImageResourceDirectoryEntryFour = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((DWORD)pImageResourceDirectoryTir + sizeof(IMAGE_RESOURCE_DIRECTORY)) + t;PIMAGE_RESOURCE_DATA_ENTRY pImageResourceDataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)((DWORD)pImageResourceDirectoryRoot + pImageResourceDirectoryEntryFour->OffsetToData);pIcoGroupData = (DWORD)pImageDosHeader + RvaToOffset(pImageNtHeader, pImageResourceDataEntry->OffsetToData);sizeOfIcoGroup = pImageResourceDataEntry->Size;//printf_s("%08x\n", *((WORD*)pIcoGroupData + 2));//得到图标组中图标数量for (int n = 0; n < *((WORD*)pIcoGroupData + 2); n++){//只包含一个图标的图标头构造byte * currentIcoHeader = 6 + 14 * n + (byte*)pIcoGroupData;byte * myIcoHeader = new byte[22];myIcoHeader[0] = 0x00;myIcoHeader[1] = 0x00;myIcoHeader[2] = 0x01;myIcoHeader[3] = 0x00;myIcoHeader[4] = 0x02;myIcoHeader[5] = 0x00;for (int m = 6; m < 14; m++){myIcoHeader[m] = currentIcoHeader[m - 6];}int ID = (DWORD)*(currentIcoHeader + 12);PIMAGE_RESOURCE_DATA_ENTRY pImageResourceDataEntryOfIco = ExtractIcoByID(pImageResourceDirectoryRoot, pImageDosHeader, pImageNtHeader, ID);myIcoHeader[14] = (byte)pImageResourceDataEntryOfIco->Size;myIcoHeader[15] = (byte)(pImageResourceDataEntryOfIco->Size >> 8);myIcoHeader[16] = (byte)(pImageResourceDataEntryOfIco->Size >> 16);myIcoHeader[17] = (byte)(pImageResourceDataEntryOfIco->Size >> 24);myIcoHeader[18] = 0x16;myIcoHeader[19] = 0x00;myIcoHeader[20] = 0x00;myIcoHeader[21] = 0x00;pIcoData = (DWORD)pImageDosHeader + RvaToOffset(pImageNtHeader, pImageResourceDataEntryOfIco->OffsetToData);char * nameHeader = "D:\\";char * nameTail = ".ico";char fileName[10] = "\0";sprintf(fileName, "%s%d", nameHeader, ID);sprintf(fileName, "%s%s", fileName, nameTail);HANDLE hFile = CreateFile(AnsiToUnicode(fileName), GENERIC_ALL, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);//写入文件WriteFile(hFile, (LPVOID)myIcoHeader, 22, NULL, NULL);WriteFile(hFile, (LPVOID)pIcoData, pImageResourceDataEntryOfIco->Size, NULL, NULL);CloseHandle(hFile);free(myIcoHeader);}}}}}
}
void PEControl()
{LPCWSTR fileName = TEXT("D:\\Program Files\\Tencent\\QQ\\Bin\\QQScLauncher.exe");HANDLE fileHandle = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);DWORD high_size;DWORD size = GetFileSize(fileHandle, &high_size);HANDLE hMapFile = CreateFileMapping(fileHandle, NULL, PAGE_READONLY, 0, 0, NULL);if (hMapFile == NULL){cout << "内存映射文件失败" << endl;system("PAUSE");}LPDWORD lpMemory = (LPDWORD)MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);//得到PE文件DOS头所在位置PIMAGE_DOS_HEADER pImageDosHeader = (PIMAGE_DOS_HEADER)lpMemory;//得到PE头所在位置 PE start = DOS MZ 基地址 + IMAGE_DOS_HEADER.e_lfanewPIMAGE_NT_HEADERS pImageNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageDosHeader->e_lfanew + (DWORD)pImageDosHeader);//PE文件的图标数据储存在资源表中 得到资源表头所在位置 资源表RVA储存在PE扩展头(pImageNTHeader->OptionalHeader)的数据目录的第三个IMAGE_RESOURCE_DIRECTORY * pImageResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY)((DWORD)pImageDosHeader + RvaToOffset(pImageNTHeader, pImageNTHeader->OptionalHeader.DataDirectory[2].VirtualAddress));//调用PE文件ICO提取方法ExtractIco(pImageResourceDirectory, pImageDosHeader, pImageNTHeader);
}
int _tmain(int argc, _TCHAR* argv[])
{PEControl();return 0;
}

ps:因为用了sprintf 所以要关闭项目的安全检测才可编译成功。

下图为提取的QQ图标中的一个:

c++实现PE文件图标提取相关推荐

  1. 代码实现pe文件图标替换

    最近,好多人问我如何通过写个小程序,动态替换可执行文件的图标.这个问题看起来虽小,但却涉及到很多问题.网上也只能找到一些零零散散的资料,却没有详细的指导性文档.所以我决定把这个问题写下来,以方便大家查 ...

  2. 通过代码实现EXE文件图标的替换

    最近,好多人问我如何通过写个小程序,动态替换可执行文件的图标.这个问题看起来虽小,但却涉及到很多问题.网上也只能找到一些零零散散的资料,却没有详细的指导性文档.所以我决定把这个问题写下来,以方便大家查 ...

  3. 4.2 x64dbg 针对PE文件的扫描

    通过运用LyScript插件并配合pefile模块,即可实现对特定PE文件的扫描功能,例如载入PE程序到内存,验证PE启用的保护方式,计算PE节区内存特征,文件FOA与内存VA转换等功能的实现,首先简 ...

  4. 对PE文件进行十六进制代码(机器码)提取并保存到外部文件

    前言与声明 秉持开源和共享的理念,博主在这里分享自己的代码. 博客中的代码可以将PE文件的十六进制代码(机器码)提取出来,这些机器码可用于机器学习.软件分析等. 声明: 转载请标明来处,创作不易! 代 ...

  5. FindResource提取PE文件中的资源

    PE文件的资源为一个隐藏的PE文件,使用FindResource把它给提取出来,顺便理解一下资源函数的使用 // test.cpp : 定义控制台应用程序的入口点. //#include " ...

  6. 如何从Windows EXE文件中提取图标

    Sometimes you're working on a project and need access to a high-quality version of a Windows 10 appl ...

  7. 提取NTLDR文件,分解Osloader.exe;pe文件找e_lfanew、IMAGE_EXPORT_DIRECTORY-AddressOfFunctions

    1.1找出NTLDR文件. NTLDR文件位于xp操作系统c盘的根目录下,不过要先设置可以查看隐藏的系统文件. 将这一栏去掉,之后就找到了. 1.2分解osloader.exe 将NTLDR文件放入w ...

  8. [系统安全] 四十一.APT系列(6)Python解析PE文件并获取时间戳判断来源区域

    您可能之前看到过我写的类似文章,为什么还要重复撰写呢?只是想更好地帮助初学者了解病毒逆向分析和系统安全,更加成体系且不破坏之前的系列.因此,我重新开设了这个专栏,准备系统整理和深入学习系统安全.逆向分 ...

  9. PE文件详解(教程1-7)

    PE文件详解(教程1-7) ========================================= PE教程1: PE文件格式一览 PE 的意思就是 Portable Executable ...

最新文章

  1. 诊断ORA-08103错误
  2. 前端面试题目汇总摘录(JS 基础篇 —— 2018.11.01更新)
  3. javascript dom节点x
  4. 使用VS Code进行远程连接
  5. Django的model查询操作 与 查询性能优化
  6. CASIO 5800P计算器游戏--猜数字游戏
  7. C++使用流进行输入输出
  8. 自然语言处理常用标识符<UNK>,<PAD>,<SOS>,<EOS>等
  9. 记-ItextPDF+freemaker 生成PDF文件---导致服务宕机
  10. 蒸妙集团用科学熏蒸法,弥补现代人在运动上的缺乏
  11. 对于未定义为 System.String 的列,唯一有效的值是(引发异常)。
  12. java使用RSA加密方式,实现数字签名
  13. CLR via C#学习笔记-第十章-无参属性
  14. 解决Eclipse出现的Failure to transfer ... jar问题
  15. 趋势:指数基金如何做大做强?
  16. 人机身份验证开发资料
  17. IT项目管理流程以及每个步骤用到的文档
  18. Linux——shell脚本的基础篇(变量定义、变量种类、变量操作)
  19. 迅雷下载太慢怎么办?
  20. 酒仙网IPO被终止:曾拟募资10亿 红杉与东方富海是股东

热门文章

  1. 2.前端面试 css篇
  2. springboot+篮球场馆预约系统 毕业设计-附源码211706
  3. 惠普HP Deskjet F2188 多功能一体机驱动
  4. bat批处理脚本语法学习
  5. java中两个doub组成一个数组_Java基础知识2-Java基本语法
  6. 用“粥”到服务,保数据“粥”全,情暖腊八节
  7. Idea突然不停地闪退 问题解决
  8. 小米手环长时间不使用,电池休眠,充不进去电破解方案
  9. c#服务器后端_一文看懂Serverless:AWS阿里云腾讯云都在发力「无服务器架构」
  10. 掷骰子问题--动态规划