Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Crashpad Authors. All rights reserved. | |
|
Mark Mentovai
2015/09/16 02:57:20
Pretty sure we still own this file.
scottmg
2015/09/16 18:05:07
Done.
| |
| 2 // | 1 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | 2 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. | 3 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at | 4 // You may obtain a copy of the License at |
| 6 // | 5 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | 6 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // | 7 // |
| 9 // Unless required by applicable law or agreed to in writing, software | 8 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | 9 // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and | 11 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. | 12 // limitations under the License. |
| 14 | 13 |
| 15 #include "util/win/process_info.h" | 14 #include "util/win/process_info.h" |
| 16 | 15 |
| 17 #include <winternl.h> | 16 #include <winternl.h> |
| 18 | 17 |
| 19 #include "base/logging.h" | 18 #include "base/logging.h" |
| 20 #include "util/numeric/safe_assignment.h" | 19 #include "util/numeric/safe_assignment.h" |
| 20 #include "util/win/ntstatus_logging.h" | |
| 21 #include "util/win/process_structs.h" | 21 #include "util/win/process_structs.h" |
| 22 | 22 |
| 23 namespace crashpad { | 23 namespace crashpad { |
| 24 | 24 |
| 25 namespace { | 25 namespace { |
| 26 | 26 |
| 27 NTSTATUS NtQueryInformationProcess(HANDLE process_handle, | 27 NTSTATUS NtQueryInformationProcess(HANDLE process_handle, |
| 28 PROCESSINFOCLASS process_information_class, | 28 PROCESSINFOCLASS process_information_class, |
| 29 PVOID process_information, | 29 PVOID process_information, |
| 30 ULONG process_information_length, | 30 ULONG process_information_length, |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 73 PLOG(ERROR) << "ReadProcessMemory UNICODE_STRING"; | 73 PLOG(ERROR) << "ReadProcessMemory UNICODE_STRING"; |
| 74 return false; | 74 return false; |
| 75 } | 75 } |
| 76 if (bytes_read != us.Length) { | 76 if (bytes_read != us.Length) { |
| 77 LOG(ERROR) << "ReadProcessMemory UNICODE_STRING incorrect size"; | 77 LOG(ERROR) << "ReadProcessMemory UNICODE_STRING incorrect size"; |
| 78 return false; | 78 return false; |
| 79 } | 79 } |
| 80 return true; | 80 return true; |
| 81 } | 81 } |
| 82 | 82 |
| 83 template <class T> bool ReadStruct(HANDLE process, WinVMAddress at, T* into) { | 83 template <class T> |
| 84 bool ReadStruct(HANDLE process, WinVMAddress at, T* into) { | |
| 84 SIZE_T bytes_read; | 85 SIZE_T bytes_read; |
| 85 if (!ReadProcessMemory(process, | 86 if (!ReadProcessMemory(process, |
| 86 reinterpret_cast<const void*>(at), | 87 reinterpret_cast<const void*>(at), |
| 87 into, | 88 into, |
| 88 sizeof(T), | 89 sizeof(T), |
| 89 &bytes_read)) { | 90 &bytes_read)) { |
| 90 // We don't have a name for the type we're reading, so include the signature | 91 // We don't have a name for the type we're reading, so include the signature |
| 91 // to get the type of T. | 92 // to get the type of T. |
| 92 PLOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__; | 93 PLOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__; |
| 93 return false; | 94 return false; |
| 94 } | 95 } |
| 95 if (bytes_read != sizeof(T)) { | 96 if (bytes_read != sizeof(T)) { |
| 96 LOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__ << " incorrect size"; | 97 LOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__ << " incorrect size"; |
| 97 return false; | 98 return false; |
| 98 } | 99 } |
| 99 return true; | 100 return true; |
| 100 } | 101 } |
| 101 | 102 |
| 102 } // namespace | 103 } // namespace |
| 103 | 104 |
| 104 template <class Traits> | 105 template <class Traits> |
| 106 bool GetProcessBasicInformation(HANDLE process, | |
| 107 bool is_wow64, | |
| 108 ProcessInfo* process_info, | |
| 109 WinVMAddress* peb_address) { | |
| 110 ULONG bytes_returned; | |
| 111 process_types::PROCESS_BASIC_INFORMATION<Traits> process_basic_information; | |
| 112 NTSTATUS status = | |
| 113 crashpad::NtQueryInformationProcess(process, | |
| 114 ProcessBasicInformation, | |
| 115 &process_basic_information, | |
| 116 sizeof(process_basic_information), | |
| 117 &bytes_returned); | |
| 118 if (!NT_SUCCESS(status)) { | |
| 119 NTSTATUS_LOG(ERROR, status) << "NtQueryInformationProcess"; | |
| 120 return false; | |
| 121 } | |
| 122 if (bytes_returned != sizeof(process_basic_information)) { | |
| 123 LOG(ERROR) << "NtQueryInformationProcess incorrect size"; | |
| 124 return false; | |
| 125 } | |
| 126 | |
| 127 // See https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203 on | |
| 128 // 32 bit being the correct size for HANDLEs for proceses, even on Windows | |
| 129 // x64. API functions (e.g. OpenProcess) take only a DWORD, so there's no | |
| 130 // sense in maintaining the top bits. | |
| 131 process_info->process_id_ = | |
| 132 static_cast<DWORD>(process_basic_information.UniqueProcessId); | |
| 133 process_info->inherited_from_process_id_ = static_cast<DWORD>( | |
| 134 process_basic_information.InheritedFromUniqueProcessId); | |
| 135 | |
| 136 // We now want to read the PEB to gather the rest of our information. The | |
| 137 // PebBaseAddress as returned above is what we want for 64-on-64 and 32-on-32, | |
| 138 // but for Wow64, we want to read the 32 bit PEB (a Wow64 process has both). | |
| 139 // The address of this is found by a second call to NtQueryInformationProcess. | |
| 140 *peb_address = process_basic_information.PebBaseAddress; | |
|
Mark Mentovai
2015/09/16 02:57:20
if (!is_wow64) {
// this assignment
} else {
/
scottmg
2015/09/16 18:05:07
Done.
| |
| 141 if (is_wow64) { | |
| 142 ULONG_PTR wow64_peb_address; | |
| 143 status = crashpad::NtQueryInformationProcess(process, | |
| 144 ProcessWow64Information, | |
|
Mark Mentovai
2015/09/16 02:57:20
It’s a little weird that the thing named this way
scottmg
2015/09/16 18:05:07
Yeah, the limited bit that MSDN documented is conf
| |
| 145 &wow64_peb_address, | |
| 146 sizeof(wow64_peb_address), | |
| 147 &bytes_returned); | |
| 148 if (!NT_SUCCESS(status)) { | |
| 149 NTSTATUS_LOG(ERROR, status), "NtQueryInformationProcess"; | |
| 150 return false; | |
| 151 } | |
| 152 if (bytes_returned != sizeof(wow64_peb_address)) { | |
| 153 LOG(ERROR) << "NtQueryInformationProcess incorrect size"; | |
| 154 return false; | |
| 155 } | |
| 156 *peb_address = wow64_peb_address; | |
| 157 } | |
| 158 | |
| 159 return true; | |
| 160 } | |
| 161 | |
| 162 template <class Traits> | |
| 105 bool ReadProcessData(HANDLE process, | 163 bool ReadProcessData(HANDLE process, |
| 106 WinVMAddress peb_address_vmaddr, | 164 WinVMAddress peb_address_vmaddr, |
| 107 ProcessInfo* process_info) { | 165 ProcessInfo* process_info) { |
| 166 | |
|
Mark Mentovai
2015/09/16 02:57:20
Unnecessary new blank line.
scottmg
2015/09/16 18:05:06
Done.
| |
| 108 Traits::Pointer peb_address; | 167 Traits::Pointer peb_address; |
| 109 if (!AssignIfInRange(&peb_address, peb_address_vmaddr)) { | 168 if (!AssignIfInRange(&peb_address, peb_address_vmaddr)) { |
| 110 LOG(ERROR) << "peb_address_vmaddr " << peb_address_vmaddr | 169 LOG(ERROR) << "peb address" << peb_address_vmaddr << " out of range"; |
|
Mark Mentovai
2015/09/16 02:57:20
Need a space after the word “address”.
peb_addres
scottmg
2015/09/16 18:05:06
Done.
| |
| 111 << " out of range"; | |
| 112 return false; | 170 return false; |
| 113 } | 171 } |
| 114 | 172 |
| 115 // Try to read the process environment block. | 173 // Try to read the process environment block. |
| 116 process_types::PEB<Traits> peb; | 174 process_types::PEB<Traits> peb; |
| 117 if (!ReadStruct(process, peb_address, &peb)) | 175 if (!ReadStruct(process, peb_address, &peb)) |
| 118 return false; | 176 return false; |
| 119 | 177 |
| 120 process_types::RTL_USER_PROCESS_PARAMETERS<Traits> process_parameters; | 178 process_types::RTL_USER_PROCESS_PARAMETERS<Traits> process_parameters; |
| 121 if (!ReadStruct(process, peb.ProcessParameters, &process_parameters)) | 179 if (!ReadStruct(process, peb.ProcessParameters, &process_parameters)) |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 205 initialized_() { | 263 initialized_() { |
| 206 } | 264 } |
| 207 | 265 |
| 208 ProcessInfo::~ProcessInfo() { | 266 ProcessInfo::~ProcessInfo() { |
| 209 } | 267 } |
| 210 | 268 |
| 211 bool ProcessInfo::Initialize(HANDLE process) { | 269 bool ProcessInfo::Initialize(HANDLE process) { |
| 212 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); | 270 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); |
| 213 | 271 |
| 214 is_wow64_ = IsProcessWow64(process); | 272 is_wow64_ = IsProcessWow64(process); |
| 273 bool self_is_wow64 = IsProcessWow64(GetCurrentProcess()); | |
|
Mark Mentovai
2015/09/16 02:57:20
Don’t declare it ’til you need it. Since you only
scottmg
2015/09/16 18:05:07
Gone.
| |
| 215 | 274 |
| 216 if (is_wow64_) { | 275 if (is_wow64_) { |
| 217 // If it's WoW64, then it's 32-on-64. | 276 // If it's WoW64, then it's 32-on-64. |
| 218 is_64_bit_ = false; | 277 is_64_bit_ = false; |
| 219 } else { | 278 } else { |
| 220 // Otherwise, it's either 32 on 32, or 64 on 64. Use GetSystemInfo() to | 279 // Otherwise, it's either 32 on 32, or 64 on 64. Use GetSystemInfo() to |
| 221 // distinguish between these two cases. | 280 // distinguish between these two cases. |
| 222 SYSTEM_INFO system_info; | 281 SYSTEM_INFO system_info; |
| 223 GetSystemInfo(&system_info); | 282 GetSystemInfo(&system_info); |
| 224 is_64_bit_ = | 283 is_64_bit_ = |
| 225 system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64; | 284 system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64; |
| 226 } | 285 } |
| 227 | 286 |
| 228 #if ARCH_CPU_32_BITS | 287 #if ARCH_CPU_32_BITS |
| 229 if (is_64_bit_) { | 288 if (is_64_bit_) { |
| 230 LOG(ERROR) << "Reading x64 process from x86 process not supported"; | 289 LOG(ERROR) << "Reading x64 process from x86 process not supported"; |
| 231 return false; | 290 return false; |
| 232 } | 291 } |
| 233 #endif | 292 #endif |
| 234 | 293 |
| 235 ULONG bytes_returned; | 294 WinVMAddress peb_address; |
| 236 // We assume this process is not running on Wow64. The | 295 bool result = |
| 237 // PROCESS_BASIC_INFORMATION uses the OS size (that is, even Wow64 has a 64 | 296 (is_64_bit_ || (is_wow64_ && !self_is_wow64)) |
|
Mark Mentovai
2015/09/16 02:57:20
This condition makes my head hurt. It seems like i
scottmg
2015/09/16 18:05:07
Me too! I think what it really needed to be was ba
| |
| 238 // bit one.) | 297 ? GetProcessBasicInformation<process_types::internal::Traits64>( |
| 239 // TODO(scottmg): Either support running as Wow64, or check/resolve this at a | 298 process, is_wow64_, this, &peb_address) |
| 240 // higher level. | 299 : GetProcessBasicInformation<process_types::internal::Traits32>( |
| 241 #if ARCH_CPU_32_BITS | 300 process, is_wow64_, this, &peb_address); |
| 242 process_types::PROCESS_BASIC_INFORMATION<process_types::internal::Traits32> | 301 if (!result) { |
| 243 process_basic_information; | 302 LOG(ERROR) << "GetProcessBasicInformation failed"; |
| 244 #else | |
| 245 process_types::PROCESS_BASIC_INFORMATION<process_types::internal::Traits64> | |
| 246 process_basic_information; | |
| 247 #endif | |
| 248 NTSTATUS status = | |
| 249 crashpad::NtQueryInformationProcess(process, | |
| 250 ProcessBasicInformation, | |
| 251 &process_basic_information, | |
| 252 sizeof(process_basic_information), | |
| 253 &bytes_returned); | |
| 254 if (status < 0) { | |
| 255 LOG(ERROR) << "NtQueryInformationProcess: status=" << status; | |
| 256 return false; | |
| 257 } | |
| 258 if (bytes_returned != sizeof(process_basic_information)) { | |
| 259 LOG(ERROR) << "NtQueryInformationProcess incorrect size"; | |
| 260 return false; | 303 return false; |
| 261 } | 304 } |
| 262 | 305 |
| 263 // See https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203 on | 306 result = is_64_bit_ ? ReadProcessData<process_types::internal::Traits64>( |
| 264 // 32 bit being the correct size for HANDLEs for proceses, even on Windows | |
| 265 // x64. API functions (e.g. OpenProcess) take only a DWORD, so there's no | |
| 266 // sense in maintaining the top bits. | |
| 267 process_id_ = static_cast<DWORD>(process_basic_information.UniqueProcessId); | |
| 268 inherited_from_process_id_ = static_cast<DWORD>( | |
| 269 process_basic_information.InheritedFromUniqueProcessId); | |
| 270 | |
| 271 // We now want to read the PEB to gather the rest of our information. The | |
| 272 // PebBaseAddress as returned above is what we want for 64-on-64 and 32-on-32, | |
| 273 // but for Wow64, we want to read the 32 bit PEB (a Wow64 process has both). | |
| 274 // The address of this is found by a second call to NtQueryInformationProcess. | |
| 275 WinVMAddress peb_address = process_basic_information.PebBaseAddress; | |
| 276 if (is_wow64_) { | |
| 277 ULONG_PTR wow64_peb_address; | |
| 278 status = | |
| 279 crashpad::NtQueryInformationProcess(process, | |
| 280 ProcessWow64Information, | |
| 281 &wow64_peb_address, | |
| 282 sizeof(wow64_peb_address), | |
| 283 &bytes_returned); | |
| 284 if (status < 0) { | |
| 285 LOG(ERROR) << "NtQueryInformationProcess: status=" << status; | |
| 286 return false; | |
| 287 } | |
| 288 if (bytes_returned != sizeof(wow64_peb_address)) { | |
| 289 LOG(ERROR) << "NtQueryInformationProcess incorrect size"; | |
| 290 return false; | |
| 291 } | |
| 292 peb_address = wow64_peb_address; | |
| 293 } | |
| 294 | |
| 295 // Read the PEB data using the correct word size. | |
| 296 bool result = is_64_bit_ ? ReadProcessData<process_types::internal::Traits64>( | |
| 297 process, peb_address, this) | 307 process, peb_address, this) |
| 298 : ReadProcessData<process_types::internal::Traits32>( | 308 : ReadProcessData<process_types::internal::Traits32>( |
| 299 process, peb_address, this); | 309 process, peb_address, this); |
| 300 if (!result) | 310 if (!result) { |
| 311 LOG(ERROR) << "ReadProcessData failed"; | |
| 301 return false; | 312 return false; |
| 313 } | |
| 302 | 314 |
| 303 INITIALIZATION_STATE_SET_VALID(initialized_); | 315 INITIALIZATION_STATE_SET_VALID(initialized_); |
| 304 return true; | 316 return true; |
| 305 } | 317 } |
| 306 | 318 |
| 307 bool ProcessInfo::Is64Bit() const { | 319 bool ProcessInfo::Is64Bit() const { |
| 308 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | 320 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| 309 return is_64_bit_; | 321 return is_64_bit_; |
| 310 } | 322 } |
| 311 | 323 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 330 return true; | 342 return true; |
| 331 } | 343 } |
| 332 | 344 |
| 333 bool ProcessInfo::Modules(std::vector<Module>* modules) const { | 345 bool ProcessInfo::Modules(std::vector<Module>* modules) const { |
| 334 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | 346 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| 335 *modules = modules_; | 347 *modules = modules_; |
| 336 return true; | 348 return true; |
| 337 } | 349 } |
| 338 | 350 |
| 339 } // namespace crashpad | 351 } // namespace crashpad |
| OLD | NEW |