• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
StructureAt(const uint8 * data,size_t data_size,const T ** structure)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
EnumResourcesWorker(const base::win::PEImage & image,const uint8 * tree_base,DWORD tree_size,DWORD directory_offset,upgrade_test::EntryPath & path,upgrade_test::EnumResource_Fn callback,uintptr_t context)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
EnumResources(const base::win::PEImage & image,EnumResource_Fn callback,uintptr_t context)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