Loading... 菜单,对话框,图标,光标,位图,工具栏.....他们称之为资源,资源就是PE文件在运行的时候需要使用到的一些通用数据。编译的时候,将他们独立保存在一个区域中。 记录这些区域的一个结构,就是资源表了。 资源表分成了3层结构: 第一层:一共有多少种资源 第二层:这种资源有多少个 第三层:这个资源的位置 ![image.png](http://www.irohane.top/usr/uploads/2021/03/942973404.png) ``` typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { union { struct { DWORD NameOffset :31; // (1) 资源名偏移 DWORD NameIsString:1; // (2) 资源名为字符串 }; DWORD Name; // (3) 资源/语言类型 WORD Id; // (4) 资源数字ID }; union { DWORD OffsetToData; // (5) 数据偏移地址 struct { DWORD OffsetToDirectory:31;// (6) 子目录偏移地址 DWORD DataIsDirectory :1;// (7) 数据为目录 }; }; }IMAGE_RESOURCE_DIRECTORY_ENTRY,*PIMAGE_RESOURCE_DIRECTORY_ENTRY; ``` ``` #include <iostream> #include <Windows.h> #define PATH L"C:\\Users\\SouLinker\\Desktop\\FileCleaner2.0.exe" // 判断是不是PE文件 #include <map> using std::map; map<int, const char*> g_mapResourceInfo; map<const char*, const char*> abc; void InitResourceInfo() { g_mapResourceInfo[0x1] = "Cursor"; g_mapResourceInfo[0x2] = "BitMap"; g_mapResourceInfo[0x3] = "Icon"; g_mapResourceInfo[0x4] = "Menu"; g_mapResourceInfo[0x5] = "Dialog"; g_mapResourceInfo[0x6] = "String Table"; g_mapResourceInfo[0x7] = "Font Directory"; g_mapResourceInfo[0x8] = "Font"; g_mapResourceInfo[0x9] = "Accelerators"; g_mapResourceInfo[0xA] = "UnFormatted"; g_mapResourceInfo[0xB] = "Message Table"; g_mapResourceInfo[0xC] = "Group Cursor"; g_mapResourceInfo[0xE] = "Group Icon"; g_mapResourceInfo[0x10] = "Version Information"; } DWORD RvaToFoa(char* lpImage, DWORD dwRva); BOOL IsPE_File(char* lpImage); void AnalyzeResource(char* lpImage); int main() { setlocale(LC_ALL, "chs"); InitResourceInfo(); //1 打开文件 HANDLE hFile = CreateFile( PATH, GENERIC_ALL, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); //2 获取文件大小 DWORD dwFileSize = GetFileSize(hFile, NULL); //3 申请空间并初始化 char* buf = new char[dwFileSize] {0}; //4 读取文件 DWORD dwRealSize = 0; ReadFile(hFile, buf, dwFileSize, &dwRealSize, NULL); //5 判断是不是PE文件 if (IsPE_File(buf) == TRUE) { //printf("这是一个PE文件"); AnalyzeResource(buf); } else { printf("这不是一个PE文件"); } delete[]buf; buf = nullptr; return 0; } DWORD RvaToFoa(char* lpImage, DWORD dwRva) { //1 获取区段表的起始位置 PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)lpImage; PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + lpImage); PIMAGE_SECTION_HEADER pHeader = IMAGE_FIRST_SECTION(pNt); if (dwRva < pNt->OptionalHeader.SizeOfHeaders) { return dwRva; } //2 循环判断RVA落在了哪个区段中 for (int i = 0; i < pNt->FileHeader.NumberOfSections; i++) { DWORD dwSectionRva = pHeader[i].VirtualAddress; DWORD dwSectionEndRva = dwSectionRva + pHeader[i].SizeOfRawData; DWORD dwSectionFOA = pHeader[i].PointerToRawData; if (dwRva >= dwSectionRva && dwRva < dwSectionEndRva) { pHeader[i].VirtualAddress; DWORD dwFOA = dwRva - dwSectionRva + dwSectionFOA; return dwFOA; } } return -1; } BOOL IsPE_File(char* lpImage) { PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)lpImage; if (pDos->e_magic != IMAGE_DOS_SIGNATURE) { return FALSE; } PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + lpImage); if (pNt->Signature != IMAGE_NT_SIGNATURE) { return FALSE; } return TRUE; } void AnalyzeResource(char* lpImage) { //1. 找到资源表的结构体 PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)lpImage; PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + lpImage); PIMAGE_OPTIONAL_HEADER pOption = &pNt->OptionalHeader; //1. 得到了资源表的数据目录 PIMAGE_DATA_DIRECTORY pResourceDir= &pOption->DataDirectory[2]; //2. 得到资源表第一层的位置 DWORD dwResourceFOA = RvaToFoa(lpImage, pResourceDir->VirtualAddress); PIMAGE_RESOURCE_DIRECTORY pFirstDir =(PIMAGE_RESOURCE_DIRECTORY)(dwResourceFOA + lpImage); PIMAGE_RESOURCE_DIRECTORY_ENTRY pFirstRes = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pFirstDir + 1); //3. 解析资源表 DWORD dwFirstCount = pFirstDir->NumberOfIdEntries + pFirstDir->NumberOfNamedEntries; //3.1 解析第一层 for (int i = 0; i < dwFirstCount; i++) { //解析第一层的名称信息 if (pFirstRes[i].NameIsString == TRUE) { //以字符串作为标识 PIMAGE_RESOURCE_DIR_STRING_U pNameInfo = (PIMAGE_RESOURCE_DIR_STRING_U)(pFirstRes[i].NameOffset + (DWORD)pFirstDir); WCHAR* pName = new WCHAR[pNameInfo->Length + 1]{0}; //wcscpy_s(pName, pNameInfo->Length, pNameInfo->NameString); for (int m = 0; m < pNameInfo->Length; m++) { pName[m] = pNameInfo->NameString[m]; } wprintf(L"资源种类标识:%s\n", pName); } //以数字作为标识 else { if (g_mapResourceInfo.count(pFirstRes[i].Id) == 1) { printf("资源种类标识%s\n", g_mapResourceInfo[pFirstRes[i].Id]); } else { printf("资源种类标识%d\n", pFirstRes[i].Id); } } //解析第一层的位置信息,从而得到第二层 if (pFirstRes[i].DataIsDirectory == 1) { //根据偏移得到第二层的位置,以及数组 PIMAGE_RESOURCE_DIRECTORY pSecondDir = (PIMAGE_RESOURCE_DIRECTORY)(pFirstRes[i].OffsetToDirectory + (DWORD)pFirstDir); PIMAGE_RESOURCE_DIRECTORY_ENTRY pSecondRes = PIMAGE_RESOURCE_DIRECTORY_ENTRY(pSecondDir + 1); //第二层的资源个数 DWORD dwSecondCount = pSecondDir->NumberOfIdEntries + pSecondDir->NumberOfNamedEntries; for (int j = 0; j < dwSecondCount; j++) { //解析第二层的名称信息 if (pSecondRes[j].NameIsString == TRUE) { //以字符串作为标识 PIMAGE_RESOURCE_DIR_STRING_U pNameInfo = (PIMAGE_RESOURCE_DIR_STRING_U)(pSecondRes[j].NameOffset + (DWORD)pFirstDir); WCHAR* pName = new WCHAR[pNameInfo->Length + 1]{ 0 }; //wcscpy_s(pName, pNameInfo->Length + 1, pNameInfo->NameString); for (int m = 0; m < pNameInfo->Length; m++) { pName[m] = pNameInfo->NameString[m]; } wprintf(L" 资源标识:%s\n", pName); } else { wprintf(L" 资源标识:%d\n", pSecondRes[j].Id); } //解析第二层的位置信息 if (pSecondRes[j].DataIsDirectory == TRUE) { //根据偏移得到第三层的位置,以及数组 PIMAGE_RESOURCE_DIRECTORY pThirdDir = (PIMAGE_RESOURCE_DIRECTORY) (pSecondRes[j].OffsetToDirectory+ (DWORD)pFirstDir); PIMAGE_RESOURCE_DIRECTORY_ENTRY pThirdRes = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pThirdDir + 1); //解析第三层,但是不需要循环了 PIMAGE_RESOURCE_DATA_ENTRY pData = (PIMAGE_RESOURCE_DATA_ENTRY)(pThirdRes->OffsetToData + (DWORD)pFirstDir); //pData->OffsetToData 资源起始位置的RVA //pData->Size 资源的大小 printf(" 资源的起始RVA:%x 资源的大小:%x\n", pData->OffsetToData, pData->Size); //获取到资源的数据了,输出10个字节,用于对比 unsigned char* pRes = (unsigned char *) (RvaToFoa(lpImage, pData->OffsetToData) + lpImage); printf(" "); for (size_t m= 0; m < 10; m++) { printf("%x ", pRes[m]); } printf("\n"); } } } } } ``` 最后修改:2021 年 03 月 01 日 © 允许规范转载 赞 0 如果觉得我的文章对你有用,请随意赞赏