滴水三期 PE 资源表解析
在PE(Portable Executable)文件结构中,资源表(Resource Table)位于可选头的数据目录数组(DataDirectory)第3项(索引2),通过IMAGE_DIRECTORY_ENTRY_RESOURCE标识。其RVA地址存储在OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress中。
树状组织结构
资源根目录
├─ 类型目录(RT_ICON/RT_BITMAP/RT_STRING等)
│ ├─ 名称/ID目录
│ │ └─ 语言目录
│ └─ ...
├─ 版本信息(VS_VERSION_INFO)
└─ 其他自定义资源
资源目录:
typedef struct _IMAGE_RESOURCE_DIRECTORY {
DWORD Characteristics;//资源属性
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
WORD NumberOfNamedEntries;
WORD NumberOfIdEntries;
} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_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;
数据项
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
内存遍历流程

编写程序,定位某个资源在PE文件中的位置代码如下:
void Resource()
{
int fileSize = 0;
DWORD ResourceTableAddress = 0;
LPVOID pFileBuffer = NULL;
//将文件读取到缓冲区
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
PIMAGE_RESOURCE_DIRECTORY ResourceTable, ResourceTable_Buf, ResourceTable2, ResourceTable3 = NULL;//资源表
fileSize = ReadPEFile(FilePath, &pFileBuffer);
if (fileSize == 0)
{
printf("ReadPEFile失败!!\n");
}
//DOS头
pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
//NT头
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
//标准PE头
pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
//可选PE头
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
//首个节表
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
//定位资源表
ResourceTableAddress = RvaToFileOffset(pFileBuffer, pOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
ResourceTable = (PIMAGE_RESOURCE_DIRECTORY)((PBYTE)pFileBuffer + ResourceTableAddress);
ResourceTable_Buf = ResourceTable;//备份数据方便后面计算用
DWORD ResourceNumber = ResourceTable->NumberOfIdEntries + ResourceTable->NumberOfNamedEntries;
//遍历一层目录
for (int i = 0; i < ResourceNumber; i++)
{
PIMAGE_RESOURCE_DIRECTORY_ENTRY Data = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((PBYTE)ResourceTable + 0x10+ i * 0x08);
if (!Data->NameIsString)
{
printf("Data->Id: %d\n", Data->Id);
}
else
{
PIMAGE_RESOURCE_DIR_STRING_U pstcString = (PIMAGE_RESOURCE_DIR_STRING_U)((DWORD)ResourceTable_Buf + Data->NameOffset);
WCHAR szStr[MAX_PATH] = { 0 };
memcpy_s(szStr, MAX_PATH, pstcString->NameString, pstcString->Length * sizeof(WCHAR));
printf("资源字符串: %ls\n", szStr);
}
//遍历二层目录
ResourceTable2= (PIMAGE_RESOURCE_DIRECTORY)((PBYTE)ResourceTable_Buf + Data->OffsetToDirectory);
DWORD Number2 = ResourceTable2->NumberOfIdEntries + ResourceTable2->NumberOfNamedEntries;
printf("Number2->%d\n", Number2);
for (int t = 0; t < Number2; t++)
{
PIMAGE_RESOURCE_DIRECTORY_ENTRY Data2 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((PBYTE)ResourceTable2 + 0x10 + t * 0x08);
if (!Data2->NameIsString)
{
printf("Data2->Id: %d\n", Data2->Id);
}
else
{
PIMAGE_RESOURCE_DIR_STRING_U pstcString = (PIMAGE_RESOURCE_DIR_STRING_U)((DWORD)ResourceTable_Buf + Data2->NameOffset);
WCHAR szStr[MAX_PATH] = { 0 };
memcpy_s(szStr, MAX_PATH, pstcString->NameString, pstcString->Length * sizeof(WCHAR));
printf("资源字符串: %ls\n", szStr);
}
遍历三层目录
ResourceTable3 = (PIMAGE_RESOURCE_DIRECTORY)((PBYTE)ResourceTable_Buf + Data2->OffsetToDirectory);
DWORD Number3 = ResourceTable3->NumberOfIdEntries + ResourceTable3->NumberOfNamedEntries;
printf("Number3->%d\n", Number3);
for (int C = 0; C < Number3; C++)
{
//获取数据条目地址
PIMAGE_RESOURCE_DIRECTORY_ENTRY Data3 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((PBYTE)ResourceTable3 + 0x10 + C * 0x08);
PIMAGE_DATA_DIRECTORY DATA_DIRE = (PIMAGE_DATA_DIRECTORY)((PBYTE)ResourceTable_Buf + Data3->OffsetToDirectory);
printf("->->->数据RVA:%x\t数据大小:%x\n", DATA_DIRE->VirtualAddress, DATA_DIRE->Size);
}
}
}
}

浙公网安备 33010602011771号