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 return EnumResourcesWorker( 116 image, 117 reinterpret_cast<uint8*>( 118 image.GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_RESOURCE)), 119 resources_size, 0, EntryPath(), callback, context); 120 } 121 return true; 122 } 123 124 } // namespace upgrade_test 125