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

Add icons array to PE module #957

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions CONTRIBUTORS
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
Anthony Desnos <[email protected]>
Christian Blichmann <[email protected]>
Hilko Bengen <[email protected]>
Jason Garman <[email protected]>
Joachim Metz <[email protected]>
Karl Hiramoto <[email protected]>
Mike Wiacek <[email protected]>
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ awesome list of [YARA-related stuff](https://github.com/InQuest/awesome-yara).
* [BinaryAlert](https://github.com/airbnb/binaryalert)
* [Blue Coat](http://www.bluecoat.com/products/malware-analysis-appliance)
* [Blueliv](http://www.blueliv.com)
* [Carbon Black](https://www.carbonblack.com)
* [Conix](http://www.conix.fr)
* [CrowdStrike FMS](https://github.com/CrowdStrike/CrowdFMS)
* [Cuckoo Sandbox](https://github.com/cuckoosandbox/cuckoo)
Expand Down
43 changes: 43 additions & 0 deletions docs/modules/pe.rst
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,49 @@ Reference

*Example: pe.data_directories[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].virtual_address != 0*

.. c:type:: number_of_icons

Number of "displayable" icons in the PE. This only counts icons that are considered
by Windows Explorer when viewing the directory containing the PE file or displaying
file properties on the PE file.

.. c:type:: icons

A zero-based array of icon objects, one for each "displayable" icon in the PE.
Individual icons can be accessed by using the [] operator. Each icon object has
the following attributes:

.. c:member:: width

Width of the icon image in pixels (1-256).

.. c:member:: height

Height of the icon image in pixels (1-256).

.. c:member:: color_bit_count

Number of bits in the color channel for this icon image (for example,
8 bit == 256 colors)

.. c:member:: color_planes

Number of color planes in the icon image.

.. c:member:: ordinal

The icon ordinal where the image can be found in the PE file.

.. c:member:: data

The icon image data as a string. Note that BMP formatted images do not
include the BITMAPINFOHEADER structure, and this structure has to be
recreated using the above metadata before the image can be displayed
properly. See the `description of the icon file format
<https://en.wikipedia.org/wiki/ICO_(file_format)>`_ for more information.
PNG formatted images are included in their entirety.


.. c:type:: number_of_sections

Number of sections in the PE.
Expand Down
22 changes: 22 additions & 0 deletions libyara/include/yara/pe.h
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,28 @@ typedef struct _RICH_SIGNATURE {
#define RICH_DANS 0x536e6144 // "DanS"
#define RICH_RICH 0x68636952 // "Rich"

//
// Group Icon directory
// https://blogs.msdn.microsoft.com/oldnewthing/20120720-00/?p=7083
//

typedef struct _PE_GROUP_ICON_DIRECTORY_ENTRY {
BYTE bWidth; // this will be \x00 for 256 byte wide icons
BYTE bHeight; // this will be \x00 for 256 byte high icons
BYTE bColorCount;
BYTE bReserved;
WORD wPlanes;
WORD wBitCount;
DWORD dwBytesInRes;
WORD nId;
} PE_GROUP_ICON_DIRECTORY_ENTRY, *PPE_GROUP_ICON_DIRECTORY_ENTRY;

typedef struct _PE_GROUP_ICON_DIRECTORY {
WORD idReserved;
WORD idType;
WORD idCount;
PE_GROUP_ICON_DIRECTORY_ENTRY idEntries[0];
} PE_GROUP_ICON_DIRECTORY, *PPE_GROUP_ICON_DIRECTORY;

#pragma pack(pop)
#endif
171 changes: 170 additions & 1 deletion libyara/modules/pe.c
Original file line number Diff line number Diff line change
Expand Up @@ -1348,6 +1348,161 @@ void pe_parse_certificates(

#endif // defined(HAVE_LIBCRYPTO)

//
// Collect icons and add them to the PE structure
//

typedef struct icon_callback_t {
PE *pe;
int number_icon_ordinals;
int64_t icon_entry_offset;
int64_t *data_offset_list;
} icon_callback_t;

int pe_collect_icon_data(
PIMAGE_RESOURCE_DATA_ENTRY rsrc_data,
int rsrc_type,
int rsrc_id,
int rsrc_language,
uint8_t* type_string,
uint8_t* name_string,
uint8_t* lang_string,
struct icon_callback_t *callback)
{
PE *pe = callback->pe;
PE_GROUP_ICON_DIRECTORY_ENTRY* icon_entry;
int i;
int64_t icon_data_offset;

if (rsrc_type != RESOURCE_TYPE_ICON)
return RESOURCE_CALLBACK_CONTINUE;

int64_t icon_entry_offset = callback->icon_entry_offset;
for (i = 0; i < callback->number_icon_ordinals; i++) {
icon_entry = (PE_GROUP_ICON_DIRECTORY_ENTRY*) (pe->data + icon_entry_offset);

icon_entry_offset += sizeof(PE_GROUP_ICON_DIRECTORY_ENTRY);
icon_data_offset = pe_rva_to_offset(pe, yr_le32toh(rsrc_data->OffsetToData));

if (icon_entry->nId == rsrc_id && icon_entry->dwBytesInRes == rsrc_data->Size
&& fits_in_pe(pe, (void*) (pe->data + icon_data_offset), rsrc_data->Size)) {
callback->data_offset_list[i] = icon_data_offset;
break;
}
}

return RESOURCE_CALLBACK_CONTINUE;
}


int pe_collect_icon_ordinals(
PIMAGE_RESOURCE_DATA_ENTRY rsrc_data,
int rsrc_type,
int rsrc_id,
int rsrc_language,
uint8_t* type_string,
uint8_t* name_string,
uint8_t* lang_string,
struct icon_callback_t* callback)
{
PE *pe = callback->pe;
PE_GROUP_ICON_DIRECTORY* group_icon;
PE_GROUP_ICON_DIRECTORY_ENTRY* icon_entry;

if (rsrc_type != RESOURCE_TYPE_GROUP_ICON) {
return RESOURCE_CALLBACK_CONTINUE;
}

int64_t group_icon_offset = pe_rva_to_offset(
pe, yr_le32toh(rsrc_data->OffsetToData));

if (group_icon_offset < 0)
return RESOURCE_CALLBACK_ABORT;

group_icon = (PE_GROUP_ICON_DIRECTORY*) (pe->data + group_icon_offset);

if (!struct_fits_in_pe(pe, group_icon, PE_GROUP_ICON_DIRECTORY))
return RESOURCE_CALLBACK_ABORT;

// iterate through the list and get the icon ordinals
int64_t icon_entry_offset = group_icon_offset + sizeof(PE_GROUP_ICON_DIRECTORY);
icon_entry = (PE_GROUP_ICON_DIRECTORY_ENTRY*) (pe->data + icon_entry_offset);

if (!fits_in_pe(pe, icon_entry, sizeof(PE_GROUP_ICON_DIRECTORY_ENTRY)*group_icon->idCount))
return RESOURCE_CALLBACK_ABORT;

callback->number_icon_ordinals = group_icon->idCount;
callback->icon_entry_offset = icon_entry_offset;

return RESOURCE_CALLBACK_ABORT;
}

void pe_parse_icons(PE* pe) {
icon_callback_t icon_callback;
PE_GROUP_ICON_DIRECTORY_ENTRY* icon_entry;

icon_callback.pe = pe;
icon_callback.number_icon_ordinals = 0;
icon_callback.icon_entry_offset = 0;
icon_callback.data_offset_list = NULL;

set_integer(0, pe->object, "number_of_icons");

// start by iterating the resources to identify the *first* RT_GROUP_ICON resource entry. This
// structure contains the metadata about each icon and an ordinal which allows us to later
// retrieve the actual image data for the icon.

// For more information, see Raymond Chen's blog at
// https://blogs.msdn.microsoft.com/oldnewthing/20120720-00/?p=7083

pe_iterate_resources(
pe,
(RESOURCE_CALLBACK_FUNC) pe_collect_icon_ordinals,
(void*) &icon_callback);

if (icon_callback.number_icon_ordinals == 0)
return;

icon_callback.data_offset_list = (int64_t*) yr_malloc(sizeof(int64_t) * icon_callback.number_icon_ordinals);
if (icon_callback.data_offset_list == NULL) {
return;
}

// now that we have populated the icon_entry_offset with the location of the RT_GROUP_ICON[] array,
// iterate over all RT_ICON resource entries to pull out the image data for each
// ordinal referenced in the RT_GROUP_ICON[] array.

// The result of this iterator is a list of offsets in the data_offset_list pointing to the
// image data for each icon ordinal referenced in the RT_GROUP_ICON resource entry.

pe_iterate_resources(pe, (RESOURCE_CALLBACK_FUNC) pe_collect_icon_data, (void*) &icon_callback);

int64_t icon_entry_offset = icon_callback.icon_entry_offset;

icon_entry_offset = icon_callback.icon_entry_offset;
for (int i = 0; i < icon_callback.number_icon_ordinals; i++) {
icon_entry = (PE_GROUP_ICON_DIRECTORY_ENTRY*) (pe->data + icon_entry_offset);

if (icon_callback.data_offset_list[i] != 0) {
const unsigned char *raw_data = pe->data + icon_callback.data_offset_list[i];

// note that the height, width, bitcount, and color planes are required to rebuild the BMP
// header for icons in bitmap format. Icons in PNG format are stored in their entirety.
set_integer(icon_entry->bWidth ? icon_entry->bWidth : 256, pe->object, "icons[%i].width", i);
set_integer(icon_entry->bHeight ? icon_entry->bHeight : 256, pe->object, "icons[%i].height", i);
set_integer(icon_entry->wBitCount, pe->object, "icons[%i].color_bit_count", i);
set_integer(icon_entry->wPlanes, pe->object, "icons[%i].color_planes", i);
set_integer(icon_entry->nId, pe->object, "icons[%i].ordinal", i);
set_sized_string((char*) raw_data, icon_entry->dwBytesInRes, pe->object, "icons[%i].data", i);
}
icon_entry_offset += sizeof(PE_GROUP_ICON_DIRECTORY_ENTRY);
}

set_integer(icon_callback.number_icon_ordinals, pe->object, "number_of_icons");

yr_free(icon_callback.data_offset_list);
}


void pe_parse_header(
PE* pe,
Expand Down Expand Up @@ -1640,6 +1795,10 @@ void pe_parse_header(
// overlay and UNDEFINED for malformed PE files or non-PE files.
if (last_section_end && (pe->data_size >= last_section_end))
set_integer(pe->data_size - last_section_end, pe->object, "overlay.size");


// collect icons
pe_parse_icons(pe);
}

//
Expand Down Expand Up @@ -2090,7 +2249,6 @@ define_function(locale)
return_integer(0);
}


define_function(language)
{
YR_OBJECT* module = module();
Expand Down Expand Up @@ -2589,6 +2747,17 @@ begin_declarations;
declare_integer("number_of_signatures");
#endif

begin_struct_array("icons");
declare_string("data");
declare_integer("height");
declare_integer("width");
declare_integer("color_bit_count");
declare_integer("color_planes");
declare_integer("ordinal");
end_struct_array("icons");

declare_integer("number_of_icons");

declare_function("rva_to_offset", "i", "i", rva_to_offset);

end_declarations;
Expand Down
6 changes: 5 additions & 1 deletion libyara/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -1150,7 +1150,11 @@ YR_API void yr_object_print_data(
{
char c = object->value.ss->c_string[l];

if (isprint((unsigned char) c))
if ((unsigned char) c == '\\')
printf("\\\\");
else if ((unsigned char) c == '\"')
printf("\\\"");
else if (isprint((unsigned char) c))
printf("%c", c);
else
printf("\\x%02x", (unsigned char) c);
Expand Down