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
, base::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.
96 base::string16 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 base::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 base::string16 command_line
;
141 if (GetCommandLineForProcess(entry
.pid(), &command_line
)) {
142 base::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 base::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
);