2.8 PE structure: detailed analysis of resource table

In Windows PE, resources refer to some fixed data collections stored in executable files, such as icons, dialog boxes, strings, bitmaps, version information, etc. Each resource in the PE file will be assigned a corresponding unique resource ID so that they can be easily found and called at runtime. The resources in the PE file are organized into a tree structure, in which the top level is the root node (Root), the next level is the resource type (Type), the next level is the resource name (Name), and finally the actual resource content.

PIMAGE_RESOURCE_DIRECTORY is a structure type in Windows PE executable files. It is used to describe the tree structure of resources (Resource), which includes the type (Type), name (Name) and language (Language) of each resource, as well as the downward pointing The address and related information of the first-level PE resource directory.

typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY
{
    
    
    union {
    
    
        struct {
    
    
            DWORD NameOffset:31;
            DWORD NameIsString:1;
        } DUMMYSTRUCTNAME;
        DWORD   Name;
        WORD    Id;
    } DUMMYUNIONNAME;
    union {
    
    
        DWORD   OffsetToData;
        struct {
    
    
            DWORD   OffsetToDirectory:31;
            DWORD   DataIsDirectory:1;
        } DUMMYSTRUCTNAME2;
    } DUMMYUNIONNAME2;
} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;

PIMAGE_RESOURCE_DIRECTORY describes the directory structure of Windows PE resources. Each resource directory includes the following fields:

  • Characteristics: Specify the attributes of the directory, such as whether naming is allowed, whether ID is allowed, etc.;
  • TimeDateStamp: Specify the timestamp of the directory;
  • MajorVersion/MinorVersion: Specify the highest and lowest version allowed in the PE file;
  • NumberOfNamedEntries: Specifies the number of named resource entries in the directory;
  • NumberOfIdEntries: Specifies the number of resource ID types;
  • PIMAGE_RESOURCE_DIRECTORY_ENTRY: Pointer, pointing to the resource entry table, that is, the entry address of each resource in the PE file.
  • PIMAGE_RESOURCE_DIRECTORY_ENTRY is used to reference the name, type and language information of the resource in the PE file. It includes Name/Id: the name or ID of the specified resource, which is searched based on the narrowed-down priority. The priority of ID is higher than the name;
  • OffsetToData: Points to the data offset address of the resource or the address of its Resource Data Entry.

When parsing, readers usually need to PIMAGE_DATA_DIRECTORYlocate the resource table in the data directory table, traverse each node in the data directory IMAGE_DIRECTORY_ENTRY_RESOURCEthrough a loop , and finally output the resource information. This output code is as follows;PIMAGE_RESOURCE_DIRECTORY_ENTRY

// --------------------------------------------------
// 定义资源表解析结构
// --------------------------------------------------
static char* szResName[0x11] = {
    
     0, (char*)"鼠标指针", (char*)"位图", (char*)"图标", (char*)"菜单", (char*)"对话框", (char*)"字符串列表", (char*)"字体目录", (char*)"字体", (char*)"快捷键", (char*)"非格式化资源", (char*)"消息列表", (char*)"鼠标指针组", (char*)"zz", (char*)"图标组", (char*)"xx", (char*)"版本信息" };


int main(int argc, char * argv[])
{
    
    
    BOOL PE = IsPeFile(OpenPeFile("c://pe/x86.exe"), 0);

    if (PE == TRUE)
    {
    
    
        // 获取数据目录表
        PIMAGE_DATA_DIRECTORY pData = NtHeader->OptionalHeader.DataDirectory;

        // 获取到资源目录表
        pData = &(pData[IMAGE_DIRECTORY_ENTRY_RESOURCE]);

        // 获取资源目录表的偏移
        DWORD dwResOffset = RVAtoFOA(pData->VirtualAddress);

        // 获取到资源目录表
        PIMAGE_RESOURCE_DIRECTORY pRes = (PIMAGE_RESOURCE_DIRECTORY)(GlobalFileBase + dwResOffset);

        // 获取紧跟着的IMAGE_RESOURCE_DIRECTORY_ENTRY的个数
        DWORD dwResSize = pRes->NumberOfNamedEntries + pRes->NumberOfIdEntries;

        // 获取到PIMAGE_RESOURCE_DIRECTORY_ENTRY 
        PIMAGE_RESOURCE_DIRECTORY_ENTRY  pResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pRes + 1);

        printf("资源类型ID \t 类型 \n");

        for (DWORD i = 0; i < dwResSize; i++)
        {
    
    

            // 如果为0则执行
            if (!pResEntry[i].NameIsString)
            {
    
    
                if (pResEntry[i].Id < 0x11)
                {
    
    
                    // printf("资源类型ID: %p --> 类型: %s\n", pResEntry[i].Id, szResName[pResEntry[i].Id]);
                    printf("%p \t %s \n", pResEntry[i].Id, szResName[pResEntry[i].Id]);
                }
                else
                {
    
    
                    char  type[20];
                    sprintf_s(type, "%d", pResEntry[i].Id);
                    // printf("资源类型ID: %p --> 类型: %s\n", pResEntry[i].Id, type);
                    printf("%p \t %s \n", pResEntry[i].Id, type);
                }
            }
            // 如果为1则执行
            else
            {
    
    
                PIMAGE_RESOURCE_DIR_STRING_U pstcString = (PIMAGE_RESOURCE_DIR_STRING_U)((DWORD)pRes + pResEntry[i].NameOffset);
                WCHAR szStr[MAX_PATH] = {
    
     0 };
                memcpy_s(szStr, MAX_PATH, pstcString->NameString, pstcString->Length * sizeof(WCHAR));
                // printf("资源字符串: %ls\n", szStr);
            }
        }
    }
    else
    {
    
    
        printf("非标准程序 \n");
    }

    system("pause");
    return 0;
}

Compile and run the above program fragment, and the reader can see all the resource information contained in the current program. For simplicity and usability, no recursive resources are output here. Only the first layer is output. The output rendering is as follows;

Author of this article: Wang Rui
Link to this article: https://www.lyshark.com/post/6532d336.html
Copyright Statement: Unless otherwise stated, all articles on this blog adopt the BY-NC-SA license agreement. Please indicate the source!

Guess you like

Origin blog.csdn.net/lyshark_csdn/article/details/132753384