Chromium Code Reviews| 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 "util/win/process_info.h" | |
| 16 | |
| 17 namespace crashpad { | |
| 18 | |
| 19 namespace { | |
| 20 | |
| 21 std::wstring ReadUnicodeString(HANDLE process, const UNICODE_STRING& us) { | |
|
Mark Mentovai
2015/03/05 17:32:22
In returning, this should have a way to distinguis
scottmg
2015/03/05 20:31:06
Done.
| |
| 22 std::wstring str; | |
| 23 if (us.Length > 0) { | |
| 24 str.resize(us.Length / sizeof(wchar_t)); | |
|
Mark Mentovai
2015/03/05 17:32:22
DCHECK_EQ(us.Length % sizeof(wchar_t), 0)
scottmg
2015/03/05 20:31:06
Done.
| |
| 25 SIZE_T bytes_read; | |
| 26 if (!ReadProcessMemory( | |
|
Mark Mentovai
2015/03/05 17:32:22
If I’m reading this correctly, for cross-bitted op
scottmg
2015/03/05 20:31:06
I haven't tested it yet, but yes, I believe that's
| |
| 27 process, us.Buffer, &str[0], us.Length, &bytes_read) || | |
| 28 bytes_read != us.Length) { | |
| 29 PLOG(ERROR) << "ReadProcessMemory UNICODE_STRING"; | |
|
Mark Mentovai
2015/03/05 17:32:22
#include "base/logging.h". Also, PLOG is incorrect
scottmg
2015/03/05 20:31:06
Done.
| |
| 30 return std::wstring(); | |
| 31 } | |
| 32 } | |
| 33 return str; | |
| 34 } | |
| 35 | |
| 36 template <class T> bool ReadStruct(HANDLE process, void* at, T* into) { | |
|
Mark Mentovai
2015/03/05 17:32:22
const void* at, but
Using pointer types to refer
scottmg
2015/03/05 20:31:06
Switched to uintptr_t. ReadProcessMemory just uses
| |
| 37 SIZE_T bytes_read; | |
| 38 if (!ReadProcessMemory(process, at, into, sizeof(T), &bytes_read) || | |
| 39 bytes_read != sizeof(T)) { | |
| 40 // We don't have a name for the type we're reading, so include the signature | |
| 41 // to get the type of T. | |
| 42 PLOG(ERROR) << "ReadProcessMemory: " << __FUNCSIG__; | |
| 43 return false; | |
| 44 } | |
| 45 return true; | |
| 46 } | |
| 47 | |
| 48 // This is similar to PEB_LDR_DATA in winternl.h, but includes the | |
| 49 // InInitializationOrderModuleList field. | |
| 50 struct FULL_PEB_LDR_DATA { | |
|
Mark Mentovai
2015/03/05 17:32:22
Since you don’t need Length or Initialized, you ca
scottmg
2015/03/05 20:31:06
Done.
| |
| 51 ULONG Length; | |
| 52 BOOLEAN Initialized; | |
| 53 PVOID Reserved; | |
| 54 LIST_ENTRY InLoadOrderModuleList; | |
|
Mark Mentovai
2015/03/05 17:32:22
What’s the difference between load order and initi
scottmg
2015/03/05 20:31:07
Load and Memory order seem to always be the same (
| |
| 55 LIST_ENTRY InMemoryOrderModuleList; | |
| 56 LIST_ENTRY InInitializationOrderModuleList; | |
| 57 }; | |
| 58 | |
| 59 } // namespace | |
| 60 | |
| 61 ProcessInfo::ProcessInfo() | |
| 62 : process_basic_information_(), | |
| 63 command_line_(), | |
| 64 is64bit_(false), | |
| 65 iswow64_(FALSE) { | |
| 66 } | |
| 67 | |
| 68 ProcessInfo::~ProcessInfo() { | |
| 69 } | |
| 70 | |
| 71 bool ProcessInfo::Initialize(HANDLE process) { | |
| 72 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); | |
| 73 | |
| 74 decltype(NtQueryInformationProcess)* nt_query_information_process = | |
|
Mark Mentovai
2015/03/05 17:32:22
I like to wrap these kinds of things in their own
scottmg
2015/03/05 20:31:06
Done.
| |
| 75 reinterpret_cast<decltype(NtQueryInformationProcess)*>(GetProcAddress( | |
| 76 LoadLibrary(L"ntdll.dll"), "NtQueryInformationProcess")); | |
| 77 if (!nt_query_information_process) { | |
| 78 PLOG(ERROR) << "GetProcAddress NtQueryInformationProcess failed"; | |
| 79 return false; | |
| 80 } | |
| 81 | |
| 82 ULONG bytes_returned; | |
| 83 NTSTATUS status = | |
| 84 nt_query_information_process(process, | |
| 85 ProcessBasicInformation, | |
| 86 &process_basic_information_, | |
| 87 sizeof(process_basic_information_), | |
| 88 &bytes_returned); | |
| 89 if (status < 0 || bytes_returned != sizeof(process_basic_information_)) { | |
| 90 LOG(ERROR) << "NtQueryInformationProcess"; | |
|
Mark Mentovai
2015/03/05 17:32:22
If status < 0, the value of status might be a good
scottmg
2015/03/05 20:31:07
Done.
| |
| 91 return false; | |
| 92 } | |
| 93 | |
| 94 // Try to read the process environment block. | |
| 95 PEB peb; | |
| 96 if (!ReadStruct(process, process_basic_information_.PebBaseAddress, &peb)) | |
|
Mark Mentovai
2015/03/05 17:32:22
This looks like the first point where cross-bitted
scottmg
2015/03/05 20:31:06
Right, good point.
For now I've moved the 32/64 c
| |
| 97 return false; | |
| 98 | |
| 99 RTL_USER_PROCESS_PARAMETERS process_parameters; | |
| 100 if (!ReadStruct(process, peb.ProcessParameters, &process_parameters)) | |
| 101 return false; | |
| 102 | |
| 103 command_line_ = | |
| 104 ReadUnicodeString(process, process_parameters.CommandLine); | |
| 105 if (command_line_.empty()) | |
| 106 return false; | |
| 107 | |
| 108 FULL_PEB_LDR_DATA peb_ldr_data; | |
| 109 if (!ReadStruct(process, peb.Ldr, &peb_ldr_data)) | |
| 110 return false; | |
| 111 | |
| 112 // Walk the PEB LDR structure (doubly-linked list) to get the list of loaded | |
| 113 // modules. We awkwardly use the Reserved fields of LDR_DATA_TABLE_ENTRY to | |
| 114 // get the modules in InitializationOrder rather than MemoryOrder. | |
| 115 LIST_ENTRY* cur = peb_ldr_data.InInitializationOrderModuleList.Flink; | |
| 116 LIST_ENTRY* last = peb_ldr_data.InInitializationOrderModuleList.Blink; | |
| 117 for (;;) { | |
|
Mark Mentovai
2015/03/05 17:32:21
You could hoist some stuff into the for construct
scottmg
2015/03/05 20:31:06
Some hoisted. Unfortunately, it's a "back" pointer
| |
| 118 // |cur| is the pointer to the LIST_ENTRY embedded in the | |
| 119 // LDR_DATA_TABLE_ENTRY, in the target process's address space. So we need | |
| 120 // to read from the target, and also offset back to the beginning of the | |
| 121 // structure. | |
| 122 LDR_DATA_TABLE_ENTRY ldr_data_table_entry; | |
| 123 if (!ReadStruct(process, | |
|
Mark Mentovai
2015/03/05 17:32:22
Your CL description had me geared up for a truly h
scottmg
2015/03/05 20:31:07
All in the eye of the beholder, I suppose. :)
| |
| 124 reinterpret_cast<char*>(cur) - | |
| 125 offsetof(LDR_DATA_TABLE_ENTRY, Reserved2), | |
|
Mark Mentovai
2015/03/05 17:32:22
I see.
Presumably, LDR_DATA_TABLE_ENTRY really st
scottmg
2015/03/05 20:31:07
That's right.
| |
| 126 &ldr_data_table_entry)) | |
| 127 return false; | |
|
Mark Mentovai
2015/03/05 17:32:22
{} around this, its controlling condition is so lo
scottmg
2015/03/05 20:31:06
Done.
| |
| 128 // TODO(scottmg): Capture TimeDateStamp, Checksum, etc. too? | |
| 129 std::wstring module = | |
| 130 ReadUnicodeString(process, ldr_data_table_entry.FullDllName); | |
| 131 if (module.empty()) | |
| 132 return false; | |
|
Mark Mentovai
2015/03/05 17:32:22
A bad module should probably invalidate that modul
scottmg
2015/03/05 20:31:06
Done. I was concerned that a bad PEB meant the wor
| |
| 133 modules_.push_back(module); | |
| 134 if (cur == last) | |
| 135 break; | |
| 136 cur = reinterpret_cast<LIST_ENTRY*>(&ldr_data_table_entry.Reserved2)->Flink; | |
| 137 } | |
| 138 | |
| 139 decltype(IsWow64Process)* is_wow64_process = | |
|
Mark Mentovai
2015/03/05 17:32:22
If you break this one into its own function, you c
scottmg
2015/03/05 20:31:07
Done.
| |
| 140 reinterpret_cast<decltype(IsWow64Process)*>( | |
| 141 GetProcAddress(LoadLibrary(L"kernel32.dll"), "IsWow64Process")); | |
| 142 if (!is_wow64_process) { | |
| 143 // This means kernel32 doesn't implement this function, so there's no such | |
| 144 // thing as WoW64 on this OS. | |
| 145 iswow64_ = FALSE; | |
| 146 } else if (!is_wow64_process(process, &iswow64_)) { | |
| 147 PLOG(ERROR) << "IsWow64Process"; | |
| 148 return false; | |
| 149 } | |
| 150 | |
| 151 if (iswow64_) { | |
| 152 // If it's WoW64, then it's 32-on-64. | |
| 153 is64bit_ = false; | |
| 154 } else { | |
| 155 // Otherwise, it's either 32 on 32, or 64 on 64. Use GetSystemInfo() to | |
| 156 // distinguish between these two cases. | |
| 157 SYSTEM_INFO system_info; | |
| 158 GetSystemInfo(&system_info); | |
| 159 is64bit_ = | |
| 160 system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64; | |
| 161 } | |
| 162 | |
| 163 INITIALIZATION_STATE_SET_VALID(initialized_); | |
| 164 return true; | |
| 165 } | |
| 166 | |
| 167 bool ProcessInfo::Is64Bit() const { | |
| 168 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 169 return is64bit_; | |
| 170 } | |
| 171 | |
| 172 bool ProcessInfo::IsWow64() const { | |
| 173 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 174 return iswow64_; | |
| 175 } | |
| 176 | |
| 177 pid_t ProcessInfo::ProcessID() const { | |
| 178 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 179 return process_basic_information_.UniqueProcessId; | |
| 180 } | |
| 181 | |
| 182 pid_t ProcessInfo::ParentProcessID() const { | |
| 183 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 184 return reinterpret_cast<ULONG_PTR>(process_basic_information_.Reserved3); | |
|
Mark Mentovai
2015/03/05 17:32:22
Can process_basic_information_ be a union type tha
scottmg
2015/03/05 20:31:06
Added FULL_... for this type too.
| |
| 185 } | |
| 186 | |
| 187 bool ProcessInfo::CommandLine(std::wstring* command_line) const { | |
| 188 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 189 *command_line = command_line_; | |
| 190 return true; | |
| 191 } | |
| 192 | |
| 193 bool ProcessInfo::Modules(std::vector<std::wstring>* modules) const { | |
| 194 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 195 *modules = modules_; | |
| 196 return true; | |
| 197 } | |
| 198 | |
| 199 } // namespace crashpad | |
| OLD | NEW |