1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sal.hxx"
26
27 #include <tchar.h>
28
29 #ifdef _MSC_VER
30 #pragma warning(push,1) // disable warnings within system headers
31 #endif
32 #define WIN32_LEAN_AND_MEAN
33 #include <windows.h>
34 #include <tlhelp32.h>
35 #include <psapi.h>
36 #ifdef _MSC_VER
37 #pragma warning(pop)
38 #endif
39
40 #include <signal.h>
41 #include <stdarg.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44
45 #ifndef SIGNULL
46 #define SIGNULL 0
47 #endif
48
49 #ifndef SIGKILL
50 #define SIGKILL 9
51 #endif
52
53 #include <signal.h>
54
55 #define MAX_MODULES 1024
56
57 /////////////////////////////////////////////////////////////////////////////
58 // Determines if a returned handle value is valid
59 /////////////////////////////////////////////////////////////////////////////
60
IsValidHandle(HANDLE handle)61 static inline bool IsValidHandle( HANDLE handle )
62 {
63 return INVALID_HANDLE_VALUE != handle && NULL != handle;
64 }
65
66
67 #define elementsof( a ) (sizeof(a) / sizeof( (a)[0] ))
68
69 /////////////////////////////////////////////////////////////////////////////
70 // Retrieves function adress in another process
71 /////////////////////////////////////////////////////////////////////////////
72
73 #if 1
74 #define GetProcAddressEx( hProcess, hModule, lpProcName ) GetProcAddress( hModule, lpProcName )
75 #else
GetProcAddressEx(HANDLE hProcess,HMODULE hModule,LPCSTR lpProcName)76 FARPROC WINAPI GetProcAddressEx( HANDLE hProcess, HMODULE hModule, LPCSTR lpProcName )
77 {
78 FARPROC lpfnProcAddress = GetProcAddress( hModule, lpProcName );
79
80 if ( lpfnProcAddress )
81 {
82 DWORD dwProcessId = GetProcessId( hProcess );
83
84 if ( GetCurrentProcessId() != dwProcessId )
85 {
86 FARPROC lpfnRemoteProcAddress = NULL;
87 TCHAR szBaseName[MAX_PATH];
88
89 if ( GetModuleBaseName( GetCurrentProcess(), hModule, szBaseName, elementsof(szBaseName) ) )
90 {
91 HMODULE ahModules[MAX_MODULES];
92 DWORD cbNeeded = 0;
93
94 if ( EnumProcessModules( hProcess, ahModules, sizeof(ahModules), &cbNeeded ) )
95 {
96 ULONG nModules = cbNeeded / sizeof(ahModules[0]);
97
98 for ( ULONG n = 0; n < nModules; n++ )
99 {
100 TCHAR szRemoteBaseName[MAX_PATH];
101
102 if ( GetModuleBaseName(
103 hProcess, ahModules[n], szRemoteBaseName, elementsof(szRemoteBaseName) ) &&
104 0 == lstrcmpi( szRemoteBaseName, szBaseName )
105 )
106 {
107 lpfnRemoteProcAddress = lpfnProcAddress;
108
109 if ( ahModules[n] != hModule )
110 *(LPBYTE*)&lpfnRemoteProcAddress += (LPBYTE)ahModules[n] - (LPBYTE)hModule;
111 break;
112 }
113 }
114 }
115 }
116
117 lpfnProcAddress = lpfnRemoteProcAddress;
118 }
119 }
120
121 return lpfnProcAddress;
122 }
123 #endif
124
125 /////////////////////////////////////////////////////////////////////////////
126 // Raises a signal in an other process
127 /////////////////////////////////////////////////////////////////////////////
128
SignalToExceptionCode(int signal)129 static DWORD SignalToExceptionCode( int signal )
130 {
131 switch ( signal )
132 {
133 case SIGSEGV:
134 return EXCEPTION_ACCESS_VIOLATION;
135 case SIGFPE:
136 return EXCEPTION_FLT_INVALID_OPERATION;
137 case SIGILL:
138 return EXCEPTION_ILLEGAL_INSTRUCTION;
139 case SIGINT:
140 return CONTROL_C_EXIT;
141 case SIGBREAK:
142 return CONTROL_C_EXIT;
143 default:
144 return 0;
145 }
146 }
147
RaiseSignalEx(HANDLE hProcess,int sig)148 static BOOL RaiseSignalEx( HANDLE hProcess, int sig )
149 {
150 DWORD dwProcessId = GetProcessId( hProcess );
151
152 HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
153 HANDLE hThread = 0;
154 BOOL fSuccess = FALSE;
155
156 if ( IsValidHandle(hSnapshot) )
157 {
158 THREADENTRY32 te;
159
160 te.dwSize = sizeof(te);
161 fSuccess = Thread32First( hSnapshot, &te );
162 while ( fSuccess )
163 {
164 if ( te.th32OwnerProcessID == dwProcessId )
165 {
166 hThread = OpenThread(
167 THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION |
168 THREAD_GET_CONTEXT | THREAD_SET_CONTEXT,
169 FALSE, te.th32ThreadID );
170 if ( IsValidHandle(hThread) )
171 break;
172 }
173
174 fSuccess = Thread32Next( hSnapshot, &te );
175 }
176
177 CloseHandle( hSnapshot );
178 }
179
180 if ( fSuccess )
181 {
182 CONTEXT aContext;
183
184 if ( SuspendThread( hThread ) != (DWORD)-1 )
185 {
186 ZeroMemory( &aContext, sizeof(aContext) );
187 aContext.ContextFlags = CONTEXT_FULL;
188
189 fSuccess = GetThreadContext( hThread, &aContext );
190
191 if ( fSuccess )
192 {
193 if ( sig )
194 {
195 DWORD dwStackBuffer[] =
196 {
197 aContext.Eip,
198 SignalToExceptionCode( sig ),
199 EXCEPTION_NONCONTINUABLE,
200 0,
201 0
202 };
203
204 aContext.Esp -= sizeof(dwStackBuffer);
205 WriteProcessMemory( hProcess, (LPVOID)aContext.Esp, dwStackBuffer, sizeof(dwStackBuffer), NULL );
206 aContext.Eip = (DWORD)GetProcAddressEx( hProcess, GetModuleHandleA("KERNEL32"), "RaiseException" );
207 }
208 else
209 {
210 aContext.Ecx = aContext.Eax = aContext.Ebx = aContext.Edx = aContext.Esi = aContext.Edi = 0;
211 }
212
213 fSuccess = SetThreadContext( hThread, &aContext );
214 }
215
216 fSuccess = ResumeThread( hThread ) && fSuccess;
217
218 DWORD dwLastError = GetLastError();
219 CloseHandle( hThread );
220 SetLastError( dwLastError );
221
222 return fSuccess;
223 }
224 }
225
226 return FALSE;
227 }
228 /////////////////////////////////////////////////////////////////////////////
229 // Command line parameter parsing
230 /////////////////////////////////////////////////////////////////////////////
231
ParseCommandArgs(LPDWORD lpProcesses,LPDWORD lpdwNumProcesses,int * pSig)232 static void ParseCommandArgs( LPDWORD lpProcesses, LPDWORD lpdwNumProcesses, int *pSig )
233 {
234 typedef struct _SignalEntry
235 {
236 LPCTSTR lpSignalName;
237 int iSignalValue;
238 } SignalEntry;
239
240 #define SIG_ENTRY( signal ) { TEXT(#signal), SIG##signal }
241
242 static SignalEntry SupportedSignals[] =
243 {
244 SIG_ENTRY( NULL ),
245 SIG_ENTRY( SEGV ),
246 SIG_ENTRY( ILL ),
247 SIG_ENTRY( FPE ),
248 SIG_ENTRY( INT ),
249 SIG_ENTRY( BREAK ),
250 SIG_ENTRY( TERM ),
251 SIG_ENTRY( ABRT ),
252 SIG_ENTRY( KILL )
253 };
254
255 const int NumSupportedSignals = elementsof(SupportedSignals);
256
257 DWORD dwMaxProcesses = *lpdwNumProcesses;
258 int argc = __argc;
259 TCHAR **argv = __targv;
260
261 *lpdwNumProcesses = 0;
262
263 for ( int argn = 1; argn < argc; argn++ )
264 {
265 if ( 0 == lstrcmpi( argv[argn], TEXT("-l") ) ||
266 0 == lstrcmpi( argv[argn], TEXT("/l") ) )
267
268 {
269 for ( int n = 0; n < NumSupportedSignals; n++ )
270 {
271 _tprintf( _T("%s "), SupportedSignals[n].lpSignalName );
272 }
273 _tprintf( _T("\n") );
274 ExitProcess( 0 );
275 }
276 else if ( 0 == lstrcmpi( argv[argn], TEXT("-?") ) ||
277 0 == lstrcmpi( argv[argn], TEXT("/?") ) ||
278 0 == lstrcmpi( argv[argn], TEXT("-h") ) ||
279 0 == lstrcmpi( argv[argn], TEXT("/h") ) ||
280 0 == lstrcmpi( argv[argn], TEXT("--help") ) )
281 {
282 _tprintf(
283 _T("Terminates a process by sending a signal.\n\n")
284 _T("Usage: kill [ -l ] [ -signal ] pid ...\n\n")
285 _T("-l Lists supported signals\n")
286 _T("-signal Sends the specified signal to the given processes.\n")
287 _T(" signal can be a numeric value specifying the signal number\n")
288 _T(" or a string listed by the -l parameter. If no signal is\n")
289 _T(" given SIGTERM (-TERM) is used.\n")
290 _T("pid Process id(s) or executables names(s) of processes to \n")
291 _T(" signal or terminate.\n\n")
292 );
293 ExitProcess( 0 );
294 }
295 else if ( argv[argn] && ( *argv[argn] == '-' || *argv[argn] == '/' ) )
296 {
297 LPCTSTR argsig = CharNext( argv[argn] );
298
299 int n;
300 for ( n = 0; n < NumSupportedSignals; n++ )
301 {
302 _TCHAR *endptr = NULL;
303
304 if ( 0 == lstrcmpi( SupportedSignals[n].lpSignalName, argsig ) ||
305 _tcstoul( argsig, &endptr, 0 ) == static_cast< unsigned >(SupportedSignals[n].iSignalValue) && (!endptr || !*endptr) )
306 {
307 *pSig = SupportedSignals[n].iSignalValue;
308 break;
309 }
310 }
311
312 if ( n >= NumSupportedSignals )
313 {
314 _ftprintf( stderr,
315 _T("kill: Illegal argument %s\n")
316 _T("Type 'kill --help' to show allowed syntax.\n")
317 _T("Type 'kill -l' to show supported signals.\n"),
318 argv[argn] );
319 ExitProcess( 0 );
320 }
321 }
322 else
323 {
324 unsigned long value = 0;
325 _TCHAR *endptr = NULL;
326
327 value = _tcstoul( argv[argn], &endptr, 0 );
328
329 if ( !endptr || !*endptr )
330 {
331 if ( *lpdwNumProcesses < dwMaxProcesses )
332 {
333 *(lpProcesses++) = value;
334 (*lpdwNumProcesses)++;
335 }
336 }
337 else
338 {
339 HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
340
341 if ( IsValidHandle( hSnapshot ) )
342 {
343 PROCESSENTRY32 pe;
344
345 pe.dwSize = sizeof(pe);
346 BOOL fSuccess = Process32First( hSnapshot, &pe );
347
348 while ( fSuccess )
349 {
350 if ( 0 == lstrcmpi( argv[argn], pe.szExeFile ) )
351 {
352 if ( *lpdwNumProcesses < dwMaxProcesses )
353 {
354 *(lpProcesses++) = pe.th32ProcessID;
355 (*lpdwNumProcesses)++;
356 }
357 }
358 fSuccess = Process32Next( hSnapshot, &pe );
359 }
360
361 CloseHandle( hSnapshot );
362 }
363 }
364 }
365 }
366
367 if ( !*lpdwNumProcesses )
368 {
369 _ftprintf( stderr,
370 _T("kill: No process specified.\n")
371 _T("Use kill --help to show allowed syntax.\n")
372 );
373 ExitProcess( 0 );
374 }
375
376 }
377
OutputSystemMessage(DWORD dwErrorCode)378 void OutputSystemMessage( DWORD dwErrorCode )
379 {
380 LPVOID lpMsgBuf;
381 FormatMessageA(
382 FORMAT_MESSAGE_ALLOCATE_BUFFER |
383 FORMAT_MESSAGE_FROM_SYSTEM |
384 FORMAT_MESSAGE_IGNORE_INSERTS,
385 NULL,
386 dwErrorCode,
387 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
388 (LPSTR)&lpMsgBuf,
389 0,
390 NULL
391 );
392
393 printf( (LPSTR)lpMsgBuf );
394 LocalFree( lpMsgBuf );
395 }
396
_tmain()397 int _tmain()
398 {
399 DWORD dwProcessIds[1024];
400 DWORD nProcesses = elementsof(dwProcessIds);
401 int sig = SIGTERM;
402
403
404 ParseCommandArgs( dwProcessIds, &nProcesses, &sig );
405
406 for ( ULONG n = 0; n < nProcesses; n++ )
407 {
408 HANDLE hProcess;
409
410 _tprintf( _T("Sending signal to process id %d..."), dwProcessIds[n] );
411 hProcess = OpenProcess( PROCESS_TERMINATE | PROCESS_CREATE_THREAD | SYNCHRONIZE |
412 PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
413 FALSE, dwProcessIds[n] );
414
415 if ( IsValidHandle( hProcess ) )
416 {
417 if ( SIGKILL == sig )
418 TerminateProcess( hProcess, 255 );
419 else
420 {
421 if ( RaiseSignalEx( hProcess, sig ) )
422 _tprintf( _T("OK\n") );
423 else
424 {
425 OutputSystemMessage( GetLastError() );
426 }
427 }
428
429 CloseHandle( hProcess );
430 }
431 else
432 {
433 OutputSystemMessage( GetLastError() );
434 }
435 }
436
437 return 0;
438 }
439
440