Home | History | Annotate | Download | only in test
      1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // This file contains the implementation for an iterator over a portable
      6 // executable file's resources.
      7 
      8 #include "chrome/installer/test/pe_image_resources.h"
      9 
     10 #include "base/logging.h"
     11 #include "base/win/pe_image.h"
     12 
     13 namespace {
     14 
     15 // Performs a cast to type |T| of |data| iff |data_size| is sufficient to hold
     16 // an instance of type |T|.  Returns true on success.
     17 template<class T>
     18 bool StructureAt(const uint8* data, size_t data_size, const T** structure) {
     19   if (sizeof(T) <= data_size) {
     20     *structure = reinterpret_cast<const T*>(data);
     21     return true;
     22   }
     23   return false;
     24 }
     25 
     26 // Recursive function for enumerating entries in an image's resource segment.
     27 // static
     28 bool EnumResourcesWorker(
     29     const base::win::PEImage& image, const uint8* tree_base, DWORD tree_size,
     30     DWORD directory_offset, upgrade_test::EntryPath* path,
     31     upgrade_test::EnumResource_Fn callback, uintptr_t context) {
     32   bool success = true;
     33   const IMAGE_RESOURCE_DIRECTORY* resource_directory;
     34 
     35   if (!StructureAt(tree_base + directory_offset, tree_size - directory_offset,
     36                    &resource_directory) ||
     37       directory_offset + sizeof(IMAGE_RESOURCE_DIRECTORY) +
     38           (resource_directory->NumberOfNamedEntries +
     39            resource_directory->NumberOfIdEntries) *
     40           sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) > tree_size) {
     41     LOG(DFATAL) << "Insufficient room in resource segment for directory entry.";
     42     return false;
     43   }
     44 
     45   const IMAGE_RESOURCE_DIRECTORY_ENTRY* scan =
     46       reinterpret_cast<const IMAGE_RESOURCE_DIRECTORY_ENTRY*>(
     47           tree_base + directory_offset +
     48           sizeof(IMAGE_RESOURCE_DIRECTORY));
     49   const IMAGE_RESOURCE_DIRECTORY_ENTRY* end = scan +
     50       resource_directory->NumberOfNamedEntries +
     51       resource_directory->NumberOfIdEntries;
     52   for (; success && scan != end; ++scan) {
     53     if ((scan->NameIsString != 0) !=
     54         (scan - reinterpret_cast<const IMAGE_RESOURCE_DIRECTORY_ENTRY*>(
     55             tree_base + directory_offset +
     56             sizeof(IMAGE_RESOURCE_DIRECTORY)) <
     57             resource_directory->NumberOfNamedEntries)) {
     58       LOG(DFATAL) << "Inconsistent number of named or numbered entries.";
     59       success = false;
     60       break;
     61     }
     62     if (scan->NameIsString) {
     63       const IMAGE_RESOURCE_DIR_STRING_U* dir_string;
     64       if (!StructureAt(tree_base + scan->NameOffset,
     65                        tree_size - scan->NameOffset, &dir_string) ||
     66           scan->NameOffset + sizeof(WORD) +
     67               dir_string->Length * sizeof(wchar_t) > tree_size) {
     68         LOG(DFATAL) << "Insufficient room in resource segment for entry name.";
     69         success = false;
     70         break;
     71       }
     72       path->push_back(
     73           upgrade_test::EntryId(std::wstring(&dir_string->NameString[0],
     74                                              dir_string->Length)));
     75     } else {
     76       path->push_back(upgrade_test::EntryId(scan->Id));
     77     }
     78     if (scan->DataIsDirectory) {
     79       success = EnumResourcesWorker(image, tree_base, tree_size,
     80                                     scan->OffsetToDirectory, path, callback,
     81                                     context);
     82     } else {
     83       const IMAGE_RESOURCE_DATA_ENTRY* data_entry;
     84       if (StructureAt(tree_base + scan->OffsetToData,
     85                       tree_size - scan->OffsetToData, &data_entry) &&
     86           reinterpret_cast<uint8*>(
     87               image.RVAToAddr(data_entry->OffsetToData)) + data_entry->Size <=
     88           tree_base + tree_size) {
     89         // Despite what winnt.h says, OffsetToData is an RVA.
     90         callback(
     91             *path,
     92             reinterpret_cast<uint8*>(image.RVAToAddr(data_entry->OffsetToData)),
     93             data_entry->Size, data_entry->CodePage, context);
     94       } else {
     95         LOG(DFATAL) << "Insufficient room in resource segment for data entry.";
     96         success = false;
     97       }
     98     }
     99     path->pop_back();
    100   }
    101 
    102   return success;
    103 }
    104 
    105 }  // namespace
    106 
    107 namespace upgrade_test {
    108 
    109 // static
    110 bool EnumResources(const base::win::PEImage& image, EnumResource_Fn callback,
    111                    uintptr_t context) {
    112   DWORD resources_size =
    113       image.GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_RESOURCE);
    114   if (resources_size != 0) {
    115     EntryPath path_storage;
    116     return EnumResourcesWorker(
    117         image,
    118         reinterpret_cast<uint8*>(
    119             image.GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_RESOURCE)),
    120         resources_size, 0, &path_storage, callback, context);
    121   }
    122   return true;
    123 }
    124 
    125 }  // namespace upgrade_test
    126