| OLD | NEW |
| 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, |
| (...skipping 62 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, uintptr_t at, T* into) { | 83 template <class T> bool ReadStruct(HANDLE process, WinVMAddress at, T* into) { |
| 84 SIZE_T bytes_read; | 84 SIZE_T bytes_read; |
| 85 if (!ReadProcessMemory(process, | 85 if (!ReadProcessMemory(process, |
| 86 reinterpret_cast<const void*>(at), | 86 reinterpret_cast<const void*>(at), |
| 87 into, | 87 into, |
| 88 sizeof(T), | 88 sizeof(T), |
| 89 &bytes_read)) { | 89 &bytes_read)) { |
| 90 // We don't have a name for the type we're reading, so include the signature | 90 // We don't have a name for the type we're reading, so include the signature |
| 91 // to get the type of T. | 91 // to get the type of T. |
| 92 PLOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__; | 92 PLOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__; |
| 93 return false; | 93 return false; |
| 94 } | 94 } |
| 95 if (bytes_read != sizeof(T)) { | 95 if (bytes_read != sizeof(T)) { |
| 96 LOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__ << " incorrect size"; | 96 LOG(ERROR) << "ReadProcessMemory " << __FUNCSIG__ << " incorrect size"; |
| 97 return false; | 97 return false; |
| 98 } | 98 } |
| 99 return true; | 99 return true; |
| 100 } | 100 } |
| 101 | 101 |
| 102 } // namespace | 102 } // namespace |
| 103 | 103 |
| 104 template <class Traits> | 104 template <class Traits> |
| 105 bool ReadProcessData(HANDLE process, | 105 bool ReadProcessData(HANDLE process, |
| 106 uintptr_t peb_address_uintptr, | 106 WinVMAddress peb_address_vmaddr, |
| 107 ProcessInfo* process_info) { | 107 ProcessInfo* process_info) { |
| 108 Traits::Pointer peb_address; | 108 Traits::Pointer peb_address; |
| 109 if (!AssignIfInRange(&peb_address, peb_address_uintptr)) { | 109 if (!AssignIfInRange(&peb_address, peb_address_vmaddr)) { |
| 110 LOG(ERROR) << "peb_address_uintptr " << peb_address_uintptr | 110 LOG(ERROR) << "peb_address_vmaddr " << peb_address_vmaddr |
| 111 << " out of range"; | 111 << " out of range"; |
| 112 return false; | 112 return false; |
| 113 } | 113 } |
| 114 | 114 |
| 115 // Try to read the process environment block. | 115 // Try to read the process environment block. |
| 116 process_types::PEB<Traits> peb; | 116 process_types::PEB<Traits> peb; |
| 117 if (!ReadStruct(process, peb_address, &peb)) | 117 if (!ReadStruct(process, peb_address, &peb)) |
| 118 return false; | 118 return false; |
| 119 | 119 |
| 120 process_types::RTL_USER_PROCESS_PARAMETERS<Traits> process_parameters; | 120 process_types::RTL_USER_PROCESS_PARAMETERS<Traits> process_parameters; |
| 121 if (!ReadStruct(process, peb.ProcessParameters, &process_parameters)) | 121 if (!ReadStruct(process, peb.ProcessParameters, &process_parameters)) |
| 122 return false; | 122 return false; |
| 123 | 123 |
| 124 if (!ReadUnicodeString(process, | 124 if (!ReadUnicodeString(process, |
| 125 process_parameters.CommandLine, | 125 process_parameters.CommandLine, |
| 126 &process_info->command_line_)) { | 126 &process_info->command_line_)) { |
| 127 return false; | 127 return false; |
| 128 } | 128 } |
| 129 | 129 |
| 130 process_types::PEB_LDR_DATA<Traits> peb_ldr_data; | 130 process_types::PEB_LDR_DATA<Traits> peb_ldr_data; |
| 131 if (!ReadStruct(process, peb.Ldr, &peb_ldr_data)) | 131 if (!ReadStruct(process, peb.Ldr, &peb_ldr_data)) |
| 132 return false; | 132 return false; |
| 133 | 133 |
| 134 std::wstring module; | |
| 135 process_types::LDR_DATA_TABLE_ENTRY<Traits> ldr_data_table_entry; | 134 process_types::LDR_DATA_TABLE_ENTRY<Traits> ldr_data_table_entry; |
| 136 | 135 |
| 137 // Include the first module in the memory order list to get our the main | 136 // Include the first module in the memory order list to get our the main |
| 138 // executable's name, as it's not included in initialization order below. | 137 // executable's name, as it's not included in initialization order below. |
| 139 if (!ReadStruct(process, | 138 if (!ReadStruct(process, |
| 140 reinterpret_cast<uintptr_t>( | 139 reinterpret_cast<WinVMAddress>( |
| 141 reinterpret_cast<const char*>( | 140 reinterpret_cast<const char*>( |
| 142 peb_ldr_data.InMemoryOrderModuleList.Flink) - | 141 peb_ldr_data.InMemoryOrderModuleList.Flink) - |
| 143 offsetof(process_types::LDR_DATA_TABLE_ENTRY<Traits>, | 142 offsetof(process_types::LDR_DATA_TABLE_ENTRY<Traits>, |
| 144 InMemoryOrderLinks)), | 143 InMemoryOrderLinks)), |
| 145 &ldr_data_table_entry)) { | 144 &ldr_data_table_entry)) { |
| 146 return false; | 145 return false; |
| 147 } | 146 } |
| 148 if (!ReadUnicodeString(process, ldr_data_table_entry.FullDllName, &module)) | 147 ProcessInfo::Module module; |
| 148 if (!ReadUnicodeString( |
| 149 process, ldr_data_table_entry.FullDllName, &module.name)) { |
| 149 return false; | 150 return false; |
| 151 } |
| 152 module.dll_base = ldr_data_table_entry.DllBase; |
| 153 module.size = ldr_data_table_entry.SizeOfImage; |
| 154 module.timestamp = ldr_data_table_entry.TimeDateStamp; |
| 150 process_info->modules_.push_back(module); | 155 process_info->modules_.push_back(module); |
| 151 | 156 |
| 152 // Walk the PEB LDR structure (doubly-linked list) to get the list of loaded | 157 // Walk the PEB LDR structure (doubly-linked list) to get the list of loaded |
| 153 // modules. We use this method rather than EnumProcessModules to get the | 158 // modules. We use this method rather than EnumProcessModules to get the |
| 154 // modules in initialization order rather than memory order. | 159 // modules in initialization order rather than memory order. |
| 155 Traits::Pointer last = peb_ldr_data.InInitializationOrderModuleList.Blink; | 160 Traits::Pointer last = peb_ldr_data.InInitializationOrderModuleList.Blink; |
| 156 for (Traits::Pointer cur = peb_ldr_data.InInitializationOrderModuleList.Flink; | 161 for (Traits::Pointer cur = peb_ldr_data.InInitializationOrderModuleList.Flink; |
| 157 ; | 162 ; |
| 158 cur = ldr_data_table_entry.InInitializationOrderLinks.Flink) { | 163 cur = ldr_data_table_entry.InInitializationOrderLinks.Flink) { |
| 159 // |cur| is the pointer to the LIST_ENTRY embedded in the | 164 // |cur| is the pointer to the LIST_ENTRY embedded in the |
| 160 // LDR_DATA_TABLE_ENTRY, in the target process's address space. So we need | 165 // LDR_DATA_TABLE_ENTRY, in the target process's address space. So we need |
| 161 // to read from the target, and also offset back to the beginning of the | 166 // to read from the target, and also offset back to the beginning of the |
| 162 // structure. | 167 // structure. |
| 163 if (!ReadStruct(process, | 168 if (!ReadStruct(process, |
| 164 reinterpret_cast<uintptr_t>( | 169 reinterpret_cast<WinVMAddress>( |
| 165 reinterpret_cast<const char*>(cur) - | 170 reinterpret_cast<const char*>(cur) - |
| 166 offsetof(process_types::LDR_DATA_TABLE_ENTRY<Traits>, | 171 offsetof(process_types::LDR_DATA_TABLE_ENTRY<Traits>, |
| 167 InInitializationOrderLinks)), | 172 InInitializationOrderLinks)), |
| 168 &ldr_data_table_entry)) { | 173 &ldr_data_table_entry)) { |
| 169 break; | 174 break; |
| 170 } | 175 } |
| 171 // TODO(scottmg): Capture TimeDateStamp, Checksum, etc. too? | 176 // TODO(scottmg): Capture Checksum, etc. too? |
| 172 if (!ReadUnicodeString(process, ldr_data_table_entry.FullDllName, &module)) | 177 if (!ReadUnicodeString( |
| 178 process, ldr_data_table_entry.FullDllName, &module.name)) { |
| 173 break; | 179 break; |
| 180 } |
| 181 module.dll_base = ldr_data_table_entry.DllBase; |
| 182 module.size = ldr_data_table_entry.SizeOfImage; |
| 183 module.timestamp = ldr_data_table_entry.TimeDateStamp; |
| 174 process_info->modules_.push_back(module); | 184 process_info->modules_.push_back(module); |
| 175 if (cur == last) | 185 if (cur == last) |
| 176 break; | 186 break; |
| 177 } | 187 } |
| 178 | 188 |
| 179 return true; | 189 return true; |
| 180 } | 190 } |
| 181 | 191 |
| 192 ProcessInfo::Module::Module() : name(), dll_base(0), size(0), timestamp() { |
| 193 } |
| 194 |
| 195 ProcessInfo::Module::~Module() { |
| 196 } |
| 197 |
| 182 ProcessInfo::ProcessInfo() | 198 ProcessInfo::ProcessInfo() |
| 183 : process_id_(), | 199 : process_id_(), |
| 184 inherited_from_process_id_(), | 200 inherited_from_process_id_(), |
| 185 command_line_(), | 201 command_line_(), |
| 186 modules_(), | 202 modules_(), |
| 187 is_64_bit_(false), | 203 is_64_bit_(false), |
| 188 is_wow64_(false), | 204 is_wow64_(false), |
| 189 initialized_() { | 205 initialized_() { |
| 190 } | 206 } |
| 191 | 207 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 244 return false; | 260 return false; |
| 245 } | 261 } |
| 246 process_id_ = process_basic_information.UniqueProcessId; | 262 process_id_ = process_basic_information.UniqueProcessId; |
| 247 inherited_from_process_id_ = | 263 inherited_from_process_id_ = |
| 248 process_basic_information.InheritedFromUniqueProcessId; | 264 process_basic_information.InheritedFromUniqueProcessId; |
| 249 | 265 |
| 250 // We now want to read the PEB to gather the rest of our information. The | 266 // We now want to read the PEB to gather the rest of our information. The |
| 251 // PebBaseAddress as returned above is what we want for 64-on-64 and 32-on-32, | 267 // PebBaseAddress as returned above is what we want for 64-on-64 and 32-on-32, |
| 252 // but for Wow64, we want to read the 32 bit PEB (a Wow64 process has both). | 268 // but for Wow64, we want to read the 32 bit PEB (a Wow64 process has both). |
| 253 // The address of this is found by a second call to NtQueryInformationProcess. | 269 // The address of this is found by a second call to NtQueryInformationProcess. |
| 254 uintptr_t peb_address = process_basic_information.PebBaseAddress; | 270 WinVMAddress peb_address = process_basic_information.PebBaseAddress; |
| 255 if (is_wow64_) { | 271 if (is_wow64_) { |
| 256 ULONG_PTR wow64_peb_address; | 272 ULONG_PTR wow64_peb_address; |
| 257 status = | 273 status = |
| 258 crashpad::NtQueryInformationProcess(process, | 274 crashpad::NtQueryInformationProcess(process, |
| 259 ProcessWow64Information, | 275 ProcessWow64Information, |
| 260 &wow64_peb_address, | 276 &wow64_peb_address, |
| 261 sizeof(wow64_peb_address), | 277 sizeof(wow64_peb_address), |
| 262 &bytes_returned); | 278 &bytes_returned); |
| 263 if (status < 0) { | 279 if (status < 0) { |
| 264 LOG(ERROR) << "NtQueryInformationProcess: status=" << status; | 280 LOG(ERROR) << "NtQueryInformationProcess: status=" << status; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 302 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | 318 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| 303 return inherited_from_process_id_; | 319 return inherited_from_process_id_; |
| 304 } | 320 } |
| 305 | 321 |
| 306 bool ProcessInfo::CommandLine(std::wstring* command_line) const { | 322 bool ProcessInfo::CommandLine(std::wstring* command_line) const { |
| 307 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | 323 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| 308 *command_line = command_line_; | 324 *command_line = command_line_; |
| 309 return true; | 325 return true; |
| 310 } | 326 } |
| 311 | 327 |
| 312 bool ProcessInfo::Modules(std::vector<std::wstring>* modules) const { | 328 bool ProcessInfo::Modules(std::vector<Module>* modules) const { |
| 313 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | 329 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| 314 *modules = modules_; | 330 *modules = modules_; |
| 315 return true; | 331 return true; |
| 316 } | 332 } |
| 317 | 333 |
| 318 } // namespace crashpad | 334 } // namespace crashpad |
| OLD | NEW |