BearParser
Portable Executable parsing library (from PE-bear)
ResourceDirWrapper.cpp
Go to the documentation of this file.
2#include "pe/PEFile.h"
3
4#define MAX_ENTRIES 50
5#define MAX_DEPTH 5
6
7/*
8typedef struct _IMAGE_RESOURCE_DIRECTORY {
9 DWORD Characteristics;
10 DWORD TimeDateStamp;
11 WORD MajorVersion;
12 WORD MinorVersion;
13 WORD NumberOfNamedEntries;
14 WORD NumberOfIdEntries;
15 // IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[];
16} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;
17
18
19 // Each directory contains the 32-bit Name of the entry and an offset,
20 // relative to the beginning of the resource directory of the data associated
21 // with this directory entry. If the name of the entry is an actual text
22 // string instead of an integer Id, then the high order bit of the name field
23 // is set to one and the low order 31-bits are an offset, relative to the
24 // beginning of the resource directory of the string, which is of type
25 // IMAGE_RESOURCE_DIRECTORY_STRING. Otherwise the high bit is clear and the
26 // low-order 16-bits are the integer Id that identify this resource directory
27 // entry. If the directory entry is yet another resource directory (i.e. a
28 // subdirectory), then the high order bit of the offset field will be
29 // set to indicate this. Otherwise the high bit is clear and the offset
30 // field points to a resource data entry.
31
32#define RESOURCE_NAME_IS_STRING 0x80000000
33#define RESOURCE_DATA_IS_DIRECTORY 0x80000000
34
35
36typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
37 union {
38 struct {
39 DWORD NameOffset:31;
40 DWORD NameIsString:1;
41 } name;
42 DWORD Name;
43 WORD Id;
44 };
45 union {
46 DWORD OffsetToData;
47 struct {
48 DWORD OffsetToDirectory:31;
49 DWORD DataIsDirectory:1;
50 } dir;
51 };
52} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;
53
54*/
55//-------------
56
57IMAGE_RESOURCE_DIRECTORY* ResourceDirWrapper::mainResourceDir()
58{
60
61 BYTE *ptr = m_Exe->getContentAt(rva, Executable::RVA, sizeof(IMAGE_RESOURCE_DIRECTORY));
62 return (IMAGE_RESOURCE_DIRECTORY*) ptr;
63}
64
65IMAGE_RESOURCE_DIRECTORY* ResourceDirWrapper::resourceDir()
66{
67 if (this->rawOff == 0) return mainResourceDir();
68
69 BYTE *ptr = m_Exe->getContentAt(this->rawOff, Executable::RAW, sizeof(IMAGE_RESOURCE_DIRECTORY));
70 return (IMAGE_RESOURCE_DIRECTORY*) ptr;
71}
72
74{
75 clear();
76 if (this->topEntryID == TOP_ENTRY_ROOT && this->album != NULL) {
77 this->album->clear();
78 }
79 IMAGE_RESOURCE_DIRECTORY* dir = resourceDir();
80 if (dir == NULL) return false;
81 size_t namesNum = dir->NumberOfNamedEntries;
82 size_t idsNum = dir->NumberOfIdEntries;
83
84 size_t totalEntries = namesNum + idsNum;
85 for (size_t i = 0; i < totalEntries && i < MAX_ENTRIES; i++ ) {
86
87 long topDirId = (this->topEntryID != TOP_ENTRY_ROOT) ? this->topEntryID : long(i) ;
88
89 //ResourceEntryWrapper(PEFile *pe, ResourceDirWrapper *parentDir, size_t entryNumber, long topEntryId, ResourcesAlbum *resAlbum)
90 ResourceEntryWrapper* entry = new ResourceEntryWrapper(this->m_PE, this, i, topDirId, this->album);
91
92 if (entry->getPtr() == NULL) {
93 delete entry;
94 break;
95 }
96 if (this->topEntryID == TOP_ENTRY_ROOT && this->album != NULL) {
97 pe::resource_type typeId = static_cast<pe::resource_type>(entry->getID());
98 this->album->mapIdToLeafType(i, typeId);
99 }
100 //this->parsedSize += val;
101 this->entries.push_back(entry);
102 }
103 //printf("Entries: %d\n", getEntriesCount());
104 return true;
105}
106
107
109{
110 if (getPtr() == NULL) return 0;
111 bufsize_t size = sizeof(IMAGE_RESOURCE_DIRECTORY);
112 size += getEntriesAreaSize();
113 return size;
114}
115
116void* ResourceDirWrapper::getFieldPtr(size_t fId, size_t subField)
117{
118 IMAGE_RESOURCE_DIRECTORY* d = resourceDir();
119 if (d == NULL) return NULL;
120
121 switch (fId) {
122 case CHARACTERISTIC: return &d->Characteristics;
123 case TIMESTAMP: return &d->TimeDateStamp;
124 case MAJOR_VER: return &d->MajorVersion;
125 case MINOR_VER: return &d->MinorVersion;
126 case NAMED_ENTRIES_NUM : return &d->NumberOfNamedEntries;
127 case ID_ENTRIES_NUM : return &d->NumberOfIdEntries;
128 case CHILDREN : return (&d->NumberOfIdEntries) + 1;
129 }
130 return this->getPtr();
131}
132
133QString ResourceDirWrapper::getFieldName(size_t fieldId)
134{
135 switch (fieldId) {
136 case CHARACTERISTIC: return "Characteristics";
137 case TIMESTAMP: return "TimeDateStamp";
138 case MAJOR_VER: return "MajorVersion";
139 case MINOR_VER: return "MinorVersion";
140 case NAMED_ENTRIES_NUM : return "NumberOfNamedEntries";
141 case ID_ENTRIES_NUM : return "NumberOfIdEntries";
142 case CHILDREN : return "Entries";
143 }
144 return getName();
145}
146
147//-----------------------------------------------------------------
148
150{
151 delete childDir;
152 this->childDir = NULL;
153 //---
154 delete childLeaf;
155 this->childLeaf = NULL;
156}
157
159{
160 clear();
161 //---
162 offset_t childRaw = getChildAddress();
163 if (childRaw == 0 || childRaw == INVALID_ADDR) return false;
164
165 if (this->isDir()) {
166 long depth = this->parentDir->getDepth() + 1;
167 if (depth >= MAX_DEPTH) return false;
168 this->childDir = new ResourceDirWrapper(this->m_PE, this->album, childRaw, depth, topEntryID);
169 } else {
170 this->childLeaf = new ResourceLeafWrapper(m_Exe, childRaw, topEntryID);
171 if (this->album != NULL) {
172 album->putLeaf(childLeaf, topEntryID);
173 }
174 }
175 return true;
176}
177
178
179IMAGE_RESOURCE_DIRECTORY_ENTRY* ResourceEntryWrapper::getEntryPtr()
180{
181 if (this->parentDir == NULL) return NULL;
182 uint64_t offset = parentDir->getFieldOffset(ResourceDirWrapper::ID_ENTRIES_NUM);
183 if (offset == INVALID_ADDR) return NULL;
184
185 size_t lastSize = parentDir->getFieldSize(ResourceDirWrapper::ID_ENTRIES_NUM, FIELD_NONE);
186 offset += lastSize;
187 offset += (this->entryNum * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
188
189 void *ptr = m_Exe->getContentAt(offset, Executable::RAW, sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
190 return (IMAGE_RESOURCE_DIRECTORY_ENTRY*) ptr;
191}
192
193//IMAGE_RESOURCE_DIRECTORY_ENTRY
194void* ResourceEntryWrapper::getFieldPtr(size_t fieldId, size_t subField)
195{
196 IMAGE_RESOURCE_DIRECTORY_ENTRY* entry = getEntryPtr();
197 if (entry == NULL) return NULL;
198
199 switch (fieldId) {
200 case NAME_ID_ADDR:
201 return &entry->Name;
202 case OFFSET_TO_DATA:
203 return &entry->OffsetToData;
204 }
205 return getPtr();
206}
207
209{
210 switch (fieldId) {
211 case NAME_ID_ADDR:
212 return(isByName()) ? "Name": "ID";
213 case OFFSET_TO_DATA:
214 return "Offset To Data";
215 }
216 return getName();
217}
218
220{
221 IMAGE_RESOURCE_DIRECTORY_ENTRY* entry = getEntryPtr();
222 if (entry == NULL) return false;
223 if (entry->NameIsString == 1) return true;
224 return false;
225}
226
228{
229 IMAGE_RESOURCE_DIRECTORY_ENTRY* entry = getEntryPtr();
230 if (entry == NULL) return false;
231 if (entry->DataIsDirectory == 1) return true;
232 return false;
233}
234
236{
237 IMAGE_RESOURCE_DIRECTORY_ENTRY* entry = getEntryPtr();
238 if (entry == NULL) return INVALID_ADDR;
239
240 if (this->parentDir == NULL) return INVALID_ADDR;
241 offset_t fOff = this->parentDir->getOffset(this->parentDir->getPtr());
242 if (fOff == INVALID_ADDR) return INVALID_ADDR;
243
244 if (entry->NameIsString != 1) return INVALID_ADDR;
245 return fOff + entry->NameOffset;
246}
247
248IMAGE_RESOURCE_DIRECTORY_STRING* ResourceEntryWrapper::getNameStr()
249{
250 offset_t nameOff = getNameOffset();
251 if (nameOff == INVALID_ADDR) return NULL;
252
253 const size_t BASIC_SIZE = sizeof(IMAGE_RESOURCE_DIRECTORY_STRING);
254 IMAGE_RESOURCE_DIRECTORY_STRING *ptr = (IMAGE_RESOURCE_DIRECTORY_STRING*) this->m_Exe->getContentAt(nameOff, Executable::RAW, BASIC_SIZE);
255 return ptr;
256}
257
259{
260 switch (id) {
261 case pe::RESTYPE_CURSOR : return "Cursor";
262 case pe::RESTYPE_FONT :return "Font";
263 case pe::RESTYPE_BITMAP : return "Bitmap";
264 case pe::RESTYPE_ICON : return "Icon";
265 case pe::RESTYPE_MENU : return "Menu";
266 case pe::RESTYPE_DIALOG : return "Dialog";
267 case pe::RESTYPE_STRING : return "String";
268 case pe::RESTYPE_FONTDIR : return "Font Dir";
269 case pe::RESTYPE_ACCELERATOR : return "Accelerator";
270 case pe::RESTYPE_RCDATA : return "RC Data";
271 case pe::RESTYPE_MESSAGETABLE : return "Message Table";
272
273 case pe::RESTYPE_GROUP_CURSOR : return "Cursors Group";
274 case pe::RESTYPE_GROUP_ICON : return "Icons Group";
275 case pe::RESTYPE_VERSION : return "Version";
276 case pe::RESTYPE_DLGINCLUDE : return "Dlg Include";
277 case pe::RESTYPE_PLUGPLAY : return "Plug & Play";
278 case pe::RESTYPE_VXD : return "VXD";
279 case pe::RESTYPE_ANICURSOR : return "Animated Cursor";
280 case pe::RESTYPE_ANIICON : return "Animated Icon";
281 case pe::RESTYPE_HTML : return "HTML";
282 case pe::RESTYPE_MANIFEST : return "Manifest";
283 }
284 return "";
285}
286
288{
289 IMAGE_RESOURCE_DIRECTORY_ENTRY* entry = getEntryPtr();
290 if (entry == NULL) return 0;
291 if (this->isByName()) return 0;
292
293 return entry->Id;
294}
295
297{
298 const IMAGE_RESOURCE_DIRECTORY_ENTRY* entry = getEntryPtr();
299 if (!entry) {
300 return INVALID_ADDR;
301 }
302 if (entry->DataIsDirectory) {
303 return entry->OffsetToDirectory;
304 }
305 return entry->OffsetToData;
306}
307
309{
310 if (!this->parentDir) return INVALID_ADDR;
311
312 const offset_t fOff = this->parentDir->getOffset(this->parentDir->mainResourceDir());
313 if (fOff == INVALID_ADDR) return INVALID_ADDR;
314
315 const offset_t childOff = getChildOffsetToDirectory();
316 if (childOff == INVALID_ADDR) return INVALID_ADDR;
317
318 return fOff + childOff;
319}
320
321//-------------------------------------------------------------------------
322
323IMAGE_RESOURCE_DATA_ENTRY* ResourceLeafWrapper::leafEntryPtr()
324{
325 if (this->offset == 0 || this->offset == INVALID_ADDR) return NULL;
326
327 IMAGE_RESOURCE_DATA_ENTRY* leaf = (IMAGE_RESOURCE_DATA_ENTRY*) this->m_Exe->getContentAt(this->offset, Executable::RAW, sizeof(IMAGE_RESOURCE_DATA_ENTRY));
328 return leaf;
329}
330
331void* ResourceLeafWrapper::getFieldPtr(size_t fieldId, size_t subField)
332{
333 IMAGE_RESOURCE_DATA_ENTRY* leaf = leafEntryPtr();
334 if (!leaf) return NULL;
335
336 switch (fieldId) {
337 case OFFSET_TO_DATA: return &leaf->OffsetToData;
338 case DATA_SIZE: return &leaf->Size;
339 case CODE_PAGE: return &leaf->CodePage;
340 case RESERVED: return &leaf->Reserved;
341 }
342 return NULL;
343}
344
346{
347 switch (fieldId) {
348 case OFFSET_TO_DATA: return "OffsetToData";
349 case DATA_SIZE: return "DataSize";
350 case CODE_PAGE: return "CodePage";
351 case RESERVED: return "Reserved";
352 }
353 return "";
354}
355
356
uint32_t bufsize_t
const offset_t INVALID_ADDR
uint64_t offset_t
#define FIELD_NONE
#define MAX_DEPTH
#define MAX_ENTRIES
#define TOP_ENTRY_ROOT
Definition: ResourcesAlbum.h:3
offset_t getDirEntryAddress()
virtual bufsize_t getFieldSize(size_t fieldId, size_t subField=FIELD_NONE)
virtual offset_t getFieldOffset(size_t fieldId, size_t subField=FIELD_NONE)
std::vector< ExeNodeWrapper * > entries
virtual void clear()
BYTE * getContentAt(offset_t offset, bufsize_t size, bool allowExceptions=false)
Definition: Executable.h:57
PEFile * m_PE
Definition: PENodeWrapper.h:36
virtual bufsize_t getSize()
virtual QString getFieldName(size_t fieldId)
virtual void * getFieldPtr(size_t fieldId, size_t subField)
virtual void * getPtr()
IMAGE_RESOURCE_DIRECTORY * mainResourceDir()
virtual QString getName()
bufsize_t getEntriesAreaSize()
WORD getID()
virtual QString getFieldName(size_t fieldId)
offset_t getChildAddress()
IMAGE_RESOURCE_DIRECTORY_ENTRY * getEntryPtr()
offset_t getNameOffset()
virtual void clear()
bool isDir()
static QString translateType(WORD id)
bool isByName()
virtual QString getName()
bool wrap()
IMAGE_RESOURCE_DIRECTORY_STRING * getNameStr()
offset_t getChildOffsetToDirectory()
@ NAME_ID_ADDR
@ OFFSET_TO_DATA
virtual void * getPtr()
virtual void * getFieldPtr(size_t fieldId, size_t subField=FIELD_NONE)
IMAGE_RESOURCE_DATA_ENTRY * leafEntryPtr()
virtual void * getFieldPtr(size_t fieldId, size_t subField)
virtual QString getFieldName(size_t fieldId)
void mapIdToLeafType(long topId, pe::resource_type leafType)
void putLeaf(ResourceLeafWrapper *leaf, long topEntryId)