Windows逆向工程提升之IMAGE_RESOURCE_DIRECTORY
- 公开视频 -> 链接点击跳转公开课程
- 博客首页 -> 链接点击跳转博客主页
目录
资源目录概述
什么是资源目录?
资源目录的作用
资源目录的位置
资源目录核心结构
IMAGE_RESOURCE_DIRECTORY
IMAGE_RESOURCE_DIRECTORY_ENTRY
IMAGE_RESOURCE_DATA_ENTRY
资源目录的层次结构
第一层:类型(Type)
第二层:名称(Name)
第三层:语言(Language)
资源目录解析流程
定位资源目录
遍历三层目录
内存布局
资源目录结构(根节点)
资源目录条目(子节点)
字符串名称结构
资源数据条目
资源目录概述
什么是资源目录?
资源目录(Resource Directory)是 PE 文件中用于存储程序非代码/数据资源的结构,例如:
- 图标(ICO)、位图(BMP)、光标(CUR)
- 字符串表(String Table)、对话框模板(Dialog Template)
- 版本信息(Version Info)、菜单(Menu)
资源目录的作用
- 模块化存储:将资源独立于代码,便于管理和本地化。
- 运行时访问:通过 API(如 LoadResource、FindResource)动态加载资源。
- 多语言支持:同一资源可存储多种语言版本。
资源目录的位置
- 资源目录的 RVA 和大小由 IMAGE_DATA_DIRECTORY[IMAGE_DIRECTORY_ENTRY_RESOURCE] 定义。
资源目录核心结构
资源目录采用 三层树形结构,由以下核心结构组成:
IMAGE_RESOURCE_DIRECTORY
typedef struct _IMAGE_RESOURCE_DIRECTORY {DWORD Characteristics; // 保留字段(通常为0)DWORD TimeDateStamp; // 时间戳(编译器生成时间)WORD MajorVersion; // 主版本号WORD MinorVersion; // 次版本号WORD NumberOfNamedEntries; // 具名条目数量(按字符串名称索引)WORD NumberOfIdEntries; // ID条目数量(按整数ID索引)
} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;NumberOfNamedEntries + NumberOfIdEntries = 总条目数。
目按名称字符串或整数 ID 排序:具名条目在前,ID条目在后。
IMAGE_RESOURCE_DIRECTORY_ENTRY
typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {union {struct {DWORD NameOffset:31; // 名称偏移(高位为0时)DWORD NameIsString:1; // 名称是否为字符串(1=字符串,0=整数ID)};DWORD Name; // 整数ID或指向字符串的偏移};union {DWORD OffsetToData; // 指向子目录或资源数据的偏移struct {DWORD OffsetToDirectory:31; // 子目录偏移(高位为1时)DWORD DataIsDirectory:1; // 是否为子目录(1=是,0=资源数据)};};
} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;
IMAGE_RESOURCE_DATA_ENTRY
typedef struct _IMAGE_RESOURCE_DATA_ENTRY {DWORD OffsetToData; // 资源数据的RVA(相对于资源目录基址)DWORD Size; // 资源数据大小(字节)DWORD CodePage; // 代码页(通常为0)DWORD Reserved; // 保留字段
} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;
资源目录的层次结构
第一层:类型(Type)
- 功能:按资源类型分类(如图标、字符串表等)。
- 常见类型ID:
- RT_ICON (3)、RT_BITMAP (2)、RT_STRING (6)
第二层:名称(Name)
- 功能:按资源名称或ID分类(如 IDI_MAIN_ICON)。
- ID资源:使用整数标识(如 101 表示第一个对话框)。
第三层:语言(Language)
- 功能:按语言和子语言分类(如英语、简体中文)。
资源目录解析流程
定位资源目录
- 从 IMAGE_DATA_DIRECTORY[IMAGE_DIRECTORY_ENTRY_RESOURCE] 获取 RVA。
遍历三层目录
Root Directory (Type)├─ Type Entry 1 (e.g., RT_ICON)│ └─ Name Directory│ ├─ Name Entry 1 (e.g., IDI_MAIN)│ │ └─ Language Directory│ │ ├─ Language Entry 1 (e.g., 0x0409)│ │ │ └─ Data Entry (OffsetToData, Size)│ │ └─ ...│ └─ ...└─ Type Entry 2 (e.g., RT_VERSION)└─ ...
内存布局
资源目录结构(根节点)
起始位置:由数据目录IMAGE_DIRECTORY_ENTRY_RESOURCE指定RVA,需转换为FOA访问。
typedef struct _IMAGE_RESOURCE_DIRECTORY {DWORD Characteristics; // 资源标志(通常为0)DWORD TimeDateStamp; // 时间戳WORD MajorVersion; // 主版本号WORD MinorVersion; // 次版本号WORD NumberOfNamedEntries; // 命名条目数量WORD NumberOfIdEntries; // ID条目数量
} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;
- 大小:16字节(4+4+2+2+2+2)
- 位置:资源表起始位置(FOA = RvaToFoa(ResourceDirRva))
- 作用:描述当前层级的资源条目数量和类型。
资源目录条目(子节点)
紧跟在每个IMAGE_RESOURCE_DIRECTORY结构之后的是多个目录条目。
typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {union {struct {DWORD NameOffset:31; // 名称偏移(相对资源表起始地址)DWORD NameIsString:1; // 是否为字符串名称(1=是,0=ID)};DWORD Name; // 资源ID(当NameIsString=0时)};union {DWORD OffsetToData; // 偏移到数据或子目录struct {DWORD OffsetToDirectory:31; // 子目录偏移(相对资源表起始地址)DWORD DataIsDirectory:1; // 是否指向子目录(1=是,0=数据条目)};};
} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;
- 大小:8字节(4+4)
- 布局规则:
- ameIsString=1:条目名称是Unicode字符串,通过NameOffset定位到IMAGE_RESOURCE_DIR_STRING_U结构。
- DataIsDirectory=1:指向下一层级的IMAGE_RESOURCE_DIRECTORY。
- DataIsDirectory=0:指向IMAGE_RESOURCE_DATA_ENTRY。
字符串名称结构
IMAGE_RESOURCE_DIR_STRING_U
typedef struct _IMAGE_RESOURCE_DIR_STRING_U {WORD Length; // 字符串长度(字符数)WCHAR NameString[1]; // Unicode字符串(变长,以NULL结尾)
} IMAGE_RESOURCE_DIR_STRING_U, *PIMAGE_RESOURCE_DIR_STRING_U;
- 大小:2 + Length*2字节
- 位置:资源表起始地址 + NameOffset
资源数据条目
IMAGE_RESOURCE_DATA_ENTRY
typedef struct _IMAGE_RESOURCE_DATA_ENTRY {DWORD OffsetToData; // 资源数据RVADWORD Size; // 资源数据大小DWORD CodePage; // 代码页(通常为0)DWORD Reserved; // 保留字段
} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;
- 大小:16字节(4+4+4+4)
- 位置:资源表起始地址 + OffsetToData
- 作用:指向实际的资源数据(如版本信息、图标、位图等)。