Fix `pe_get_directory_entry`
@@ -87,48 +87,33 @@ PIMAGE_NT_HEADERS32 pe_get_header(const uint8_t* data, size_t data_size)
PIMAGE_DATA_DIRECTORY pe_get_directory_entry(PE* pe, int entry)
{
- PIMAGE_DATA_DIRECTORY directory_start;
- uint8_t* optional_header_start;
- uint16_t optional_header_size;
-
- // We are specifically NOT checking NumberOfRvaAndSizes here because it can
- // lie. 7ff1bf680c80fd73c0b35084904848b3705480ddeb6d0eff62180bd14cd18570 has
- // NumberOfRvaAndSizes set to 11 when in fact there is a valid
- // IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR entry (which is more than 11). If we
- // are overly strict here and only parse entries which are less than
- // NumberOfRvaAndSizes we run the risk of missing otherwise perfectly valid
- // files. Instead of being strict we check to make sure the entry is within
- // the OptionalHeader, since SizeOfOptionalHeader includes the DataDirectory
- // array.
-
- // In case someone requests an entry which is, by definition, invalid.
- if (entry >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
- return NULL;
+ // Explanation
+ // https://github.com/VirusTotal/yara/issues/1525
- if (IS_64BITS_PE(pe))
- {
- optional_header_start = (uint8_t*) &pe->header64->OptionalHeader;
- optional_header_size = pe->header64->FileHeader.SizeOfOptionalHeader;
- directory_start = pe->header64->OptionalHeader.DataDirectory;
- }
- else
- {
- optional_header_start = (uint8_t*) &pe->header->OptionalHeader;
- optional_header_size = pe->header->FileHeader.SizeOfOptionalHeader;
- directory_start = pe->header->OptionalHeader.DataDirectory;
- }
+ // In Windows, any access to data directories is controlled by the
+ // RtlImageDirectoryEntryToData function. This is one of the first checks
+ // whether the desired directory entry is smaller than NumberOfRvaAndSizes.
+ // If it's not, it means that the requested directory entry is not there.
+ //
+ // 1. Must NOT check whether NumberOfRvaAndSizes > 0x10
+ //
+ // 2. Must check for NumberOfRvaAndSizes < DataDirectory except for
+ // IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR for 32-bit binary
+ //
+ // 3. The function must NOT check for SizeOfOptionalHeader
- // Make sure the entry doesn't point outside of the OptionalHeader.
- if ((uint8_t*) (directory_start + entry) <=
- optional_header_start + optional_header_size)
- {
- if (IS_64BITS_PE(pe))
- return &pe->header64->OptionalHeader.DataDirectory[entry];
- else
- return &pe->header->OptionalHeader.DataDirectory[entry];
- }
+ if ((entry != IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR || IS_64BITS_PE(pe)) &&
+ OptionalHeader(pe, NumberOfRvaAndSizes) < entry)
+ return NULL;
+
+ PIMAGE_DATA_DIRECTORY result = &OptionalHeader(pe, DataDirectory)[entry];
+
+ // Check that directory is in file
+ if (!struct_fits_in_pe(pe, result, IMAGE_DATA_DIRECTORY))
return NULL;
+
+ return result;
}
