PE文件解析ICO资源图片(x86和x64均可用)
#include <Windows.h> #include <stdio.h> #include <iostream> #include <time.h> #define RES_IS_DIR 0x80000000 #define RES_AND_DIR 0x7fffffff #define RES_IS_NAME 0x80000000 #define RES_AND_NAME 0x7fffffff #define FILENAME_LENGTH 256 #define RES_ICON_INDEX 0x03 #define RES_ICON_GROUP_INDEX 0xE char sectioninfo[] = "\nname\t实际大小\tRVA\t\t原始大小\t文件位置\t属性\n"; char szSection[] = "%s\t%08x\t%08x\t%08x\t%08x\t%08x"; char szMsgRes[] = "\n\n资源所处的节:%s , rva:%08X , foa:%08X,资源首地址:%08X\n"; char szMsgResErr[] = "没有资源\n"; wchar_t szLevel1ByID[] = L"资源类型(自定义) %d"; wchar_t szLevel1[] = L"\n资源类型:%s\n"; wchar_t szLevel2ByName[] = L" Name:%s\n"; wchar_t szLevel2ByID[] = L" ID:%d\n"; wchar_t szResData[] = L" 文件偏移:%08X, RVA::%08X 代码页=%04X, 长度%d字节\n"; const wchar_t* szMsgResType[] = { L"光标", L"位图", L"图标",\ L"菜单",\ L"对话框",\ L"字符串",\ L"字体目录",\ L"字体",\ L"加速键",\ L"未格式化资源",\ L"消息表",\ L"光标组",\ L"未知类型",\ L"图标组",\ L"未知类型",\ L"版本信息" }; #pragma pack( push, 1 ) //文件中 图标项结构 struct ICON_DIR_ENTRY { unsigned char width; unsigned char height; unsigned char colorcount; unsigned char reserved; WORD planes; WORD bitcount; DWORD bytesInRes; //字节大小 DWORD imageOffset; // 文件中的位置 }; //pe中图标项结构,与文件中只有最后一个字段有区别 struct ICON_DIR_ENTRY_IN_PE { unsigned char width; unsigned char height; unsigned char colorcount; unsigned char reserved; WORD planes; WORD bitcount; DWORD bytesInRes; WORD idIndex; // 图标id, 对应资源图标目录中的id }; //文件中icon头结构 struct ICON_DIR { WORD reserved; WORD idtype; WORD idcount; ICON_DIR_ENTRY dir_entry[1]; }; // pe中的图标头结构 struct ICON_DIR_IN_PE { WORD reserved; // 保留 WORD idtype; // 图标类型 WORD idcount; // 此图标包含图片的数量 ICON_DIR_ENTRY_IN_PE dir_entry[1]; }; #pragma pack( pop) IMAGE_SECTION_HEADER* find_section(SIZE_T mem, DWORD rva) { IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)mem; IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)(mem + dos->e_lfanew); WORD n = nt->FileHeader.NumberOfSections; IMAGE_SECTION_HEADER* header = IMAGE_FIRST_SECTION(nt); IMAGE_SECTION_HEADER* sec = 0; for (WORD i = 0; i < n; ++i) { if (rva >= header->VirtualAddress && rva < header->VirtualAddress + header->SizeOfRawData) { sec = header; break; } header++; } return sec; } SIZE_T rva2foa(SIZE_T mem, DWORD rva) { IMAGE_SECTION_HEADER* header = find_section(mem, rva); SIZE_T foa = 0; if (header) { foa = rva - header->VirtualAddress; foa += header->PointerToRawData; } return foa; } char* get_section_name(SIZE_T mem, DWORD rva) { IMAGE_SECTION_HEADER* header = find_section(mem, rva); if (header) { return (char*)header->Name; } return NULL; } void print_all_sections(SIZE_T mem) { IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)mem; IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)(mem + dos->e_lfanew); WORD n = nt->FileHeader.NumberOfSections; IMAGE_SECTION_HEADER* header = IMAGE_FIRST_SECTION(nt); printf(sectioninfo); for (WORD i = 0; i < n; ++i) { printf(szSection, header->Name, header->Misc.VirtualSize, header->VirtualAddress, header->SizeOfRawData, header->PointerToRawData, header->Characteristics); header++; } } bool pathExists(const TCHAR* path) { WIN32_FILE_ATTRIBUTE_DATA attr = { 0 }; return 0 != ::GetFileAttributesExW(path, GetFileExInfoStandard, &attr); } //查找资源类型入口, 仅匹配预定义的资源类型 IMAGE_RESOURCE_DIRECTORY_ENTRY* find_res_type_entry(SIZE_T resmem, DWORD res_type) { IMAGE_RESOURCE_DIRECTORY* res = (IMAGE_RESOURCE_DIRECTORY*)resmem; IMAGE_RESOURCE_DIRECTORY_ENTRY* entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(resmem + sizeof(IMAGE_RESOURCE_DIRECTORY)); WORD n = res->NumberOfIdEntries + res->NumberOfNamedEntries; IMAGE_RESOURCE_DIRECTORY_ENTRY* ret_entry = 0; for (WORD i = 0; i < n; ++i) { if (entry->OffsetToData & RES_IS_DIR) { if ((!(entry->Name & RES_IS_NAME)) && (res_type == entry->Name)) { ret_entry = entry; break; } } entry++; } return ret_entry; } //创建一个ico文件 HANDLE create_icon_file(SIZE_T resmem, DWORD icon_name_addr) { WCHAR filename[FILENAME_LENGTH] = { 0 }; DWORD randnum = 0; DWORD times = 0; create_file_name: ++times; memset(filename, 0, sizeof(wchar_t) * FILENAME_LENGTH); randnum = rand(); if (icon_name_addr & RES_IS_NAME) { IMAGE_RESOURCE_DIR_STRING_U* rds = (IMAGE_RESOURCE_DIR_STRING_U*)((icon_name_addr & RES_AND_NAME) + resmem); wsprintfW(filename, L"%s_%d.ico", rds->NameString, randnum); } else { wsprintfW(filename, L"%d_%d.ico", icon_name_addr, randnum); } if (pathExists(filename)) { if (times < 100) // 大于100次尝试重命名直接放弃 goto create_file_name; return INVALID_HANDLE_VALUE; } return ::CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); } //写入 BOOL write_bin(HANDLE hFile, void* mem, DWORD size) { DWORD nWritten = 0; return WriteFile(hFile, mem, size, &nWritten, 0); } //根据图标id 查找图标入口 IMAGE_RESOURCE_DIRECTORY_ENTRY* find_icon_entry_by_id(SIZE_T resmem, DWORD id) { IMAGE_RESOURCE_DIRECTORY_ENTRY* icon_entry = find_res_type_entry(resmem, RES_ICON_INDEX); IMAGE_RESOURCE_DIRECTORY* icon_id_dir = (IMAGE_RESOURCE_DIRECTORY*)((icon_entry->OffsetToData & RES_AND_DIR) + resmem); IMAGE_RESOURCE_DIRECTORY_ENTRY* identry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)((SIZE_T)icon_id_dir + sizeof(IMAGE_RESOURCE_DIRECTORY)); IMAGE_RESOURCE_DIRECTORY_ENTRY* ret_entry = 0; int n = icon_id_dir->NumberOfIdEntries + icon_id_dir->NumberOfNamedEntries; for (int i = 0; i < n; ++i) { if (identry->OffsetToData & RES_IS_DIR) { if ((!(identry->Name & RES_IS_NAME)) && (id == identry->Name)) { ret_entry = identry; break; } } ++identry; } return ret_entry; } //根据图标ID 找到对应的代码页 IMAGE_RESOURCE_DIRECTORY* find_icon_codepage_dir_by_id(SIZE_T resmem, DWORD id) { IMAGE_RESOURCE_DIRECTORY_ENTRY* id_entry = find_icon_entry_by_id(resmem, id); IMAGE_RESOURCE_DIRECTORY* code_page_dir = (IMAGE_RESOURCE_DIRECTORY*)((id_entry->OffsetToData & RES_AND_DIR) + resmem); return code_page_dir; } //根据图标组的ico头信息, 找到对应的图标资源本体, 写入文件 void process_icon_body_data(SIZE_T filemem, SIZE_T resmem, ICON_DIR_ENTRY_IN_PE* pe_icon_entry, HANDLE hFile) { DWORD id = pe_icon_entry->idIndex; IMAGE_RESOURCE_DIRECTORY* code_page_dir = find_icon_codepage_dir_by_id(resmem, id); IMAGE_RESOURCE_DIRECTORY_ENTRY* code_page_entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)((SIZE_T)code_page_dir + sizeof(IMAGE_RESOURCE_DIRECTORY)); int n = code_page_dir->NumberOfIdEntries + code_page_dir->NumberOfNamedEntries; for (int i = 0; i < n; ++i) { IMAGE_RESOURCE_DATA_ENTRY* data_entry = (IMAGE_RESOURCE_DATA_ENTRY*)(code_page_entry->OffsetToData + resmem); SIZE_T data_offset = rva2foa(filemem, data_entry->OffsetToData); data_offset += filemem; write_bin(hFile, (void*)data_offset, data_entry->Size); } } //解析图标组, 把ICON_DIR_ENTRY_IN_PE 转成 文件中适用的ICON_DIR_ENTRY void process_icon_header_data(SIZE_T filemem, SIZE_T resmem, SIZE_T data_mem, DWORD data_size, HANDLE hFile) { ICON_DIR_IN_PE* pe_icon_header = (ICON_DIR_IN_PE*)data_mem; ICON_DIR_ENTRY_IN_PE* pe_icon_entry = pe_icon_header->dir_entry; WORD iCount = pe_icon_header->idcount; // 此图标包含有几个图片数据 DWORD iFileHeaderSize = data_size + iCount * 2; //每个图标项少2个字节,因此全部加上后为文件中的头文件大小 //首先写头 6 个字节, 后续ICON_DIR_ENTRY_IN_PE 需要改成 ICON_DIR_ENTRY //以下所有的写入出错处理全部简化 BOOL bSuccess = write_bin(hFile, pe_icon_header, 6); if (!bSuccess) { std::cout << __LINE__ << ", 写入头失败" << std::endl; return; } ICON_DIR_ENTRY file_entry = { 0 }; const DWORD dwCopyBytes = 12; // 前12字节全一样 DWORD offset = 0; //写入ICON_DIR_ENTRY,从ICON_DIR_ENTRY_IN_PE转成ICON_DIR_ENTRY //等循环结束, 整个头结构全部写入 for (int i = 0; i < iCount; ++i) { memcpy(&file_entry, pe_icon_entry, dwCopyBytes); offset += iFileHeaderSize; file_entry.imageOffset = offset; if (!write_bin(hFile, &file_entry, sizeof(ICON_DIR_ENTRY))) { std::cout << __LINE__ << ", 写入ICON_DIR_ENTRY失败 , 第:" << i << "个 " << std::endl; return; } offset = file_entry.bytesInRes; pe_icon_entry++; } //写入图片本身数据 pe_icon_entry = pe_icon_header->dir_entry; for (int i = 0; i < iCount; ++i) { process_icon_body_data(filemem, resmem, pe_icon_entry, hFile); ++pe_icon_entry; } } void process_iconGroup_dataEntry(SIZE_T filemem, SIZE_T resmem, IMAGE_RESOURCE_DIRECTORY_ENTRY* entry, HANDLE hFile) { IMAGE_RESOURCE_DATA_ENTRY* data_entry = (IMAGE_RESOURCE_DATA_ENTRY*)(entry->OffsetToData + resmem); SIZE_T data_foa = rva2foa(filemem, data_entry->OffsetToData); SIZE_T data_mem = data_foa + filemem; process_icon_header_data(filemem, resmem, data_mem, data_entry->Size, hFile); } void process_iconGroup_codePageDir(SIZE_T filemem, SIZE_T resmem, SIZE_T dirmem, DWORD icon_name_addr) { //这里只处理一个codepage 的入口,如果有多个需要自己依次组合每个文件头 IMAGE_RESOURCE_DIRECTORY* res = (IMAGE_RESOURCE_DIRECTORY*)dirmem; IMAGE_RESOURCE_DIRECTORY_ENTRY* entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(dirmem + sizeof(IMAGE_RESOURCE_DIRECTORY)); HANDLE hFile = create_icon_file(resmem, icon_name_addr); if (INVALID_HANDLE_VALUE == hFile) { std::cout << "icon_name_addr :" << icon_name_addr << " , 创建文件失败" << std::endl; return; } process_iconGroup_dataEntry(filemem, resmem, entry, hFile); CloseHandle(hFile); } //开始处理图标组 void process_iconGroup_idDir(SIZE_T filemem, SIZE_T resmem, SIZE_T dirmem) { IMAGE_RESOURCE_DIRECTORY* res = (IMAGE_RESOURCE_DIRECTORY*)dirmem; IMAGE_RESOURCE_DIRECTORY_ENTRY* entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(dirmem + sizeof(IMAGE_RESOURCE_DIRECTORY)); WORD n = res->NumberOfIdEntries + res->NumberOfNamedEntries; SIZE_T inner_dir_addr = 0; for (WORD i = 0; i < n; ++i) { if (entry->OffsetToData & RES_IS_DIR) { inner_dir_addr = (entry->OffsetToData & RES_AND_DIR) + resmem; process_iconGroup_codePageDir(filemem, resmem, inner_dir_addr, entry->Name); } entry++; } } //开始解析图标 void process_res(SIZE_T filemem, SIZE_T resmem) { IMAGE_RESOURCE_DIRECTORY_ENTRY* icon_group_entry = find_res_type_entry(resmem, RES_ICON_GROUP_INDEX); IMAGE_RESOURCE_DIRECTORY_ENTRY* icon_entry = find_res_type_entry(resmem, RES_ICON_INDEX); if (0 == icon_group_entry || 0 == icon_entry) { std::cout << __LINE__ << " 图标组或图标入口不存在" << std::endl; return; } SIZE_T icon_group_id_dir_addr = (icon_group_entry->OffsetToData & RES_AND_DIR) + resmem; process_iconGroup_idDir(filemem, resmem, icon_group_id_dir_addr); } void get_res(SIZE_T mem) { IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)mem; IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)(mem + dos->e_lfanew); DWORD res_rva = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; if (0 == res_rva) { puts(szMsgResErr); return; } SIZE_T res_foa = rva2foa(mem, res_rva); SIZE_T res_mem = res_foa + mem; puts("开始检查图标组和图标资源"); printf(szMsgRes, get_section_name(mem, res_rva), res_rva, res_foa, res_mem); process_res(mem, res_mem); } void print_res_dir_data(SIZE_T filemem, SIZE_T resmem, IMAGE_RESOURCE_DIRECTORY_ENTRY* entry) { DWORD code_page = entry->Name; IMAGE_RESOURCE_DATA_ENTRY* data_entry = (IMAGE_RESOURCE_DATA_ENTRY*)(entry->OffsetToData + resmem); SIZE_T rva = data_entry->OffsetToData; SIZE_T foa = rva2foa(filemem, rva); wprintf(szResData, foa, rva, code_page, data_entry->Size); } void print_res_dir_id(SIZE_T resmem, IMAGE_RESOURCE_DIRECTORY_ENTRY* entry) { DWORD name = entry->Name; SIZE_T name_addr = 0; if (name & RES_IS_NAME) { name_addr = (name & RES_AND_NAME) + resmem; IMAGE_RESOURCE_DIR_STRING_U* rds = (IMAGE_RESOURCE_DIR_STRING_U*)(name_addr); wprintf(szLevel2ByName, rds->NameString); } else { wprintf(szLevel2ByID, name); } } void print_res_dir_type(SIZE_T resmem, IMAGE_RESOURCE_DIRECTORY_ENTRY* entry) { DWORD name = entry->Name; SIZE_T name_addr = 0; wchar_t* pname = 0; wchar_t buffer[64] = { 0 }; if (name & RES_IS_NAME) { name_addr = (name & RES_AND_NAME) + resmem; IMAGE_RESOURCE_DIR_STRING_U* rds = (IMAGE_RESOURCE_DIR_STRING_U*)(name_addr); pname = rds->NameString; } else { if (name <= 0x10) wsprintfW(buffer, szMsgResType[name - 1]); else wsprintfW(buffer, szLevel1ByID, name); pname = buffer; } wprintf(szLevel1, pname); } void print_res_dir(SIZE_T filemem, SIZE_T resmem, SIZE_T dirmem, DWORD level) { IMAGE_RESOURCE_DIRECTORY* res = (IMAGE_RESOURCE_DIRECTORY*)dirmem; IMAGE_RESOURCE_DIRECTORY_ENTRY* entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(dirmem + sizeof(IMAGE_RESOURCE_DIRECTORY)); int n = res->NumberOfIdEntries + res->NumberOfNamedEntries; DWORD next_dir_mem = 0; for (int i = 0; i < n; ++i) { if (entry->OffsetToData & RES_IS_DIR) { if (1 == level) { print_res_dir_type(resmem, entry); } else if (2 == level) { print_res_dir_id(resmem, entry); } else { std::cout << "error" << std::endl; } next_dir_mem = (entry->OffsetToData & RES_AND_DIR) + resmem; print_res_dir(filemem, resmem, next_dir_mem, level + 1); } else { print_res_dir_data(filemem, resmem, entry); } entry++; } } void print_res(SIZE_T mem) { IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)mem; IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)(mem + dos->e_lfanew); DWORD res_rva = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; if (0 == res_rva) { puts(szMsgResErr); return; } SIZE_T res_foa = rva2foa(mem, res_rva); SIZE_T res_mem = res_foa + mem; printf(szMsgRes, get_section_name(mem, res_rva), res_rva, res_foa, res_mem); print_res_dir(mem, res_mem, res_mem, 1); } void createFileMapAndPrint(LPCWSTR lpcwFileName) { setlocale(LC_ALL, ""); HANDLE hFile = 0; HANDLE hMap = 0; void* mem = 0; __try { hFile = ::CreateFileW(lpcwFileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, 0); if (INVALID_HANDLE_VALUE == hFile) { std::cout << "create file failed" << std::endl; __leave; } hMap = ::CreateFileMappingW(hFile, 0, PAGE_READONLY, 0, 0, 0); if (0 == hMap) { std::cout << "CreateFileMapping failed" << std::endl; __leave; } mem = ::MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); if (0 == mem) { std::cout << "MapViewOfFile failed" << std::endl; __leave; } get_res((SIZE_T)mem); //解析图标组,写入图标 //print_res((DWORD)mem); //print_all_sections((DWORD)mem); } __finally { ::UnmapViewOfFile(mem); ::CloseHandle(hMap); ::CloseHandle(hFile); } } __inline static int test_main(const std::wstring& wExeName) { srand(time(0)); createFileMapAndPrint(wExeName.c_str()); return 0; }
收藏的用户(0)
X
正在加载信息~
2
最新回复 (0)