1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/test/test_process_killer_win.h"
12 #include "base/logging.h"
13 #include "base/process/kill.h"
14 #include "base/process/process_iterator.h"
15 #include "base/strings/string_util.h"
16 #include "base/win/scoped_handle.h"
21 NtQueryInformationProcess(
22 IN HANDLE ProcessHandle,
23 IN PROCESSINFOCLASS ProcessInformationClass,
24 OUT PVOID ProcessInformation,
25 IN ULONG ProcessInformationLength,
26 OUT PULONG ReturnLength OPTIONAL
29 // Get the function pointer to NtQueryInformationProcess in NTDLL.DLL
30 static bool GetQIP(NtQueryInformationProcess** qip_func_ptr) {
31 static NtQueryInformationProcess* qip_func =
32 reinterpret_cast<NtQueryInformationProcess*>(
33 GetProcAddress(GetModuleHandle(L"ntdll.dll"),
34 "NtQueryInformationProcess"));
35 DCHECK(qip_func) << "Could not get pointer to NtQueryInformationProcess.";
36 *qip_func_ptr = qip_func;
37 return qip_func != NULL;
40 // Get the command line of a process
41 bool GetCommandLineForProcess(uint32 process_id, string16* cmd_line) {
42 DCHECK(process_id != 0);
46 base::win::ScopedHandle process_handle(::OpenProcess(
47 PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
50 if (!process_handle) {
51 DLOG(ERROR) << "Failed to open process " << process_id << ", last error = "
55 // Obtain Process Environment Block
56 NtQueryInformationProcess* qip_func = NULL;
61 // Read the address of the process params from the peb.
62 DWORD process_params_address = 0;
64 PROCESS_BASIC_INFORMATION info = { 0 };
65 // NtQueryInformationProcess returns an NTSTATUS for whom negative values
66 // are negative. Just check for that instead of pulling in DDK macros.
67 if ((qip_func(process_handle.Get(),
68 ProcessBasicInformation,
72 DLOG(ERROR) << "Failed to invoke NtQueryProcessInformation, last error = "
75 BYTE* peb = reinterpret_cast<BYTE*>(info.PebBaseAddress);
77 // The process command line parameters are (or were once) located at
78 // the base address of the PEB + 0x10 for 32 bit processes. 64 bit
79 // processes have a different PEB struct as per
80 // http://msdn.microsoft.com/en-us/library/aa813706(VS.85).aspx.
81 // TODO(robertshield): See about doing something about this.
82 SIZE_T bytes_read = 0;
83 if (!::ReadProcessMemory(process_handle.Get(),
85 &process_params_address,
86 sizeof(process_params_address),
88 DLOG(ERROR) << "Failed to read process params address, last error = "
94 // Copy all the process parameters into a buffer.
97 if (process_params_address) {
99 RTL_USER_PROCESS_PARAMETERS params = { 0 };
100 if (!::ReadProcessMemory(process_handle.Get(),
101 reinterpret_cast<void*>(process_params_address),
105 DLOG(ERROR) << "Failed to read RTL_USER_PROCESS_PARAMETERS, "
106 << "last error = " << GetLastError();
108 // Read the command line parameter
109 const int max_cmd_line_len = std::min(
110 static_cast<int>(params.CommandLine.MaximumLength),
112 buffer.resize(max_cmd_line_len + 1);
113 if (!::ReadProcessMemory(process_handle.Get(),
114 params.CommandLine.Buffer,
118 DLOG(ERROR) << "Failed to copy process command line, "
119 << "last error = " << GetLastError();
130 // Used to filter processes by process ID.
131 class ArgumentFilter : public base::ProcessFilter {
133 explicit ArgumentFilter(const string16& argument)
134 : argument_to_find_(argument) {}
136 // Returns true to indicate set-inclusion and false otherwise. This method
137 // should not have side-effects and should be idempotent.
138 virtual bool Includes(const base::ProcessEntry& entry) const {
140 string16 command_line;
141 if (GetCommandLineForProcess(entry.pid(), &command_line)) {
142 string16::const_iterator it =
143 std::search(command_line.begin(),
145 argument_to_find_.begin(),
146 argument_to_find_.end(),
147 base::CaseInsensitiveCompareASCII<wchar_t>());
148 found = (it != command_line.end());
154 string16 argument_to_find_;
161 bool KillAllNamedProcessesWithArgument(const string16& process_name,
162 const string16& argument) {
163 ArgumentFilter argument_filter(argument);
164 return base::KillProcesses(process_name, 0, &argument_filter);