mirror of
https://github.com/hasherezade/bearparser
synced 2026-06-08 14:32:38 +00:00
375 lines
12 KiB
C++
375 lines
12 KiB
C++
#include "pe/ResourceDirWrapper.h"
|
|
#include "pe/PEFile.h"
|
|
|
|
#define MAX_ENTRIES (-1)
|
|
#define MAX_DEPTH 5
|
|
|
|
/*
|
|
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;
|
|
|
|
|
|
// Each directory contains the 32-bit Name of the entry and an offset,
|
|
// relative to the beginning of the resource directory of the data associated
|
|
// with this directory entry. If the name of the entry is an actual text
|
|
// string instead of an integer Id, then the high order bit of the name field
|
|
// is set to one and the low order 31-bits are an offset, relative to the
|
|
// beginning of the resource directory of the string, which is of type
|
|
// IMAGE_RESOURCE_DIRECTORY_STRING. Otherwise the high bit is clear and the
|
|
// low-order 16-bits are the integer Id that identify this resource directory
|
|
// entry. If the directory entry is yet another resource directory (i.e. a
|
|
// subdirectory), then the high order bit of the offset field will be
|
|
// set to indicate this. Otherwise the high bit is clear and the offset
|
|
// field points to a resource data entry.
|
|
|
|
#define RESOURCE_NAME_IS_STRING 0x80000000
|
|
#define RESOURCE_DATA_IS_DIRECTORY 0x80000000
|
|
|
|
|
|
typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
|
|
union {
|
|
struct {
|
|
DWORD NameOffset:31;
|
|
DWORD NameIsString:1;
|
|
} name;
|
|
DWORD Name;
|
|
WORD Id;
|
|
};
|
|
union {
|
|
DWORD OffsetToData;
|
|
struct {
|
|
DWORD OffsetToDirectory:31;
|
|
DWORD DataIsDirectory:1;
|
|
} dir;
|
|
};
|
|
} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;
|
|
|
|
*/
|
|
//-------------
|
|
|
|
IMAGE_RESOURCE_DIRECTORY* ResourceDirWrapper::mainResourceDir()
|
|
{
|
|
offset_t rva = getDirEntryAddress();
|
|
|
|
BYTE *ptr = m_Exe->getContentAt(rva, Executable::RVA, sizeof(IMAGE_RESOURCE_DIRECTORY));
|
|
return (IMAGE_RESOURCE_DIRECTORY*) ptr;
|
|
}
|
|
|
|
IMAGE_RESOURCE_DIRECTORY* ResourceDirWrapper::resourceDir()
|
|
{
|
|
if (this->rawOff == 0) return mainResourceDir();
|
|
|
|
BYTE *ptr = m_Exe->getContentAt(this->rawOff, Executable::RAW, sizeof(IMAGE_RESOURCE_DIRECTORY));
|
|
return (IMAGE_RESOURCE_DIRECTORY*) ptr;
|
|
}
|
|
|
|
bool ResourceDirWrapper::wrap()
|
|
{
|
|
clear();
|
|
if (this->topEntryID == TOP_ENTRY_ROOT && this->album != NULL) {
|
|
this->album->clear();
|
|
}
|
|
IMAGE_RESOURCE_DIRECTORY* dir = resourceDir();
|
|
if (dir == NULL) return false;
|
|
size_t namesNum = dir->NumberOfNamedEntries;
|
|
size_t idsNum = dir->NumberOfIdEntries;
|
|
|
|
size_t totalEntries = namesNum + idsNum;
|
|
for (size_t i = 0; i < totalEntries && i < MAX_ENTRIES; i++ ) {
|
|
|
|
long topDirId = (this->topEntryID != TOP_ENTRY_ROOT) ? this->topEntryID : long(i) ;
|
|
|
|
//ResourceEntryWrapper(PEFile *pe, ResourceDirWrapper *parentDir, size_t entryNumber, long topEntryId, ResourcesAlbum *resAlbum)
|
|
ResourceEntryWrapper* entry = new ResourceEntryWrapper(this->m_PE, this, i, topDirId, this->album);
|
|
|
|
if (entry->getPtr() == NULL) {
|
|
delete entry;
|
|
break;
|
|
}
|
|
if (this->topEntryID == TOP_ENTRY_ROOT && this->album != NULL) {
|
|
pe::resource_type typeId = static_cast<pe::resource_type>(entry->getID());
|
|
this->album->mapIdToLeafType(i, typeId);
|
|
}
|
|
//this->parsedSize += val;
|
|
this->entries.push_back(entry);
|
|
}
|
|
//printf("Entries: %d\n", getEntriesCount());
|
|
return true;
|
|
}
|
|
|
|
|
|
bufsize_t ResourceDirWrapper::getSize()
|
|
{
|
|
if (getPtr() == NULL) return 0;
|
|
bufsize_t size = sizeof(IMAGE_RESOURCE_DIRECTORY);
|
|
size += getEntriesAreaSize();
|
|
return size;
|
|
}
|
|
|
|
void* ResourceDirWrapper::getFieldPtr(size_t fId, size_t subField)
|
|
{
|
|
IMAGE_RESOURCE_DIRECTORY* d = resourceDir();
|
|
if (d == NULL) return NULL;
|
|
|
|
switch (fId) {
|
|
case CHARACTERISTIC: return &d->Characteristics;
|
|
case TIMESTAMP: return &d->TimeDateStamp;
|
|
case MAJOR_VER: return &d->MajorVersion;
|
|
case MINOR_VER: return &d->MinorVersion;
|
|
case NAMED_ENTRIES_NUM : return &d->NumberOfNamedEntries;
|
|
case ID_ENTRIES_NUM : return &d->NumberOfIdEntries;
|
|
}
|
|
return this->getPtr();
|
|
}
|
|
|
|
bufsize_t ResourceDirWrapper::getFieldSize(size_t fId, size_t subField)
|
|
{
|
|
IMAGE_RESOURCE_DIRECTORY* d = resourceDir();
|
|
if (d == NULL) return 0;
|
|
|
|
// calculate size of the last field separately:
|
|
if (fId == ID_ENTRIES_NUM) {
|
|
void *nextPtr = (&d->NumberOfIdEntries) + 1;
|
|
void *argPtr = &d->NumberOfIdEntries;
|
|
return (BYTE*) nextPtr - (BYTE*)argPtr;
|
|
}
|
|
return DataDirEntryWrapper::getFieldSize(fId, subField);
|
|
}
|
|
|
|
QString ResourceDirWrapper::getFieldName(size_t fieldId)
|
|
{
|
|
switch (fieldId) {
|
|
case CHARACTERISTIC: return "Characteristics";
|
|
case TIMESTAMP: {
|
|
PEFile* myPe = dynamic_cast<PEFile*>(this->m_Exe);
|
|
if (myPe && myPe->isReproBuild()) {
|
|
return "ReproChecksum";
|
|
}
|
|
return "TimeDateStamp";
|
|
}
|
|
case MAJOR_VER: return "MajorVersion";
|
|
case MINOR_VER: return "MinorVersion";
|
|
case NAMED_ENTRIES_NUM : return "NumberOfNamedEntries";
|
|
case ID_ENTRIES_NUM : return "NumberOfIdEntries";
|
|
}
|
|
return getName();
|
|
}
|
|
|
|
//-----------------------------------------------------------------
|
|
|
|
void ResourceEntryWrapper::clear()
|
|
{
|
|
delete childDir;
|
|
this->childDir = NULL;
|
|
//---
|
|
delete childLeaf;
|
|
this->childLeaf = NULL;
|
|
}
|
|
|
|
bool ResourceEntryWrapper::wrap()
|
|
{
|
|
clear();
|
|
//---
|
|
offset_t childRaw = getChildAddress();
|
|
if (childRaw == 0 || childRaw == INVALID_ADDR) return false;
|
|
|
|
if (this->isDir()) {
|
|
long depth = this->parentDir->getDepth() + 1;
|
|
if (depth >= MAX_DEPTH) return false;
|
|
this->childDir = new ResourceDirWrapper(this->m_PE, this->album, childRaw, depth, topEntryID);
|
|
} else {
|
|
this->childLeaf = new ResourceLeafWrapper(m_Exe, childRaw, topEntryID);
|
|
if (this->album != NULL) {
|
|
album->putLeaf(childLeaf, topEntryID);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
IMAGE_RESOURCE_DIRECTORY_ENTRY* ResourceEntryWrapper::getEntryPtr()
|
|
{
|
|
if (this->parentDir == NULL) return NULL;
|
|
uint64_t offset = parentDir->getFieldOffset(ResourceDirWrapper::ID_ENTRIES_NUM);
|
|
if (offset == INVALID_ADDR) return NULL;
|
|
|
|
size_t lastSize = parentDir->getFieldSize(ResourceDirWrapper::ID_ENTRIES_NUM, FIELD_NONE);
|
|
offset += lastSize;
|
|
offset += (this->entryNum * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
|
|
|
|
void *ptr = m_Exe->getContentAt(offset, Executable::RAW, sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
|
|
return (IMAGE_RESOURCE_DIRECTORY_ENTRY*) ptr;
|
|
}
|
|
|
|
//IMAGE_RESOURCE_DIRECTORY_ENTRY
|
|
void* ResourceEntryWrapper::getFieldPtr(size_t fieldId, size_t subField)
|
|
{
|
|
IMAGE_RESOURCE_DIRECTORY_ENTRY* entry = getEntryPtr();
|
|
if (entry == NULL) return NULL;
|
|
|
|
switch (fieldId) {
|
|
case NAME_ID_ADDR:
|
|
return &entry->Name;
|
|
case OFFSET_TO_DATA:
|
|
return &entry->OffsetToData;
|
|
}
|
|
return getPtr();
|
|
}
|
|
|
|
QString ResourceEntryWrapper::getFieldName(size_t fieldId)
|
|
{
|
|
switch (fieldId) {
|
|
case NAME_ID_ADDR:
|
|
return(isByName()) ? "Name": "ID";
|
|
case OFFSET_TO_DATA:
|
|
return "Offset To Data";
|
|
}
|
|
return getName();
|
|
}
|
|
|
|
bool ResourceEntryWrapper::isByName()
|
|
{
|
|
IMAGE_RESOURCE_DIRECTORY_ENTRY* entry = getEntryPtr();
|
|
if (entry == NULL) return false;
|
|
if (entry->NameIsString == 1) return true;
|
|
return false;
|
|
}
|
|
|
|
bool ResourceEntryWrapper::isDir()
|
|
{
|
|
IMAGE_RESOURCE_DIRECTORY_ENTRY* entry = getEntryPtr();
|
|
if (entry == NULL) return false;
|
|
if (entry->DataIsDirectory == 1) return true;
|
|
return false;
|
|
}
|
|
|
|
offset_t ResourceEntryWrapper::getNameOffset()
|
|
{
|
|
IMAGE_RESOURCE_DIRECTORY_ENTRY* entry = getEntryPtr();
|
|
if (entry == NULL) return INVALID_ADDR;
|
|
|
|
if (this->parentDir == NULL) return INVALID_ADDR;
|
|
offset_t fOff = this->parentDir->getOffset(this->parentDir->getPtr());
|
|
if (fOff == INVALID_ADDR) return INVALID_ADDR;
|
|
|
|
if (entry->NameIsString != 1) return INVALID_ADDR;
|
|
return fOff + entry->NameOffset;
|
|
}
|
|
|
|
IMAGE_RESOURCE_DIRECTORY_STRING* ResourceEntryWrapper::getNameStr()
|
|
{
|
|
offset_t nameOff = getNameOffset();
|
|
if (nameOff == INVALID_ADDR) return NULL;
|
|
|
|
const size_t BASIC_SIZE = sizeof(IMAGE_RESOURCE_DIRECTORY_STRING);
|
|
IMAGE_RESOURCE_DIRECTORY_STRING *ptr = (IMAGE_RESOURCE_DIRECTORY_STRING*) this->m_Exe->getContentAt(nameOff, Executable::RAW, BASIC_SIZE);
|
|
return ptr;
|
|
}
|
|
|
|
QString ResourceEntryWrapper::translateType(WORD id)
|
|
{
|
|
switch (id) {
|
|
case pe::RESTYPE_CURSOR : return "Cursor";
|
|
case pe::RESTYPE_FONT :return "Font";
|
|
case pe::RESTYPE_BITMAP : return "Bitmap";
|
|
case pe::RESTYPE_ICON : return "Icon";
|
|
case pe::RESTYPE_MENU : return "Menu";
|
|
case pe::RESTYPE_DIALOG : return "Dialog";
|
|
case pe::RESTYPE_STRING : return "String";
|
|
case pe::RESTYPE_FONTDIR : return "Font Dir";
|
|
case pe::RESTYPE_ACCELERATOR : return "Accelerator";
|
|
case pe::RESTYPE_RCDATA : return "RC Data";
|
|
case pe::RESTYPE_MESSAGETABLE : return "Message Table";
|
|
|
|
case pe::RESTYPE_GROUP_CURSOR : return "Cursors Group";
|
|
case pe::RESTYPE_GROUP_ICON : return "Icons Group";
|
|
case pe::RESTYPE_VERSION : return "Version";
|
|
case pe::RESTYPE_DLGINCLUDE : return "Dlg Include";
|
|
case pe::RESTYPE_PLUGPLAY : return "Plug & Play";
|
|
case pe::RESTYPE_VXD : return "VXD";
|
|
case pe::RESTYPE_ANICURSOR : return "Animated Cursor";
|
|
case pe::RESTYPE_ANIICON : return "Animated Icon";
|
|
case pe::RESTYPE_HTML : return "HTML";
|
|
case pe::RESTYPE_MANIFEST : return "Manifest";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
WORD ResourceEntryWrapper::getID()
|
|
{
|
|
IMAGE_RESOURCE_DIRECTORY_ENTRY* entry = getEntryPtr();
|
|
if (entry == NULL) return 0;
|
|
if (this->isByName()) return 0;
|
|
|
|
return entry->Id;
|
|
}
|
|
|
|
offset_t ResourceEntryWrapper::getChildOffsetToDirectory()
|
|
{
|
|
const IMAGE_RESOURCE_DIRECTORY_ENTRY* entry = getEntryPtr();
|
|
if (!entry) {
|
|
return INVALID_ADDR;
|
|
}
|
|
if (entry->DataIsDirectory) {
|
|
return entry->OffsetToDirectory;
|
|
}
|
|
return entry->OffsetToData;
|
|
}
|
|
|
|
offset_t ResourceEntryWrapper::getChildAddress()
|
|
{
|
|
if (!this->parentDir) return INVALID_ADDR;
|
|
|
|
const offset_t fOff = this->parentDir->getOffset(this->parentDir->mainResourceDir());
|
|
if (fOff == INVALID_ADDR) return INVALID_ADDR;
|
|
|
|
const offset_t childOff = getChildOffsetToDirectory();
|
|
if (childOff == INVALID_ADDR) return INVALID_ADDR;
|
|
|
|
return fOff + childOff;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
IMAGE_RESOURCE_DATA_ENTRY* ResourceLeafWrapper::leafEntryPtr()
|
|
{
|
|
if (this->offset == 0 || this->offset == INVALID_ADDR) return NULL;
|
|
|
|
IMAGE_RESOURCE_DATA_ENTRY* leaf = (IMAGE_RESOURCE_DATA_ENTRY*) this->m_Exe->getContentAt(this->offset, Executable::RAW, sizeof(IMAGE_RESOURCE_DATA_ENTRY));
|
|
return leaf;
|
|
}
|
|
|
|
void* ResourceLeafWrapper::getFieldPtr(size_t fieldId, size_t subField)
|
|
{
|
|
IMAGE_RESOURCE_DATA_ENTRY* leaf = leafEntryPtr();
|
|
if (!leaf) return NULL;
|
|
|
|
switch (fieldId) {
|
|
case OFFSET_TO_DATA: return &leaf->OffsetToData;
|
|
case DATA_SIZE: return &leaf->Size;
|
|
case CODE_PAGE: return &leaf->CodePage;
|
|
case RESERVED: return &leaf->Reserved;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
QString ResourceLeafWrapper::getFieldName(size_t fieldId)
|
|
{
|
|
switch (fieldId) {
|
|
case OFFSET_TO_DATA: return "OffsetToData";
|
|
case DATA_SIZE: return "DataSize";
|
|
case CODE_PAGE: return "CodePage";
|
|
case RESERVED: return "Reserved";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
|