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

Side by Side Diff: snapshot/win/pe_image_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: 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
OLDNEW
1 // Copyright 2015 The Crashpad Authors. All rights reserved. 1 // Copyright 2015 The Crashpad Authors. All rights reserved.
2 // 2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with 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 5 // You may obtain a copy of the License at
6 // 6 //
7 // http://www.apache.org/licenses/LICENSE-2.0 7 // http://www.apache.org/licenses/LICENSE-2.0
8 // 8 //
9 // Unless required by applicable law or agreed to in writing, software 9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, 10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and 12 // See the License for the specific language governing permissions and
13 // limitations under the License. 13 // limitations under the License.
14 14
15 #include "snapshot/win/pe_image_reader.h" 15 #include "snapshot/win/pe_image_reader.h"
16 16
17 #include <string.h> 17 #include <string.h>
18 18
19 #include "base/logging.h" 19 #include "base/logging.h"
20 #include "base/memory/scoped_ptr.h" 20 #include "base/memory/scoped_ptr.h"
21 #include "base/strings/stringprintf.h"
22 #include "client/crashpad_info.h" 21 #include "client/crashpad_info.h"
22 #include "snapshot/win/pe_image_resource_reader.h"
23 #include "snapshot/win/process_reader_win.h" 23 #include "snapshot/win/process_reader_win.h"
24 #include "util/misc/pdb_structures.h" 24 #include "util/misc/pdb_structures.h"
25 #include "util/win/process_structs.h" 25 #include "util/win/process_structs.h"
26 26
27 namespace crashpad { 27 namespace crashpad {
28 28
29 namespace { 29 namespace {
30 30
31 std::string RangeToString(const CheckedWinAddressRange& range) {
32 return base::StringPrintf("[0x%llx + 0x%llx (%s)]",
33 range.Base(),
34 range.Size(),
35 range.Is64Bit() ? "64" : "32");
36 }
37
38 // Map from Traits to an IMAGE_NT_HEADERSxx. 31 // Map from Traits to an IMAGE_NT_HEADERSxx.
39 template <class Traits> 32 template <class Traits>
40 struct NtHeadersForTraits; 33 struct NtHeadersForTraits;
41 34
42 template <> 35 template <>
43 struct NtHeadersForTraits<process_types::internal::Traits32> { 36 struct NtHeadersForTraits<process_types::internal::Traits32> {
44 using type = IMAGE_NT_HEADERS32; 37 using type = IMAGE_NT_HEADERS32;
45 }; 38 };
46 39
47 template <> 40 template <>
(...skipping 16 matching lines...) Expand all
64 bool PEImageReader::Initialize(ProcessReaderWin* process_reader, 57 bool PEImageReader::Initialize(ProcessReaderWin* process_reader,
65 WinVMAddress address, 58 WinVMAddress address,
66 WinVMSize size, 59 WinVMSize size,
67 const std::string& module_name) { 60 const std::string& module_name) {
68 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); 61 INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
69 62
70 process_reader_ = process_reader; 63 process_reader_ = process_reader;
71 module_range_.SetRange(process_reader_->Is64Bit(), address, size); 64 module_range_.SetRange(process_reader_->Is64Bit(), address, size);
72 if (!module_range_.IsValid()) { 65 if (!module_range_.IsValid()) {
73 LOG(WARNING) << "invalid module range for " << module_name << ": " 66 LOG(WARNING) << "invalid module range for " << module_name << ": "
74 << RangeToString(module_range_); 67 << module_range_.AsString();
75 return false; 68 return false;
76 } 69 }
77 module_name_ = module_name; 70 module_name_ = module_name;
78 71
79 INITIALIZATION_STATE_SET_VALID(initialized_); 72 INITIALIZATION_STATE_SET_VALID(initialized_);
80 return true; 73 return true;
81 } 74 }
82 75
83 template <class Traits> 76 template <class Traits>
84 bool PEImageReader::GetCrashpadInfo( 77 bool PEImageReader::GetCrashpadInfo(
85 process_types::CrashpadInfo<Traits>* crashpad_info) const { 78 process_types::CrashpadInfo<Traits>* crashpad_info) const {
86 INITIALIZATION_STATE_DCHECK_VALID(initialized_); 79 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
87 80
88 IMAGE_SECTION_HEADER section; 81 IMAGE_SECTION_HEADER section;
89 if (!GetSectionByName<NtHeadersForTraits<Traits>::type>("CPADinfo", &section)) 82 if (!GetSectionByName<NtHeadersForTraits<Traits>::type>("CPADinfo", &section))
90 return false; 83 return false;
91 84
92 if (section.Misc.VirtualSize < sizeof(process_types::CrashpadInfo<Traits>)) { 85 if (section.Misc.VirtualSize < sizeof(process_types::CrashpadInfo<Traits>)) {
93 LOG(WARNING) << "small crashpad info section size " 86 LOG(WARNING) << "small crashpad info section size "
94 << section.Misc.VirtualSize << ", " << module_name_; 87 << section.Misc.VirtualSize << ", " << module_name_;
95 return false; 88 return false;
96 } 89 }
97 90
98 WinVMAddress crashpad_info_address = Address() + section.VirtualAddress; 91 WinVMAddress crashpad_info_address = Address() + section.VirtualAddress;
99 CheckedWinAddressRange crashpad_info_range(process_reader_->Is64Bit(), 92 CheckedWinAddressRange crashpad_info_range(process_reader_->Is64Bit(),
100 crashpad_info_address, 93 crashpad_info_address,
101 section.Misc.VirtualSize); 94 section.Misc.VirtualSize);
102 if (!crashpad_info_range.IsValid()) { 95 if (!crashpad_info_range.IsValid()) {
103 LOG(WARNING) << "invalid range for crashpad info: " 96 LOG(WARNING) << "invalid range for crashpad info: "
104 << RangeToString(crashpad_info_range); 97 << crashpad_info_range.AsString();
105 return false; 98 return false;
106 } 99 }
107 100
108 if (!module_range_.ContainsRange(crashpad_info_range)) { 101 if (!module_range_.ContainsRange(crashpad_info_range)) {
109 LOG(WARNING) << "crashpad info does not fall inside module " 102 LOG(WARNING) << "crashpad info does not fall inside module "
110 << module_name_; 103 << module_name_;
111 return false; 104 return false;
112 } 105 }
113 106
114 if (!process_reader_->ReadMemory(crashpad_info_address, 107 if (!process_reader_->ReadMemory(crashpad_info_address,
115 sizeof(process_types::CrashpadInfo<Traits>), 108 sizeof(process_types::CrashpadInfo<Traits>),
116 crashpad_info)) { 109 crashpad_info)) {
117 LOG(WARNING) << "could not read crashpad info " << module_name_; 110 LOG(WARNING) << "could not read crashpad info " << module_name_;
118 return false; 111 return false;
119 } 112 }
120 113
121 if (crashpad_info->signature != CrashpadInfo::kSignature || 114 if (crashpad_info->signature != CrashpadInfo::kSignature ||
122 crashpad_info->version < 1) { 115 crashpad_info->version < 1) {
123 LOG(WARNING) << "unexpected crashpad info data " << module_name_; 116 LOG(WARNING) << "unexpected crashpad info data " << module_name_;
124 return false; 117 return false;
125 } 118 }
126 119
127 return true; 120 return true;
128 } 121 }
129 122
130 bool PEImageReader::DebugDirectoryInformation(UUID* uuid, 123 bool PEImageReader::DebugDirectoryInformation(UUID* uuid,
131 DWORD* age, 124 DWORD* age,
132 std::string* pdbname) const { 125 std::string* pdbname) const {
133 if (process_reader_->Is64Bit()) { 126 IMAGE_DATA_DIRECTORY data_directory;
134 return ReadDebugDirectoryInformation<IMAGE_NT_HEADERS64>( 127 if (!ImageDataDirectoryEntry(IMAGE_DIRECTORY_ENTRY_DEBUG, &data_directory))
135 uuid, age, pdbname);
136 } else {
137 return ReadDebugDirectoryInformation<IMAGE_NT_HEADERS32>(
138 uuid, age, pdbname);
139 }
140 }
141
142 template <class NtHeadersType>
143 bool PEImageReader::ReadDebugDirectoryInformation(UUID* uuid,
144 DWORD* age,
145 std::string* pdbname) const {
146 NtHeadersType nt_headers;
147 if (!ReadNtHeaders(&nt_headers, nullptr))
148 return false; 128 return false;
149 129
150 if (nt_headers.FileHeader.SizeOfOptionalHeader <
151 offsetof(decltype(nt_headers.OptionalHeader),
152 DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]) +
153 sizeof(nt_headers.OptionalHeader
154 .DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]) ||
155 nt_headers.OptionalHeader.NumberOfRvaAndSizes <=
156 IMAGE_DIRECTORY_ENTRY_DEBUG) {
157 return false;
158 }
159
160 const IMAGE_DATA_DIRECTORY& data_directory =
161 nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
162 if (data_directory.VirtualAddress == 0 || data_directory.Size == 0)
163 return false;
164 IMAGE_DEBUG_DIRECTORY debug_directory; 130 IMAGE_DEBUG_DIRECTORY debug_directory;
165 if (data_directory.Size % sizeof(debug_directory) != 0) 131 if (data_directory.Size % sizeof(debug_directory) != 0)
166 return false; 132 return false;
167 for (size_t offset = 0; offset < data_directory.Size; 133 for (size_t offset = 0; offset < data_directory.Size;
168 offset += sizeof(debug_directory)) { 134 offset += sizeof(debug_directory)) {
169 if (!CheckedReadMemory(Address() + data_directory.VirtualAddress + offset, 135 if (!CheckedReadMemory(Address() + data_directory.VirtualAddress + offset,
170 sizeof(debug_directory), 136 sizeof(debug_directory),
171 &debug_directory)) { 137 &debug_directory)) {
172 LOG(WARNING) << "could not read data directory"; 138 LOG(WARNING) << "could not read data directory";
173 return false; 139 return false;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 // This occurs for non-PDB based debug information. We simply ignore these 175 // This occurs for non-PDB based debug information. We simply ignore these
210 // as we don't expect to encounter modules that will be in this format 176 // as we don't expect to encounter modules that will be in this format
211 // for which we'll actually have symbols. See 177 // for which we'll actually have symbols. See
212 // https://crashpad.chromium.org/bug/47. 178 // https://crashpad.chromium.org/bug/47.
213 } 179 }
214 } 180 }
215 181
216 return false; 182 return false;
217 } 183 }
218 184
185 bool PEImageReader::VSFixedFileInfo(
186 VS_FIXEDFILEINFO* vs_fixed_file_info) const {
187 IMAGE_DATA_DIRECTORY data_directory;
188 if (!ImageDataDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE,
189 &data_directory)) {
190 return false;
191 }
192
193 PEImageResourceReader resource_reader;
194 if (!resource_reader.Initialize(
195 process_reader_, data_directory, module_range_, module_name_)) {
196 return false;
197 }
198
199 WinVMAddress address;
200 WinVMSize size;
201 if (!resource_reader.FindResourceByID(
202 reinterpret_cast<uint16_t>(VS_FILE_INFO),
203 VS_VERSION_INFO,
204 MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
205 &address,
206 &size,
207 nullptr)) {
208 return false;
209 }
210
211 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms647001.aspx
212 struct VS_VERSIONINFO {
213 WORD wLength;
214 WORD wValueLength;
215 WORD wType;
216
217 // MSDN doesn’t show the [16], but this is in fact a 16-character string.
218 WCHAR szKey[16];
219
220 WORD Padding1;
221 VS_FIXEDFILEINFO Value;
222
223 // Don’t include Children or the Padding2 that precedes it, because they may
224 // not be present.
225 // WORD Padding2;
226 // WORD Children;
227 };
228 VS_VERSIONINFO version_info;
229
230 if (size < sizeof(version_info)) {
231 LOG(WARNING) << "version info size " << size
232 << " too small for structure of size " << sizeof(version_info)
233 << " in " << module_name_;
234 return false;
235 }
236
237 if (!CheckedReadMemory(address, sizeof(version_info), &version_info)) {
238 return false;
239 }
240
241 if (version_info.wLength < sizeof(version_info) ||
242 version_info.wValueLength < sizeof(version_info.Value) ||
scottmg 2015/11/26 21:29:59 != for this one rather than <, as if it's not our
Mark Mentovai 2015/12/01 18:48:00 scottmg wrote:
243 version_info.wType != 0 ||
244 wcsncmp(version_info.szKey,
245 L"VS_VERSION_INFO",
246 arraysize(version_info.szKey)) != 0) {
247 LOG(WARNING) << "unexpected VS_VERSIONINFO";
248 return false;
249 }
250
251 if (version_info.Value.dwSignature != VS_FFI_SIGNATURE ||
252 version_info.Value.dwStrucVersion != VS_FFI_STRUCVERSION) {
253 LOG(WARNING) << "unexpected VS_FIXEDFILEINFO";
254 return false;
255 }
256
257 *vs_fixed_file_info = version_info.Value;
258 vs_fixed_file_info->dwFileFlags &= vs_fixed_file_info->dwFileFlagsMask;
259 return true;
260 }
261
219 template <class NtHeadersType> 262 template <class NtHeadersType>
220 bool PEImageReader::ReadNtHeaders(NtHeadersType* nt_headers, 263 bool PEImageReader::ReadNtHeaders(NtHeadersType* nt_headers,
221 WinVMAddress* nt_headers_address) const { 264 WinVMAddress* nt_headers_address) const {
222 IMAGE_DOS_HEADER dos_header; 265 IMAGE_DOS_HEADER dos_header;
223 if (!CheckedReadMemory(Address(), sizeof(IMAGE_DOS_HEADER), &dos_header)) { 266 if (!CheckedReadMemory(Address(), sizeof(IMAGE_DOS_HEADER), &dos_header)) {
224 LOG(WARNING) << "could not read dos header of " << module_name_; 267 LOG(WARNING) << "could not read dos header of " << module_name_;
225 return false; 268 return false;
226 } 269 }
227 270
228 if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) { 271 if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) {
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 if (strncmp(reinterpret_cast<const char*>(section->Name), 318 if (strncmp(reinterpret_cast<const char*>(section->Name),
276 name.c_str(), 319 name.c_str(),
277 sizeof(section->Name)) == 0) { 320 sizeof(section->Name)) == 0) {
278 return true; 321 return true;
279 } 322 }
280 } 323 }
281 324
282 return false; 325 return false;
283 } 326 }
284 327
328 bool PEImageReader::ImageDataDirectoryEntry(size_t index,
329 IMAGE_DATA_DIRECTORY* entry) const {
330 bool rv;
331 if (process_reader_->Is64Bit()) {
332 rv = ImageDataDirectoryEntryT<IMAGE_NT_HEADERS64>(index, entry);
333 } else {
334 rv = ImageDataDirectoryEntryT<IMAGE_NT_HEADERS32>(index, entry);
335 }
336
337 return rv && entry->VirtualAddress != 0 && entry->Size != 0;
338 }
339
340 template <class NtHeadersType>
341 bool PEImageReader::ImageDataDirectoryEntryT(
342 size_t index,
343 IMAGE_DATA_DIRECTORY* entry) const {
344 NtHeadersType nt_headers;
345 if (!ReadNtHeaders(&nt_headers, nullptr)) {
346 return false;
347 }
348
349 if (nt_headers.FileHeader.SizeOfOptionalHeader <
350 offsetof(decltype(nt_headers.OptionalHeader), DataDirectory[index]) +
351 sizeof(nt_headers.OptionalHeader.DataDirectory[index]) ||
352 nt_headers.OptionalHeader.NumberOfRvaAndSizes <= index) {
353 return false;
354 }
355
356 *entry = nt_headers.OptionalHeader.DataDirectory[index];
357 return true;
358 }
359
285 bool PEImageReader::CheckedReadMemory(WinVMAddress address, 360 bool PEImageReader::CheckedReadMemory(WinVMAddress address,
286 WinVMSize size, 361 WinVMSize size,
287 void* into) const { 362 void* into) const {
288 CheckedWinAddressRange read_range(process_reader_->Is64Bit(), address, size); 363 CheckedWinAddressRange read_range(process_reader_->Is64Bit(), address, size);
289 if (!read_range.IsValid()) { 364 if (!read_range.IsValid()) {
290 LOG(WARNING) << "invalid read range: " << RangeToString(read_range); 365 LOG(WARNING) << "invalid read range: " << read_range.AsString();
291 return false; 366 return false;
292 } 367 }
293 if (!module_range_.ContainsRange(read_range)) { 368 if (!module_range_.ContainsRange(read_range)) {
294 LOG(WARNING) << "attempt to read outside of module " << module_name_ 369 LOG(WARNING) << "attempt to read outside of module " << module_name_
295 << " at range: " << RangeToString(read_range); 370 << " at range: " << read_range.AsString();
296 return false; 371 return false;
297 } 372 }
298 return process_reader_->ReadMemory(address, size, into); 373 return process_reader_->ReadMemory(address, size, into);
299 } 374 }
300 375
301 // Explicit instantiations with the only 2 valid template arguments to avoid 376 // Explicit instantiations with the only 2 valid template arguments to avoid
302 // putting the body of the function in the header. 377 // putting the body of the function in the header.
303 template bool PEImageReader::GetCrashpadInfo<process_types::internal::Traits32>( 378 template bool PEImageReader::GetCrashpadInfo<process_types::internal::Traits32>(
304 process_types::CrashpadInfo<process_types::internal::Traits32>* 379 process_types::CrashpadInfo<process_types::internal::Traits32>*
305 crashpad_info) const; 380 crashpad_info) const;
306 template bool PEImageReader::GetCrashpadInfo<process_types::internal::Traits64>( 381 template bool PEImageReader::GetCrashpadInfo<process_types::internal::Traits64>(
307 process_types::CrashpadInfo<process_types::internal::Traits64>* 382 process_types::CrashpadInfo<process_types::internal::Traits64>*
308 crashpad_info) const; 383 crashpad_info) const;
309 384
310 } // namespace crashpad 385 } // namespace crashpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698