PE 文件解析5-数据目录[资源表]
本帖最后由 appsion 于 2020-11-3 12:33 编辑PE 文件解析5-数据目录[资源表]
新手学习PE文件解析记录,持续更新. 部分参考来源于网络, 无法逐一标注, 如果侵权,请及时联系. 如有错误请指正,误喷.
上文连接: https://www.52pojie.cn/thread-1295307-1-1.html
资源树分为三层:
第一层 资源类型的数量
第二层 资源的数量
第三层 资源数据的数量
示意图:
结构体: IMAGE_RESOURCE_DIRECTORY
说明: 资源目录表
头文件: winnt.h
帮助文档: 仅存在于头文件, 没有帮助文档
参考文档: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#resource-directory-table
typedef struct _IMAGE_RESOURCE_DIRECTORY
{
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
WORD NumberOfNamedEntries;
WORD NumberOfIdEntries;
//IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[];
} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;
参数说明: 仅供参考, 详细说明请参考原文.
Characteristics
资源描述
TimeDateStamp
时间日期戳
MajorVersion
资源主要版本
MinorVersion
资源次要版本
NumberOfNamedEntries
资源用字符串命名的数量.
NumberOfIdEntries
资源用ID命名的数量.
结构体: IMAGE_RESOURCE_DIRECTORY_ENTRY
说明: 资源目录项
头文件: winnt.h
帮助文档: 仅存在于头文件, 没有帮助文档
参考文档: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#resource-directory-entries
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;
参数说明: 仅供参考, 详细说明请参考原文.
DUMMYUNIONNAME
第一层: 资源类型标识, 第二层: 资源标识, 第三层: 国家地区语言标识
DUMMYUNIONNAME.DUMMYSTRUCTNAME.NameOffset
DUMMYUNIONNAME 的低31位值.
当 NameIsString == 0 时表示资源目录类型. 也就是 DUMMYUNIONNAME.Id.
当 NameIsString == 1 时表示资源目录名称的偏移. IMAGE_RESOURCE_DIR_STRING_U 结构. 相对于资源目录表(IMAGE_RESOURCE_DIRECTORY)的起始位置 + NameOffset 的偏移.
DUMMYUNIONNAME.DUMMYSTRUCTNAME.NameIsString
DUMMYUNIONNAME 的最高位值.用于判断 NameOffset 为名称还是资源类型.
DUMMYUNIONNAME.Name
DUMMYUNIONNAME 的值.
DUMMYUNIONNAME.Id
资源类型的ID.
DUMMYUNIONNAME2
第一层: 资源偏移, 第二层: 资源数据偏移, 第三层: 资源数据的偏移
DUMMYUNIONNAME2.OffsetToData
DUMMYUNIONNAME2 的值
DUMMYUNIONNAME2.DUMMYSTRUCTNAME2.OffsetToDirectory
DUMMYUNIONNAME2 值的低31位值.
当 DataIsDirectory == 0 时, 表示资源数据的偏移, IMAGE_RESOURCE_DATA_ENTRY 结构.
当 DataIsDirectory == 1 时, 表示资源目录的偏移, IMAGE_RESOURCE_DIRECTORY 结构. 相对资源目录表(IMAGE_RESOURCE_DIRECTORY)的起始位置 + OffsetToDirectory偏移.
DUMMYUNIONNAME2.DUMMYSTRUCTNAME2.DataIsDirectory
DUMMYUNIONNAME2 值的最高位值
LCID, 区域设置标识符
参考地址:
https://docs.microsoft.com/zh-cn/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c#Appendix_A_8
https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/70feba9f-294e-491e-b6eb-56532684c37f
资源类型
原文地址: https://docs.microsoft.com/en-us/windows/win32/menurc/resource-types
RT_CURSOR1光标资源
RT_BITMAP2位图资源
RT_ICON3图标资源
RT_MENU4菜单资源
RT_DIALOG5对话框资源
RT_STRING6字符串表条目。
RT_FONTDIR7字体目录资源。
RT_FONT8字体资源
RT_ACCELERATOR9加速器表。
RT_RCDATA10应用程序定义的资源(原始数据)
RT_MESSAGETABLE11消息表条目。
RT_GROUP_CURSOR12与硬件无关的游标资源。
RT_GROUP_ICON14与硬件无关的图标资源。
RT_VERSION16版本资源。
RT_DLGINCLUDE17允许资源编辑工具将字符串与.rc文件关联。 通常,字符串是提供符号名称的头文件的名称。 资源编译器解析该字符串,但忽略该值。 例如,1 DLGINCLUDE“ MyFile.h”
RT_PLUGPLAY19即插即用资源。
RT_VXD20VXD。
RT_ANICURSOR21动画的光标。
RT_ANIICON22动画的图标。
RT_HTML23HTML资源。
RT_MANIFEST24并排组装清单。
结构体: IMAGE_RESOURCE_DATA_ENTRY
说明: 资源数据
头文件: winnt.h
帮助文档: 仅存在于头文件, 没有帮助文档
参考文档: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#resource-data-entry
typedef struct _IMAGE_RESOURCE_DATA_ENTRY
{
DWORD OffsetToData;
DWORD Size;
DWORD CodePage;
DWORD Reserved;
} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;
参数说明: 仅供参考, 详细说明请参考原文.
OffsetToData
资源数据的RVA
Size
资源数据大小
CodePage
代码页
Reserved
保留
结构体: IMAGE_RESOURCE_DIR_STRING_U
说明: 资源目录项名称
头文件: winnt.h
帮助文档: 仅存在于头文件, 没有帮助文档
参考文档:https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#resource-directory-string
typedef struct _IMAGE_RESOURCE_DIR_STRING_U
{
WORD Length;
WCHAR NameString[ 1 ];
} IMAGE_RESOURCE_DIR_STRING_U, *PIMAGE_RESOURCE_DIR_STRING_U;
参数说明: 仅供参考, 详细说明请参考原文.
Length
字符串资源目录项名称的长度.
NameString
资源目录项名称. 该字符串为Unicode字符串.
5.1 获取资源目录树
注: 资源分为二种, 字符串命名的资源和ID命名的资源
示意图
注释说明:
// 资源总数量
IMAGE_RESOURCE_DIRECTORY.NumberOfIdEntries + IMAGE_RESOURCE_DIRECTORY.NumberOfNamedEntries
// 节表
SectionHead
// 节表数量
SectionCount
// 资源表RVA
m_DataDirRVA
// RVA 转 FOA,详情说明参见前面章节.
RVAToRaw(SectionHead, SectionCount, m_DataDirRVA)
// 文件指针
m_DataBuff
// 资源FOA
DWORD ResourceFOA = (DWORD)m_DataBuff + RVAToRaw(SectionHead, SectionCount, m_DataDirRVA);
// 获取资源树
GetResourceEntry(ResourceFOA, 0, 0);
// 参数说明:
// ResourceFOA, 资源FOA
// ResourceFOAOffset, 资源偏移
// depth, 资源树深度
void GetResourceEntry(DWORD ResourceFOA, DWORD ResourceFOAOffset, int depth)
{
// 获取节表
int SectionCount = 0;
IMAGE_SECTION_HEADER *SectionHead = GetSectionHead(m_DataBuff, SectionCount);
// 资源树
IMAGE_RESOURCE_DIRECTORY *ResourceDir = (IMAGE_RESOURCE_DIRECTORY*)(ResourceFOA + ResourceFOAOffset);
// 遍历资源
for (int i = 0; i < ResourceDir->NumberOfIdEntries + ResourceDir->NumberOfNamedEntries; i++)
{
// 获取资源
IMAGE_RESOURCE_DIRECTORY_ENTRY ResourceEntry = ((IMAGE_RESOURCE_DIRECTORY_ENTRY*)((DWORD)ResourceDir + sizeof(IMAGE_RESOURCE_DIRECTORY)));
// 获取资源名称
CString RCTypeName;
int RCTypeId = 0;
GetResourceName(ResourceFOA, &ResourceEntry, depth, RCTypeName, RCTypeId);
// 最高位为1时, 低32位为 IMAGE_RESOURCE_DIRECTORY 结构的偏移
// 最高位为0时, 低32位为 IMAGE_RESOURCE_DATA_ENTRY 结构的偏移
if (ResourceEntry.DataIsDirectory)
{
GetResourceEntry(ResourceFOA, ResourceEntry.OffsetToDirectory, depth + 1);
}
else
{
// LCID
m_ResourceData->ResourceLCID = ResourceEntry.Id;
// 资源数据
IMAGE_RESOURCE_DATA_ENTRY * ResourceData = (IMAGE_RESOURCE_DATA_ENTRY *)(ResourceFOA + ResourceEntry.OffsetToDirectory);
m_ResourceData->ResourceDataRVA = ResourceData->OffsetToData;
m_ResourceData->ResourceDataFOA = RVAToRaw(SectionHead, SectionCount, ResourceData->OffsetToData);
m_ResourceData->ResourceDataSize = ResourceData->Size;
}
}
}
// 资源类型
void GetResourceName(DWORD ResourceFOA, IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceEntry, int depth, CString &RCTypeName, int &RCTypeId)
{
CString Tempstr;
if (ResourceEntry->NameIsString)
{
IMAGE_RESOURCE_DIR_STRING_U *ResourceDirName = (IMAGE_RESOURCE_DIR_STRING_U*)(ResourceFOA + ResourceEntry->NameOffset);
WCHAR *Buff = new WCHAR;
memset(Buff, 0, (ResourceDirName->Length + 1) * 2);
wcsncpy_s(Buff, ResourceDirName->Length + 1, ResourceDirName->NameString, ResourceDirName->Length);
Tempstr = (PWCHAR)Buff;
delete Buff;
}
else
{
switch (depth)
{
case 0:
switch (ResourceEntry->Id)
{
case 1: Tempstr = "光标"; break;
case 2: Tempstr = "位图"; break;
case 3: Tempstr = "图标"; break;
case 4: Tempstr = "菜单"; break;
case 5: Tempstr = "对话框"; break;
case 6: Tempstr = "字符串"; break;
case 7: Tempstr = "字体目录"; break;
case 8: Tempstr = "字体"; break;
case 9: Tempstr = "加速键"; break;
case 10: Tempstr = "RC数据"; break;
case 11: Tempstr = "消息表"; break;
case 12: Tempstr = "光标组"; break;
case 14: Tempstr = "图标组"; break;
case 16: Tempstr = "版本信息"; break;
case 23: Tempstr = "HTML"; break;
case 24: Tempstr = "清单"; break;
default: Tempstr.Format("%d", ResourceEntry->Id); break;
}
break;
case 1: Tempstr.Format("%d", ResourceEntry->Id); break;
case 2:
Tempstr.Format("区域语言标识: 0x%04X", ResourceEntry->Id);
break;
default:
Tempstr = "未知";
break;
}
}
RCTypeName = Tempstr;
} 挺不错,来看看 虽然看不懂,但能知道楼主博学,楼主真牛,老湿这波操作稳了。 谢谢您的鼓励,挺不错 感谢分享!!!!!!!! 谢谢分享,最近正好有用 挺不错,虽然看不懂,但博主牛逼 非常好的学习资料,支持分享 感谢楼主分享,学习了 感谢,向大佬学习
页:
[1]
2