Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed discrepancies in icon hash between YARA and retdec-fileinfo #1006

Merged
merged 1 commit into from
Sep 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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