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 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 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 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 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 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 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 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