1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
|
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/test/base/process_inspector_win.h"
#include <winternl.h>
#include "base/logging.h"
#include "base/process/process.h"
#include "base/win/windows_version.h"
namespace {
// Certain Windows types that depend on the word size of the OS (rather than the
// size of the current process) are defined here.
// PROCESS_BASIC_INFORMATION.
template <class Traits>
struct ProcessInformation {
using RemotePointer = typename Traits::RemotePointer;
DWORD exit_status() const { return static_cast<DWORD>(exit_status_); }
RemotePointer peb_base_address() const { return peb_base_address_; }
RemotePointer affinity_mask() const { return affinity_mask_; }
int base_priority() const { return static_cast<int>(base_priority_); }
DWORD unique_process_id() const { return static_cast<DWORD>(unique_pid_); }
DWORD inherited_from_unique_process_id() const {
return static_cast<DWORD>(inherited_from_unique_process_id_);
}
private:
RemotePointer exit_status_;
RemotePointer peb_base_address_;
RemotePointer affinity_mask_;
RemotePointer base_priority_;
RemotePointer unique_pid_;
RemotePointer inherited_from_unique_process_id_;
};
// A subset of a process's environment block.
template <class Traits>
struct ProcessExecutionBlock {
using RemotePointer = typename Traits::RemotePointer;
uint8_t InheritedAddressSpace;
uint8_t ReadImageFileExecOptions;
uint8_t BeingDebugged;
uint8_t ProcessFlags;
uint8_t Padding[4];
RemotePointer Mutant;
RemotePointer ImageBaseAddress;
RemotePointer Ldr;
RemotePointer ProcessParameters; // RtlUserProcessParameters
};
// UNICODE_STRING.
template <class Traits>
struct UnicodeString {
using RemotePointer = typename Traits::RemotePointer;
uint16_t Length;
uint16_t MaximumLength;
RemotePointer Buffer;
};
// CURDIR.
template <class Traits>
struct CurDir {
using RemotePointer = typename Traits::RemotePointer;
UnicodeString<Traits> DosPath;
RemotePointer Handle;
};
// RTL_USER_PROCESS_PARAMETERS.
template <class Traits>
struct RtlUserProcessParameters {
using RemotePointer = typename Traits::RemotePointer;
uint32_t MaximumLength;
uint32_t Length;
uint32_t Flags;
uint32_t DebugFlags;
RemotePointer ConsoleHandle;
uint32_t ConsoleFlags;
RemotePointer StandardInput;
RemotePointer StandardOutput;
RemotePointer StandardError;
CurDir<Traits> CurrentDirectory;
UnicodeString<Traits> DllPath;
UnicodeString<Traits> ImagePathName;
UnicodeString<Traits> CommandLine;
};
// A concrete ProcessInspector that can read from another process based on the
// architecture. |Traits| specifies traits based on the OS architecture.
template <class Traits>
class Inspector : public ProcessInspector {
public:
Inspector();
Inspector(const Inspector&) = delete;
Inspector& operator=(const Inspector&) = delete;
// ProcessInspector:
DWORD GetParentPid() const override;
const std::wstring& command_line() const override;
private:
// ProcessInspector:
bool Inspect(const base::Process& process) override;
ProcessInformation<Traits> process_basic_information_;
ProcessExecutionBlock<Traits> peb_;
RtlUserProcessParameters<Traits> process_parameters_;
std::wstring command_line_;
};
#if !defined(_WIN64)
// Traits for a 32-bit process running in WoW.
struct Wow64Traits {
// The name of the ntdll function to query process information.
static const char kQueryProcessInformationFunctionName[];
// The type of a pointer to the read process memory function.
using ReadMemoryFn =
NTSTATUS(NTAPI*)(HANDLE, uint64_t, void*, uint64_t, uint64_t*);
// An unsigned integer type matching the size of a pointer in the remote
// process.
using RemotePointer = uint64_t;
// Returns the function to read memory from a remote process.
static ReadMemoryFn GetReadMemoryFn() {
return reinterpret_cast<ReadMemoryFn>(::GetProcAddress(
::GetModuleHandle(L"ntdll.dll"), "NtWow64ReadVirtualMemory64"));
}
// Reads |buffer_size| bytes from |handle|'s process at |address| into
// |buffer| using |fn|. Returns true on success.
static bool ReadMemory(ReadMemoryFn fn,
HANDLE handle,
RemotePointer address,
void* buffer,
RemotePointer buffer_size) {
NTSTATUS status = fn(handle, address, buffer, buffer_size, nullptr);
if (NT_SUCCESS(status))
return true;
LOG(ERROR) << "Failed to read process memory with status " << std::hex
<< status << ".";
return false;
}
};
// static
constexpr char Wow64Traits::kQueryProcessInformationFunctionName[] =
"NtWow64QueryInformationProcess64";
#endif
// Traits for a 32-bit process running on 32-bit Windows, or a 64-bit process
// running on 64-bit Windows.
struct NormalTraits {
// The name of the ntdll function to query process information.
static const char kQueryProcessInformationFunctionName[];
// The type of a pointer to the read process memory function.
using ReadMemoryFn = decltype(&::ReadProcessMemory);
// An unsigned integer type matching the size of a pointer in the remote
// process.
using RemotePointer = uintptr_t;
// Returns the function to read memory from a remote process.
static ReadMemoryFn GetReadMemoryFn() { return &::ReadProcessMemory; }
// Reads |buffer_size| bytes from |handle|'s process at |address| into
// |buffer| using |fn|. Returns true on success.
static bool ReadMemory(ReadMemoryFn fn,
HANDLE handle,
RemotePointer address,
void* buffer,
RemotePointer buffer_size) {
BOOL result = fn(handle, reinterpret_cast<const void*>(address), buffer,
buffer_size, nullptr);
if (result)
return true;
PLOG(ERROR) << "Failed to read process memory";
return false;
}
};
// static
constexpr char NormalTraits::kQueryProcessInformationFunctionName[] =
"NtQueryInformationProcess";
template <class Traits>
Inspector<Traits>::Inspector() = default;
template <class Traits>
DWORD Inspector<Traits>::GetParentPid() const {
return process_basic_information_.inherited_from_unique_process_id();
}
template <class Traits>
const std::wstring& Inspector<Traits>::command_line() const {
return command_line_;
}
template <class Traits>
bool Inspector<Traits>::Inspect(const base::Process& process) {
auto query_information_process_fn =
reinterpret_cast<decltype(&::NtQueryInformationProcess)>(
::GetProcAddress(::GetModuleHandle(L"ntdll.dll"),
Traits::kQueryProcessInformationFunctionName));
typename Traits::ReadMemoryFn read_memory_fn = Traits::GetReadMemoryFn();
if (!query_information_process_fn)
return false;
ULONG in_len = sizeof(process_basic_information_);
ULONG out_len = 0;
NTSTATUS status = query_information_process_fn(
process.Handle(), ProcessBasicInformation, &process_basic_information_,
in_len, &out_len);
if (NT_ERROR(status) || out_len != in_len)
return false;
if (!Traits::ReadMemory(read_memory_fn, process.Handle(),
process_basic_information_.peb_base_address(), &peb_,
sizeof(peb_))) {
return false;
}
if (!Traits::ReadMemory(read_memory_fn, process.Handle(),
peb_.ProcessParameters, &process_parameters_,
sizeof(process_parameters_))) {
return false;
}
if (process_parameters_.CommandLine.Length) {
command_line_.resize(process_parameters_.CommandLine.Length /
sizeof(wchar_t));
if (!Traits::ReadMemory(read_memory_fn, process.Handle(),
process_parameters_.CommandLine.Buffer,
&command_line_[0],
process_parameters_.CommandLine.Length)) {
command_line_.clear();
return false;
}
}
return true;
}
} // namespace
// static
std::unique_ptr<ProcessInspector> ProcessInspector::Create(
const base::Process& process) {
std::unique_ptr<ProcessInspector> inspector;
#if !defined(_WIN64)
using base::win::OSInfo;
if (OSInfo::GetInstance()->IsWowX86OnAMD64())
inspector = std::make_unique<Inspector<Wow64Traits>>();
#endif
if (!inspector)
inspector = std::make_unique<Inspector<NormalTraits>>();
if (!inspector->Inspect(process))
inspector.reset();
return inspector;
}
|