Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(162)

Side by Side Diff: snapshot/win/pe_image_resource_reader.cc

Issue 1475023004: Get module versions and types from in-memory images (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Address review feedback (2) Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « snapshot/win/pe_image_resource_reader.h ('k') | snapshot/win/process_subrange_reader.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "snapshot/win/pe_image_resource_reader.h"
16
17 #include <algorithm>
18
19 #include "base/logging.h"
20 #include "base/memory/scoped_ptr.h"
21
22 namespace {
23
24 void AddLanguageAndNeutralSublanguage(std::vector<uint16_t>* languages,
25 uint16_t language) {
26 languages->push_back(language);
27 if (SUBLANGID(language) != SUBLANG_NEUTRAL) {
28 languages->push_back(MAKELANGID(PRIMARYLANGID(language), SUBLANG_NEUTRAL));
29 }
30 }
31
32 } // namespace
33
34 namespace crashpad {
35
36 PEImageResourceReader::PEImageResourceReader()
37 : resources_subrange_reader_(),
38 module_base_(0),
39 initialized_() {
40 }
41
42 PEImageResourceReader::~PEImageResourceReader() {}
43
44 bool PEImageResourceReader::Initialize(
45 const ProcessSubrangeReader& module_subrange_reader,
46 const IMAGE_DATA_DIRECTORY& resources_directory_entry) {
47 INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
48
49 module_base_ = module_subrange_reader.Base();
50
51 if (!resources_subrange_reader_.InitializeSubrange(
52 module_subrange_reader,
53 module_base_ + resources_directory_entry.VirtualAddress,
54 resources_directory_entry.Size,
55 "resources")) {
56 return false;
57 }
58
59 INITIALIZATION_STATE_SET_VALID(initialized_);
60 return true;
61 }
62
63 bool PEImageResourceReader::FindResourceByID(uint16_t type,
64 uint16_t name,
65 uint16_t language,
66 WinVMAddress* address,
67 WinVMSize* size,
68 uint32_t* code_page) const {
69 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
70
71 // The root resource directory is at the beginning of the resources area
72 // within the module.
73 const uint32_t name_directory_offset =
74 GetEntryFromResourceDirectoryByID(0, type, true);
75 if (!name_directory_offset) {
76 return false;
77 }
78
79 const uint32_t language_directory_offset =
80 GetEntryFromResourceDirectoryByID(name_directory_offset, name, true);
81 if (!language_directory_offset) {
82 return false;
83 }
84
85 // The definition of IMAGE_RESOURCE_DIRECTORY_ENTRY in <winnt.h> has a comment
86 // saying that its offsets are relative to “the resource directory of the data
87 // associated with this directory entry”. That could be interpreted to mean
88 // that language_directory_offset is relative to name_directory_offset, since
89 // the language directory entry is found within the name directory. This is
90 // not correct. All resource offsets are relative to the resources area within
91 // the module.
92 const uint32_t data_offset = GetEntryFromResourceDirectoryByLanguage(
93 language_directory_offset, language);
94 if (!data_offset) {
95 return false;
96 }
97
98 IMAGE_RESOURCE_DATA_ENTRY data_entry;
99 if (!resources_subrange_reader_.ReadMemory(
100 resources_subrange_reader_.Base() + data_offset,
101 sizeof(data_entry),
102 &data_entry)) {
103 LOG(WARNING) << "could not read resource data entry from "
104 << resources_subrange_reader_.name();
105 return false;
106 }
107
108 // The definition of IMAGE_RESOURCE_DATA_ENTRY in <winnt.h> has a comment
109 // saying that OffsetToData is relative to the beginning of the resource data.
110 // This is not correct. It’s module-relative.
111 *address = module_base_ + data_entry.OffsetToData;
112 *size = data_entry.Size;
113 if (code_page) {
114 *code_page = data_entry.CodePage;
115 }
116
117 return true;
118 }
119
120 uint32_t PEImageResourceReader::GetEntryFromResourceDirectoryByID(
121 uint32_t language_directory_offset,
122 uint16_t id,
123 bool want_subdirectory) const {
124 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
125
126 std::vector<IMAGE_RESOURCE_DIRECTORY_ENTRY> entries_by_id;
127 if (!ReadResourceDirectory(
128 language_directory_offset, nullptr, nullptr, &entries_by_id)) {
129 return 0;
130 }
131
132 const auto entry_it =
133 std::find_if(entries_by_id.begin(),
134 entries_by_id.end(),
135 [id](const IMAGE_RESOURCE_DIRECTORY_ENTRY& entry) {
136 return !entry.NameIsString && entry.Id == id;
137 });
138 if (entry_it != entries_by_id.end()) {
139 if ((entry_it->DataIsDirectory != 0) != want_subdirectory) {
140 LOG(WARNING) << "expected " << (want_subdirectory ? "" : "non-")
141 << "directory for entry id " << id << " in "
142 << resources_subrange_reader_.name();
143 return 0;
144 }
145
146 return entry_it->DataIsDirectory ? entry_it->OffsetToDirectory
147 : entry_it->OffsetToData;
148 }
149
150 return 0;
151 }
152
153 uint32_t PEImageResourceReader::GetEntryFromResourceDirectoryByLanguage(
154 uint32_t resource_directory_offset,
155 uint16_t language) const {
156 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
157
158 std::vector<IMAGE_RESOURCE_DIRECTORY_ENTRY> entries_by_language;
159 if (!ReadResourceDirectory(
160 resource_directory_offset, nullptr, nullptr, &entries_by_language)) {
161 return 0;
162 }
163
164 if (entries_by_language.empty()) {
165 return 0;
166 }
167
168 // https://msdn.microsoft.com/en-us/library/cc194810.aspx
169 //
170 // TODO(mark): It seems like FindResourceEx() might do something more complex.
171 // It would be best to mimic its behavior.
172 std::vector<uint16_t> try_languages;
173 if (PRIMARYLANGID(language) != LANG_NEUTRAL) {
174 AddLanguageAndNeutralSublanguage(&try_languages, language);
175 } else {
176 if (SUBLANGID(language) != SUBLANG_SYS_DEFAULT) {
177 AddLanguageAndNeutralSublanguage(&try_languages,
178 LANGIDFROMLCID(GetThreadLocale()));
179 AddLanguageAndNeutralSublanguage(&try_languages,
180 LANGIDFROMLCID(GetUserDefaultLCID()));
181 }
182 if (SUBLANGID(language) != SUBLANG_DEFAULT) {
183 AddLanguageAndNeutralSublanguage(&try_languages,
184 LANGIDFROMLCID(GetSystemDefaultLCID()));
185 }
186 }
187
188 try_languages.push_back(MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
189 try_languages.push_back(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT));
190
191 for (const auto try_language : try_languages) {
192 const auto entry_it = std::find_if(
193 entries_by_language.begin(),
194 entries_by_language.end(),
195 [try_language](const IMAGE_RESOURCE_DIRECTORY_ENTRY& entry) {
196 return !entry.NameIsString && entry.Id == try_language;
197 });
198 if (entry_it != entries_by_language.end()) {
199 if (entry_it->DataIsDirectory) {
200 LOG(WARNING) << "expected non-directory for entry language "
201 << try_language << " in "
202 << resources_subrange_reader_.name();
203 return 0;
204 }
205
206 return entry_it->OffsetToData;
207 }
208 }
209
210 // Fall back to the first entry in the list.
211 const auto& entry = entries_by_language.front();
212 if (entry.DataIsDirectory) {
213 LOG(WARNING) << "expected non-directory for entry in "
214 << resources_subrange_reader_.name();
215 return 0;
216 }
217
218 return entry.OffsetToData;
219 }
220
221 bool PEImageResourceReader::ReadResourceDirectory(
222 uint32_t resource_directory_offset,
223 IMAGE_RESOURCE_DIRECTORY* resource_directory,
224 std::vector<IMAGE_RESOURCE_DIRECTORY_ENTRY>* named_entries,
225 std::vector<IMAGE_RESOURCE_DIRECTORY_ENTRY>* id_entries) const {
226 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
227
228 // resource_directory is optional, but it’s still needed locally even if the
229 // caller isn’t interested in it.
230 scoped_ptr<IMAGE_RESOURCE_DIRECTORY> local_resource_directory;
231 if (!resource_directory) {
232 local_resource_directory.reset(new IMAGE_RESOURCE_DIRECTORY);
233 resource_directory = local_resource_directory.get();
234 }
235
236 const WinVMAddress address =
237 resources_subrange_reader_.Base() + resource_directory_offset;
238
239 if (!resources_subrange_reader_.ReadMemory(
240 address, sizeof(*resource_directory), resource_directory)) {
241 LOG(WARNING) << "could not read resource directory from "
242 << resources_subrange_reader_.name();
243 return false;
244 }
245
246 if (named_entries) {
247 named_entries->clear();
248 named_entries->resize(resource_directory->NumberOfNamedEntries);
249 if (!named_entries->empty() &&
250 !resources_subrange_reader_.ReadMemory(
251 address + sizeof(*resource_directory),
252 named_entries->size() * sizeof((*named_entries)[0]),
253 &(*named_entries)[0])) {
254 LOG(WARNING) << "could not read resource directory named entries from "
255 << resources_subrange_reader_.name();
256 return false;
257 }
258 }
259
260 if (id_entries) {
261 id_entries->clear();
262 id_entries->resize(resource_directory->NumberOfIdEntries);
263 if (!id_entries->empty() &&
264 !resources_subrange_reader_.ReadMemory(
265 address + sizeof(*resource_directory) +
266 resource_directory->NumberOfNamedEntries *
267 sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY),
268 id_entries->size() * sizeof((*id_entries)[0]),
269 &(*id_entries)[0])) {
270 LOG(WARNING) << "could not read resource directory ID entries from "
271 << resources_subrange_reader_.name();
272 return false;
273 }
274 }
275
276 return true;
277 }
278
279 } // namespace crashpad
OLDNEW
« no previous file with comments | « snapshot/win/pe_image_resource_reader.h ('k') | snapshot/win/process_subrange_reader.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698