OLD | NEW |
---|---|
(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_reader.h" | |
16 | |
17 #include <string.h> | |
18 | |
19 #include "base/logging.h" | |
20 #include "base/strings/stringprintf.h" | |
21 #include "client/crashpad_info.h" | |
22 #include "snapshot/win/process_reader_win.h" | |
23 | |
24 namespace crashpad { | |
25 | |
26 namespace { | |
27 | |
28 std::string RangeToString(const CheckedWinAddressRange& range) { | |
29 return base::StringPrintf("[0x%llx + 0x%llx (%s)]", | |
30 range.Base(), | |
31 range.Size(), | |
32 range.Is64Bit() ? "64" : "32"); | |
33 } | |
34 | |
35 } // namespace | |
36 | |
37 PEImageReader::PEImageReader() | |
38 : process_reader_(nullptr), | |
39 address_(0), | |
40 size_(0), | |
41 module_range_(), | |
42 module_name_(), | |
43 initialized_() { | |
44 } | |
45 | |
46 PEImageReader::~PEImageReader() { | |
47 } | |
48 | |
49 bool PEImageReader::Initialize(ProcessReaderWin* process_reader, | |
50 win_vm_address_t address, | |
51 win_vm_size_t size, | |
52 const std::string& module_name) { | |
53 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); | |
54 | |
55 process_reader_ = process_reader; | |
56 address_ = address; | |
Mark Mentovai
2015/05/01 19:05:31
Do you need distinct fields for address_ and size_
scottmg
2015/05/01 19:46:31
Done.
| |
57 size_ = size; | |
58 module_range_.SetRange(process_reader_->Is64Bit(), address_, size_); | |
59 if (!module_range_.IsValid()) { | |
60 LOG(WARNING) << "invalid module range for " << module_name << ": " | |
61 << RangeToString(module_range_); | |
62 return false; | |
63 } | |
64 module_name_ = module_name; | |
65 | |
66 INITIALIZATION_STATE_SET_VALID(initialized_); | |
67 return true; | |
68 } | |
69 | |
70 bool PEImageReader::GetCrashpadInfo( | |
71 process_types::CrashpadInfo* crashpad_info) const { | |
72 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
73 | |
74 IMAGE_SECTION_HEADER section; | |
75 if (!GetSectionByName("CPADinfo", §ion)) | |
76 return false; | |
77 | |
78 if (section.Misc.VirtualSize < sizeof(process_types::CrashpadInfo)) { | |
79 LOG(WARNING) << "small crashpad info section size " | |
80 << section.Misc.VirtualSize << ", " << module_name_; | |
81 return false; | |
82 } | |
83 | |
84 win_vm_address_t crashpad_info_address = address_ + section.VirtualAddress; | |
85 CheckedWinAddressRange crashpad_info_range(process_reader_->Is64Bit(), | |
86 crashpad_info_address, | |
87 section.Misc.VirtualSize); | |
88 if (!crashpad_info_range.IsValid()) { | |
89 LOG(WARNING) << "invalid range for crashpad info: " | |
90 << RangeToString(crashpad_info_range); | |
91 return false; | |
92 } | |
93 | |
94 if (!module_range_.ContainsRange(crashpad_info_range)) { | |
95 LOG(WARNING) << "crashpad info does not fall inside module " | |
96 << module_name_; | |
97 return false; | |
98 } | |
99 | |
100 // TODO(scottmg): process_types for cross-bitness. | |
101 if (!process_reader_->ReadMemory(crashpad_info_address, | |
102 sizeof(process_types::CrashpadInfo), | |
103 crashpad_info)) { | |
104 LOG(WARNING) << "could not read crashpad info " << module_name_; | |
105 return false; | |
106 } | |
107 | |
108 if (crashpad_info->signature != CrashpadInfo::kSignature || | |
109 crashpad_info->version < 1) { | |
110 LOG(WARNING) << "unexpected crashpad info data " << module_name_; | |
111 return false; | |
112 } | |
113 | |
114 return true; | |
115 } | |
116 | |
117 bool PEImageReader::GetSectionByName(const std::string& name, | |
118 IMAGE_SECTION_HEADER* section) const { | |
119 if (name.size() > sizeof(section->Name)) { | |
120 LOG(WARNING) << "supplied section name too long " << name; | |
121 return false; | |
122 } | |
123 | |
124 IMAGE_DOS_HEADER dos_header; | |
125 if (!CheckedReadMemory(address_, sizeof(IMAGE_DOS_HEADER), &dos_header)) { | |
126 LOG(WARNING) << "could not read dos header of " << module_name_; | |
127 return false; | |
128 } | |
129 | |
130 if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) { | |
131 LOG(WARNING) << "invalid e_magic in dos header of " << module_name_; | |
132 return false; | |
133 } | |
134 | |
135 // TODO(scottmg): This is reading a same-bitness sized structure. | |
136 IMAGE_NT_HEADERS nt_headers; | |
137 win_vm_address_t nt_headers_address = address_ + dos_header.e_lfanew; | |
138 if (!CheckedReadMemory( | |
139 nt_headers_address, sizeof(IMAGE_NT_HEADERS), &nt_headers)) { | |
140 LOG(WARNING) << "could not read nt headers of " << module_name_; | |
141 return false; | |
142 } | |
143 | |
144 if (nt_headers.Signature != IMAGE_NT_SIGNATURE) { | |
145 LOG(WARNING) << "invalid signature in nt headers of " << module_name_; | |
146 return false; | |
147 } | |
148 | |
149 win_vm_address_t first_section_address = | |
150 nt_headers_address + offsetof(IMAGE_NT_HEADERS, OptionalHeader) + | |
151 nt_headers.FileHeader.SizeOfOptionalHeader; | |
152 for (DWORD i = 0; i < nt_headers.FileHeader.NumberOfSections; ++i) { | |
153 win_vm_address_t section_address = | |
154 first_section_address + sizeof(IMAGE_SECTION_HEADER) * i; | |
155 if (!CheckedReadMemory( | |
156 section_address, sizeof(IMAGE_SECTION_HEADER), section)) { | |
157 LOG(WARNING) << "could not read section " << i << " of " << module_name_; | |
158 return false; | |
159 } | |
160 if (strncmp(reinterpret_cast<const char*>(section->Name), | |
161 name.c_str(), | |
162 sizeof(section->Name)) == 0) { | |
163 return true; | |
164 } | |
165 } | |
166 | |
167 return false; | |
168 } | |
169 | |
170 bool PEImageReader::CheckedReadMemory(win_vm_address_t address, | |
171 win_vm_size_t size, | |
172 void* into) const { | |
173 CheckedWinAddressRange read_range(process_reader_->Is64Bit(), address, size); | |
174 if (!read_range.IsValid()) { | |
175 LOG(WARNING) << "invalid read range: " << RangeToString(read_range); | |
176 return false; | |
177 } | |
178 if (!module_range_.ContainsRange(read_range)) { | |
179 LOG(WARNING) << "attempt to read outside of module " << module_name_ | |
180 << " at range: " << RangeToString(read_range); | |
181 return false; | |
182 } | |
183 return process_reader_->ReadMemory(address, size, into); | |
184 } | |
185 | |
186 } // namespace crashpad | |
OLD | NEW |