Skip to content

Commit

Permalink
Fixed discrepancies in icon hash between YARA and retdec-fileinfo
Browse files Browse the repository at this point in the history
  • Loading branch information
Ladislav Zezula authored and PeterMatula committed Sep 1, 2021
1 parent d439db3 commit 6a793d1
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 8 deletions.
17 changes: 17 additions & 0 deletions include/retdec/fileformat/types/resource_table/resource_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,22 @@
namespace retdec {
namespace fileformat {

/**
* Definition of the icon priority structure
*/

struct IconPriorityEntry
{
IconPriorityEntry(std::uint16_t width, std::uint16_t bitCount)
{
iconWidth = width;
iconBitCount = bitCount;
}

std::uint16_t iconWidth;
std::uint16_t iconBitCount;
};

/**
* Table of resources
*/
Expand Down Expand Up @@ -63,6 +79,7 @@ class ResourceTable
const std::string& getResourceIconhashSha256() const;
const std::string& getResourceIconPerceptualAvgHash() const;
const ResourceIconGroup* getPriorResourceIconGroup() const;
const ResourceIcon* getIconForIconHash() const;
/// @}

/// @name Iterators
Expand Down
116 changes: 109 additions & 7 deletions src/fileformat/types/resource_table/resource_table.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,27 @@ struct VersionInfoHeader
namespace retdec {
namespace fileformat {

// Icon priority from YARA
static const std::vector<IconPriorityEntry> iconPriority_YARA =
{
{32, 32},
{24, 32},
{48, 32},
{32, 8},
{16, 32},
{64, 32},
{24, 8},
{48, 8},
{16, 8},
{64, 8},
{96, 32},
{96, 8},
{128, 32},
{128, 8},
{256, 32},
{256, 8}
};

/**
* Compute icon perceptual hashes
* @param icon Icon to compute the hash of
Expand Down Expand Up @@ -368,6 +389,93 @@ const ResourceIconGroup* ResourceTable::getPriorResourceIconGroup() const
return nullptr;
}

/**
* Get the icon that will be used for calculation of the icon hash.
* This algorithm is supposed to be YARA-compatible
* @return Prior icon
*/
const ResourceIcon* ResourceTable::getIconForIconHash() const
{
ResourceIconGroup * iconGroup = nullptr;
ResourceIcon * theBestIcon = nullptr;
std::size_t number_icon_ordinals = 0;
std::size_t best_icon_priority = 0xFF;

//
// Step 1: Get the suitable icon group. YARA takes the first icon group
// YARA: Done in module "pe.c", function "pe_collect_icon_ordinals()"
//

if(iconGroups.size())
{
iconGroup = iconGroups[0];
iconGroup->getNumberOfEntries(number_icon_ordinals);
}

//
// Step 2: Parse all icons in the PE and retrieve the
// YARA: Done in module "pe.c", function "pe_collect_icon_data()"
//

if(iconGroup && number_icon_ordinals)
{
for(ResourceIcon * icon : icons)
{
std::uint32_t icon_data_offset = icon->getOffset();
std::uint32_t icon_data_size = icon->getSizeInFile();

// Skip icons with zero offset or zero size
if(icon_data_offset == 0 || icon_data_size == 0 /* || icon_data_offset > pe->data_size */)
continue;

// Parse all icons in the group
for(std::size_t i = 0; i < number_icon_ordinals; i++)
{
std::size_t nameIdInGroup = 0;
std::size_t nameIdOfIcon = 0;
std::uint16_t iconWidth = 0;
std::uint16_t iconHeight = 0;
std::uint16_t iconBitCount = 0;

// Skip icons that are of different ID
iconGroup->getEntryNameID(i, nameIdInGroup);
icon->getNameId(nameIdOfIcon);
if(nameIdOfIcon != nameIdInGroup /* || fits_in_pe() */)
continue;

// Retrieve size and bit count
iconGroup->getEntryWidth(i, iconWidth);
iconGroup->getEntryHeight(i, iconHeight);
iconGroup->getEntryBitCount(i, iconBitCount);

// YARA ignores any icons that have width != height
if(iconWidth == iconHeight)
{
for(size_t j = 0; j < iconPriority_YARA.size() && j < best_icon_priority; j++)
{
if(iconWidth == iconPriority_YARA[j].iconWidth && iconBitCount == iconPriority_YARA[j].iconBitCount)
{
best_icon_priority = j;
theBestIcon = icon;
break;
}
}
}

// Set the current icon as the best one
if(!theBestIcon && icons.size())
{
best_icon_priority = iconPriority_YARA.size();
theBestIcon = icon;
}
}
}
}

// Return whatever best icon we found
return theBestIcon;
}

/**
* Get begin iterator
* @return Begin iterator
Expand All @@ -393,13 +501,7 @@ void ResourceTable::computeIconHashes()
{
std::vector<std::uint8_t> iconHashBytes;

auto priorGroup = getPriorResourceIconGroup();
if(!priorGroup)
{
return;
}

auto priorIcon = priorGroup->getPriorIcon();
auto priorIcon = getIconForIconHash();
if(!priorIcon)
{
return;
Expand Down
2 changes: 1 addition & 1 deletion src/pelib/ResourceDirectory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ namespace PeLib

// No data or invalid leaf
if(entry.OffsetToData == 0 && entry.Size == 0)
return ERROR_INVALID_FILE;
return ERROR_SKIP_RESOURCE; // Be in sync with YARA
if(entry.OffsetToData > sizeOfImage || entry.Size > sizeOfImage)
return ERROR_NONE;
if((uiRsrcRva + entry.OffsetToData) >= sizeOfImage || (uiRsrcRva + entry.OffsetToData + entry.Size) > sizeOfImage)
Expand Down

0 comments on commit 6a793d1

Please sign in to comment.