[Forensics-changes] [yara] 83/160: Add improvements suggested in pull request #282

Hilko Bengen bengen at moszumanska.debian.org
Sat Jul 1 10:29:20 UTC 2017


This is an automated email from the git hooks/post-receive script.

bengen pushed a commit to annotated tag v3.4.0
in repository yara.

commit 07d9d74c078e8b8890b351c2a0f02ee4ba936a03
Author: Victor M. Alvarez <plusvic at gmail.com>
Date:   Tue Apr 21 13:42:00 2015 +0200

    Add improvements suggested in pull request #282
    
    But using an slightly different approach for pe_rva_to_offset function
---
 libyara/modules/pe.c | 98 ++++++++++++++++++++++++++++++++++------------------
 1 file changed, 65 insertions(+), 33 deletions(-)

diff --git a/libyara/modules/pe.c b/libyara/modules/pe.c
index 400aad1..354ea17 100644
--- a/libyara/modules/pe.c
+++ b/libyara/modules/pe.c
@@ -74,6 +74,7 @@ limitations under the License.
 
 #define MAX_PE_SECTIONS              96
 #define MAX_PE_IMPORTS               256
+#define MAX_PE_EXPORTS               65535
 
 
 #define IS_RESOURCE_SUBDIRECTORY(entry) \
@@ -95,7 +96,7 @@ limitations under the License.
 #define fits_in_pe(pe, pointer, size) \
     (size <= pe->data_size && \
      (uint8_t*)(pointer) >= pe->data && \
-     (uint8_t*)(pointer) + size <= pe->data + pe->data_size)
+     (uint8_t*)(pointer) <= pe->data + pe->data_size - size)
 
 
 #define struct_fits_in_pe(pe, pointer, struct_type) \
@@ -367,26 +368,30 @@ PIMAGE_DATA_DIRECTORY pe_get_directory_entry(
 }
 
 
-uint64_t pe_rva_to_offset(
+int64_t pe_rva_to_offset(
     PE* pe,
     uint64_t rva)
 {
   PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pe->header);
+
   DWORD section_rva = 0;
   DWORD section_offset = 0;
+  DWORD section_virtual_size = 0;
+  DWORD section_raw_size = 0;
 
   int i = 0;
 
   while(i < yr_min(pe->header->FileHeader.NumberOfSections, MAX_PE_SECTIONS))
   {
-    if ((uint8_t*) section - \
-        (uint8_t*) pe->data + sizeof(IMAGE_SECTION_HEADER) < pe->data_size)
+    if (struct_fits_in_pe(pe, section, IMAGE_SECTION_HEADER))
     {
       if (rva >= section->VirtualAddress &&
           section_rva <= section->VirtualAddress)
       {
         section_rva = section->VirtualAddress;
         section_offset = section->PointerToRawData;
+        section_virtual_size = section->Misc.VirtualSize;
+        section_raw_size = section->SizeOfRawData;
       }
 
       section++;
@@ -394,11 +399,24 @@ uint64_t pe_rva_to_offset(
     }
     else
     {
-      return 0;
+      return -1;
     }
   }
 
-  return section_offset + (rva - section_rva);
+  // Many sections, have a raw (on disk) size smaller than their in-memory size.
+  // Check for rva's that map to this sparse space, and therefore have no valid
+  // associated file offset.
+
+  if ((rva - section_rva) >= section_raw_size)
+    return -1;
+
+  int64_t result = section_offset + (rva - section_rva);
+
+  // Check that the offset fits within the file.
+  if (result >= pe->data_size)
+    return -1;
+
+  return result;
 }
 
 
@@ -428,7 +446,7 @@ uint8_t* parse_resource_name(
     DWORD length = *rsrc_str_ptr;
 
     // Move past the length and make sure we have enough bytes for the string.
-    if (!fits_in_pe(pe, rsrc_str_ptr + 2, length))
+    if (!fits_in_pe(pe, rsrc_str_ptr + 2, length * 2))
       return NULL;
 
     return rsrc_str_ptr;
@@ -562,7 +580,7 @@ int pe_iterate_resources(
     RESOURCE_CALLBACK_FUNC callback,
     void* callback_data)
 {
-  uint64_t offset;
+  int64_t offset;
 
   int type = -1;
   int id = -1;
@@ -579,21 +597,25 @@ int pe_iterate_resources(
   {
     offset = pe_rva_to_offset(pe, directory->VirtualAddress);
 
-    if (offset != 0 &&
-        offset < pe->data_size)
-    {
-      PIMAGE_RESOURCE_DIRECTORY rsrc_dir =
+    if (offset < 0)
+      return 0;
+
+    PIMAGE_RESOURCE_DIRECTORY rsrc_dir =
         (PIMAGE_RESOURCE_DIRECTORY) (pe->data + offset);
 
+    if (struct_fits_in_pe(pe, rsrc_dir, IMAGE_RESOURCE_DIRECTORY))
+    {
       set_integer(rsrc_dir->TimeDateStamp,
-                  pe->object,
-                  "resource_timestamp");
+          pe->object,
+          "resource_timestamp");
+
       set_integer(rsrc_dir->MajorVersion,
                   pe->object,
                   "resource_version.major");
       set_integer(rsrc_dir->MinorVersion,
                   pe->object,
                   "resource_version.minor");
+
       _pe_iterate_resources(
           pe,
           rsrc_dir,
@@ -630,13 +652,16 @@ void pe_parse_version_info(
     PIMAGE_RESOURCE_DATA_ENTRY rsrc_data,
     PE* pe)
 {
-  size_t version_info_offset = pe_rva_to_offset(pe, rsrc_data->OffsetToData);
+  int64_t version_info_offset = pe_rva_to_offset(pe, rsrc_data->OffsetToData);
 
-  if (version_info_offset == 0)
+  if (version_info_offset < 0)
     return;
 
   PVERSION_INFO version_info = (PVERSION_INFO) (pe->data + version_info_offset);
 
+  if (!struct_fits_in_pe(pe, version_info, VERSION_INFO))
+    return;
+
   if (!fits_in_pe(pe, version_info->Key, sizeof("VS_VERSION_INFO") * 2))
     return;
 
@@ -711,9 +736,10 @@ int pe_collect_resources(
     PE* pe)
 {
   DWORD length;
-  size_t offset = pe_rva_to_offset(pe, rsrc_data->OffsetToData);
 
-  if (offset == 0 || !fits_in_pe(pe, pe->data + offset, rsrc_data->Size))
+  int64_t offset = pe_rva_to_offset(pe, rsrc_data->OffsetToData);
+
+  if (offset < 0 || !fits_in_pe(pe, pe->data + offset, rsrc_data->Size))
     return RESOURCE_CALLBACK_CONTINUE;
 
   set_integer(
@@ -733,6 +759,7 @@ int pe_collect_resources(
     // Multiply by 2 because it is a Unicode string.
     length = ((DWORD) *type_string) * 2;
     type_string += 2;
+
     set_sized_string(
         (char*) type_string, length, pe->object,
         "resources[%i].type_string", pe->resources);
@@ -799,16 +826,16 @@ IMPORTED_FUNCTION* pe_parse_import_descriptor(
   IMPORTED_FUNCTION* head = NULL;
   IMPORTED_FUNCTION* tail = NULL;
 
-  uint64_t offset = pe_rva_to_offset(
+  int64_t offset = pe_rva_to_offset(
       pe, import_descriptor->OriginalFirstThunk);
 
   // I've seen binaries where OriginalFirstThunk is zero. In this case
   // use FirstThunk.
 
-  if (offset == 0)
+  if (offset < 0)
     offset = pe_rva_to_offset(pe, import_descriptor->FirstThunk);
 
-  if (offset == 0)
+  if (offset < 0)
     return NULL;
 
   int num_functions = 0;
@@ -827,7 +854,7 @@ IMPORTED_FUNCTION* pe_parse_import_descriptor(
         // If imported by name
         offset = pe_rva_to_offset(pe, thunks64->u1.Function);
 
-        if (offset != 0)
+        if (offset >= 0)
         {
           PIMAGE_IMPORT_BY_NAME import = (PIMAGE_IMPORT_BY_NAME) \
               (pe->data + offset);
@@ -884,7 +911,7 @@ IMPORTED_FUNCTION* pe_parse_import_descriptor(
         // If imported by name
         offset = pe_rva_to_offset(pe, thunks32->u1.Function);
 
-        if (offset != 0)
+        if (offset >= 0)
         {
           PIMAGE_IMPORT_BY_NAME import = (PIMAGE_IMPORT_BY_NAME) \
               (pe->data + offset);
@@ -976,9 +1003,9 @@ IMPORTED_DLL* pe_parse_imports(
   if (directory->VirtualAddress == 0)
     return NULL;
 
-  uint64_t offset = pe_rva_to_offset(pe, directory->VirtualAddress);
+  int64_t offset = pe_rva_to_offset(pe, directory->VirtualAddress);
 
-  if (offset == 0)
+  if (offset < 0)
     return NULL;
 
   PIMAGE_IMPORT_DESCRIPTOR imports = (PIMAGE_IMPORT_DESCRIPTOR) \
@@ -989,9 +1016,9 @@ IMPORTED_DLL* pe_parse_imports(
   while (struct_fits_in_pe(pe, imports, IMAGE_IMPORT_DESCRIPTOR) &&
          imports->Name != 0 && num_imports < MAX_PE_IMPORTS)
   {
-    uint64_t offset = pe_rva_to_offset(pe, imports->Name);
+    int64_t offset = pe_rva_to_offset(pe, imports->Name);
 
-    if (offset != 0 && offset < pe->data_size)
+    if (offset >= 0)
     {
       char* dll_name = (char *) (pe->data + offset);
 
@@ -1402,19 +1429,24 @@ define_function(exports)
   if (directory->VirtualAddress == 0)
     return_integer(0);
 
-  uint64_t offset = pe_rva_to_offset(pe, directory->VirtualAddress);
+  int64_t offset = pe_rva_to_offset(pe, directory->VirtualAddress);
 
-  if (offset == 0 ||
-      offset >= pe->data_size)
+  if (offset < 0)
     return_integer(0);
 
   PIMAGE_EXPORT_DIRECTORY exports = (PIMAGE_EXPORT_DIRECTORY) \
       (pe->data + offset);
 
+  if (!struct_fits_in_pe(pe, exports, IMAGE_EXPORT_DIRECTORY))
+    return_integer(0);
+
   offset = pe_rva_to_offset(pe, exports->AddressOfNames);
 
-  if (offset == 0 ||
-      offset + exports->NumberOfNames * sizeof(DWORD) > pe->data_size)
+  if (offset < 0)
+    return_integer(0);
+
+  if (exports->NumberOfNames > MAX_PE_EXPORTS ||
+      exports->NumberOfNames * sizeof(DWORD) > pe->data_size - offset)
     return_integer(0);
 
   DWORD* names = (DWORD*)(pe->data + offset);
@@ -1423,7 +1455,7 @@ define_function(exports)
   {
     offset = pe_rva_to_offset(pe, names[i]);
 
-    if (offset == 0 || offset >= pe->data_size)
+    if (offset < 0)
       return_integer(0);
 
     char* name = (char*)(pe->data + offset);

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/forensics/yara.git



More information about the forensics-changes mailing list