1 /*****************************************************************
2  *               nsProcess NSIS plugin v1.5                      *
3  *                                                               *
4  * 2006 Shengalts Aleksander aka Instructor (Shengalts@mail.ru)  *
5  *                                                               *
6  * Source function FIND_PROC_BY_NAME based                       *
7  *   upon the Ravi Kochhar (kochhar@physiology.wisc.edu) code    *
8  * Thanks iceman_k (FindProcDLL plugin) and                      *
9  *   DITMan (KillProcDLL plugin) for point me up                 *
10  *****************************************************************/
11 
12 
13 #define WIN32_LEAN_AND_MEAN
14 #include <windows.h>
15 #include <Tlhelp32.h>
16 //#include "ConvFunc.h"
17 #include "pluginapi.h"
18 
19 /* Defines */
20 #define NSIS_MAX_STRLEN 1024
21 
22 #define SystemProcessInformation     5
23 #define STATUS_SUCCESS               0x00000000L
24 #define STATUS_INFO_LENGTH_MISMATCH  0xC0000004L
25 
26 typedef struct _SYSTEM_THREAD_INFO {
27   FILETIME ftCreationTime;
28   DWORD dwUnknown1;
29   DWORD dwStartAddress;
30   DWORD dwOwningPID;
31   DWORD dwThreadID;
32   DWORD dwCurrentPriority;
33   DWORD dwBasePriority;
34   DWORD dwContextSwitches;
35   DWORD dwThreadState;
36   DWORD dwUnknown2;
37   DWORD dwUnknown3;
38   DWORD dwUnknown4;
39   DWORD dwUnknown5;
40   DWORD dwUnknown6;
41   DWORD dwUnknown7;
42 } SYSTEM_THREAD_INFO;
43 
44 typedef struct _SYSTEM_PROCESS_INFO {
45   DWORD dwOffset;
46   DWORD dwThreadCount;
47   DWORD dwUnkown1[6];
48   FILETIME ftCreationTime;
49   DWORD dwUnkown2;
50   DWORD dwUnkown3;
51   DWORD dwUnkown4;
52   DWORD dwUnkown5;
53   DWORD dwUnkown6;
54   WCHAR *pszProcessName;
55   DWORD dwBasePriority;
56   DWORD dwProcessID;
57   DWORD dwParentProcessID;
58   DWORD dwHandleCount;
59   DWORD dwUnkown7;
60   DWORD dwUnkown8;
61   DWORD dwVirtualBytesPeak;
62   DWORD dwVirtualBytes;
63   DWORD dwPageFaults;
64   DWORD dwWorkingSetPeak;
65   DWORD dwWorkingSet;
66   DWORD dwUnkown9;
67   DWORD dwPagedPool;
68   DWORD dwUnkown10;
69   DWORD dwNonPagedPool;
70   DWORD dwPageFileBytesPeak;
71   DWORD dwPageFileBytes;
72   DWORD dwPrivateBytes;
73   DWORD dwUnkown11;
74   DWORD dwUnkown12;
75   DWORD dwUnkown13;
76   DWORD dwUnkown14;
77   SYSTEM_THREAD_INFO ati[ANYSIZE_ARRAY];
78 } SYSTEM_PROCESS_INFO;
79 
80 
81 /* Include conversion functions */
82 //#define xatoi
83 //#define xitoa
84 //#include "ConvFunc.h"
85 
86 /* Global variables */
87 TCHAR szBuf[NSIS_MAX_STRLEN];
88 
89 /* Funtions prototypes and macros */
90 int FIND_PROC_BY_NAME(TCHAR *szProcessName, BOOL bTerminate, BOOL bClose);
91 
92 /* NSIS functions code */
_FindProcess(HWND hwndParent,int string_size,TCHAR * variables,stack_t ** stacktop,extra_parameters * extra)93 void __declspec(dllexport) _FindProcess(HWND hwndParent, int string_size,
94                                       TCHAR *variables, stack_t **stacktop, extra_parameters *extra)
95 {
96   EXDLL_INIT();
97   {
98     int nError;
99 
100     popstringn(szBuf, NSIS_MAX_STRLEN);
101     nError=FIND_PROC_BY_NAME(szBuf, FALSE, FALSE);
102     pushint(nError);
103   }
104 }
105 
_KillProcess(HWND hwndParent,int string_size,TCHAR * variables,stack_t ** stacktop,extra_parameters * extra)106 void __declspec(dllexport) _KillProcess(HWND hwndParent, int string_size,
107                                       TCHAR *variables, stack_t **stacktop, extra_parameters *extra)
108 {
109   EXDLL_INIT();
110   {
111     int nError=0;
112 
113     popstringn(szBuf, NSIS_MAX_STRLEN);
114     nError=FIND_PROC_BY_NAME(szBuf, TRUE, FALSE);
115     pushint(nError);
116   }
117 }
118 
_CloseProcess(HWND hwndParent,int string_size,TCHAR * variables,stack_t ** stacktop,extra_parameters * extra)119 void __declspec(dllexport) _CloseProcess(HWND hwndParent, int string_size,
120                                       TCHAR *variables, stack_t **stacktop, extra_parameters *extra)
121 {
122   EXDLL_INIT();
123   {
124     int nError=0;
125 
126     popstringn(szBuf, NSIS_MAX_STRLEN);
127     nError=FIND_PROC_BY_NAME(szBuf, TRUE, TRUE);
128     pushint(nError);
129   }
130 }
131 
_Unload(HWND hwndParent,int string_size,TCHAR * variables,stack_t ** stacktop,extra_parameters * extra)132 void __declspec(dllexport) _Unload(HWND hwndParent, int string_size,
133                                       TCHAR *variables, stack_t **stacktop, extra_parameters *extra)
134 {
135 }
136 
DllMain(HANDLE hInst,ULONG ul_reason_for_call,LPVOID lpReserved)137 BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
138 {
139   return TRUE;
140 }
141 
EnumWindowsProc(HWND hwnd,LPARAM lParam)142 BOOL CALLBACK EnumWindowsProc(          HWND hwnd,
143     LPARAM lParam
144 )
145 {
146 	HANDLE *data = lParam;
147 	DWORD pid;
148 	GetWindowThreadProcessId(hwnd, &pid);
149 	if (pid == data[0])
150 	{
151 		PostMessage(data[1], WM_CLOSE, 0, 0);
152 		data[1] = hwnd;
153 	}
154 	return TRUE;
155 }
156 
NiceTerminate(DWORD id,BOOL bClose,BOOL * bSuccess,BOOL * bFailed)157 void NiceTerminate(DWORD id, BOOL bClose, BOOL *bSuccess, BOOL *bFailed)
158 {
159   HANDLE hProc;
160   HANDLE data[2];
161   DWORD ec;
162   BOOL bDone = FALSE;
163   if (hProc=OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, id))
164   {
165 	data[0] = id;
166 	data[1] = NULL;
167 
168 	if (bClose)
169 		EnumWindows(EnumWindowsProc, data);
170 	if (data[1] != NULL)
171 	{
172 	  if (GetExitCodeProcess(hProc,&ec) && ec == STILL_ACTIVE)
173 		if (WaitForSingleObject(hProc, 3000) == WAIT_OBJECT_0)
174 		{
175 		  *bSuccess = bDone = TRUE;
176 		}
177 		else;
178 	  else
179 	  {
180 		  *bSuccess = bDone = TRUE;
181 	  }
182 	}
183 	if (!bDone)
184 	{
185             // Open for termination
186               if (TerminateProcess(hProc, 0))
187                 *bSuccess=TRUE;
188               else
189                 *bFailed=TRUE;
190 	}
191     CloseHandle(hProc);
192   }
193 }
194 
FIND_PROC_BY_NAME(TCHAR * szProcessName,BOOL bTerminate,BOOL bClose)195 int FIND_PROC_BY_NAME(TCHAR *szProcessName, BOOL bTerminate, BOOL bClose)
196 // Find the process "szProcessName" if it is currently running.
197 // This works for Win95/98/ME and also WinNT/2000/XP.
198 // The process name is case-insensitive, i.e. "notepad.exe" and "NOTEPAD.EXE"
199 // will both work. If bTerminate is TRUE, then process will be terminated.
200 //
201 // Return codes are as follows:
202 //   0   = Success
203 //   601 = No permission to terminate process
204 //   602 = Not all processes terminated successfully
205 //   603 = Process was not currently running
206 //   604 = Unable to identify system type
207 //   605 = Unsupported OS
208 //   606 = Unable to load NTDLL.DLL
209 //   607 = Unable to get procedure address from NTDLL.DLL
210 //   608 = NtQuerySystemInformation failed
211 //   609 = Unable to load KERNEL32.DLL
212 //   610 = Unable to get procedure address from KERNEL32.DLL
213 //   611 = CreateToolhelp32Snapshot failed
214 //
215 // Change history:
216 //   created  06/23/2000  - Ravi Kochhar (kochhar@physiology.wisc.edu)
217 //                            http://www.neurophys.wisc.edu/ravi/software/
218 //   modified 03/08/2002  - Ravi Kochhar (kochhar@physiology.wisc.edu)
219 //                          - Borland-C compatible if BORLANDC is defined as
220 //                            suggested by Bob Christensen
221 //   modified 03/10/2002  - Ravi Kochhar (kochhar@physiology.wisc.edu)
222 //                          - Removed memory leaks as suggested by
223 //                            Jonathan Richard-Brochu (handles to Proc and Snapshot
224 //                            were not getting closed properly in some cases)
225 //   modified 14/11/2005  - Shengalts Aleksander aka Instructor (Shengalts@mail.ru):
226 //                          - Combine functions FIND_PROC_BY_NAME and KILL_PROC_BY_NAME
227 //                          - Code has been optimized
228 //                          - Now kill all processes with specified name (not only one)
229 //                          - Cosmetic improvements
230 //                          - Removed error 632 (Invalid process name)
231 //                          - Changed error 602 (Unable to terminate process for some other reason)
232 //                          - BORLANDC define not needed
233 //   modified 04/01/2006  - Shengalts Aleksander aka Instructor (Shengalts@mail.ru):
234 //                          - Removed CRT dependency
235 //   modified 21/04/2006  - Shengalts Aleksander aka Instructor (Shengalts@mail.ru):
236 //                          - Removed memory leak as suggested by {_trueparuex^}
237 //                            (handle to hSnapShot was not getting closed properly in some cases)
238 //   modified 21/04/2006  - Shengalts Aleksander aka Instructor (Shengalts@mail.ru):
239 //                          - Removed memory leak as suggested by {_trueparuex^}
240 //                            (handle to hSnapShot was not getting closed properly in some cases)
241 //   modified 19/07/2006  - Shengalts Aleksander aka Instructor (Shengalts@mail.ru):
242 //                          - Code for WinNT/2000/XP has been rewritten
243 //                          - Changed error codes
244 //   modified 31/08/2006  - Shengalts Aleksander aka Instructor (Shengalts@mail.ru):
245 //                          - Removed memory leak as suggested by Daniel Vanesse
246 {
247   TCHAR szName[MAX_PATH];
248   OSVERSIONINFO osvi;
249   HMODULE hLib;
250   HANDLE hProc;
251   ULONG uError;
252   BOOL bFound=FALSE;
253   BOOL bSuccess=FALSE;
254   BOOL bFailed=FALSE;
255 
256   // First check what version of Windows we're in
257   osvi.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
258   if (!GetVersionEx(&osvi)) return 604;
259 
260   if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT &&
261       osvi.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
262     return 605;
263 
264   if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
265   {
266     // WinNT/2000/XP
267 
268     SYSTEM_PROCESS_INFO *spi;
269     SYSTEM_PROCESS_INFO *spiCount;
270     DWORD dwSize=0x4000;
271     DWORD dwData;
272     ULONG (WINAPI *NtQuerySystemInformationPtr)(ULONG, PVOID, LONG, PULONG);
273 
274     if (hLib=LoadLibraryW(L"NTDLL.DLL"))
275     {
276       NtQuerySystemInformationPtr=(ULONG(WINAPI *)(ULONG, PVOID, LONG, PULONG))GetProcAddress(hLib, "NtQuerySystemInformation");
277 
278       if (NtQuerySystemInformationPtr)
279       {
280         while (1)
281         {
282           if (spi=LocalAlloc(LMEM_FIXED, dwSize))
283           {
284             uError=(*NtQuerySystemInformationPtr)(SystemProcessInformation, spi, dwSize, &dwData);
285 
286             if (uError == STATUS_SUCCESS) break;
287 
288             LocalFree(spi);
289 
290             if (uError != STATUS_INFO_LENGTH_MISMATCH)
291             {
292               uError=608;
293               break;
294             }
295           }
296           else
297           {
298             uError=608;
299             break;
300           }
301           dwSize*=2;
302         }
303       }
304       else uError=607;
305 
306       FreeLibrary(hLib);
307     }
308     else uError=606;
309 
310     if (uError != STATUS_SUCCESS) return uError;
311 
312     spiCount=spi;
313 
314     while (1)
315     {
316       if (spiCount->pszProcessName)
317       {
318 
319 #ifdef UNICODE
320 	    lstrcpyn(szName, spiCount->pszProcessName, MAX_PATH);
321 #else
322 	    WideCharToMultiByte(CP_ACP, 0, spiCount->pszProcessName, -1, szName, MAX_PATH, NULL, NULL);
323 #endif
324 
325         if (!lstrcmpi(szName, szProcessName))
326         {
327           // Process found
328           bFound=TRUE;
329 
330           if (bTerminate == TRUE)
331           {
332 			  NiceTerminate(spiCount->dwProcessID, bClose, &bSuccess, &bFailed);
333           }
334           else break;
335         }
336       }
337       if (spiCount->dwOffset == 0) break;
338       spiCount=(SYSTEM_PROCESS_INFO *)((char *)spiCount + spiCount->dwOffset);
339     }
340     LocalFree(spi);
341   }
342   else
343   {
344     // Win95/98/ME
345 
346     PROCESSENTRY32 pe;
347     char *pName;
348     HANDLE hSnapShot;
349     BOOL bResult;
350     HANDLE (WINAPI *CreateToolhelp32SnapshotPtr)(DWORD, DWORD);
351     BOOL (WINAPI *Process32FirstPtr)(HANDLE, LPPROCESSENTRY32);
352     BOOL (WINAPI *Process32NextPtr)(HANDLE, LPPROCESSENTRY32);
353 
354     if (hLib=LoadLibraryA("KERNEL32.DLL"))
355     {
356       CreateToolhelp32SnapshotPtr=(HANDLE(WINAPI *)(DWORD, DWORD)) GetProcAddress(hLib, "CreateToolhelp32Snapshot");
357       Process32FirstPtr=(BOOL(WINAPI *)(HANDLE, LPPROCESSENTRY32)) GetProcAddress(hLib, "Process32First");
358       Process32NextPtr=(BOOL(WINAPI *)(HANDLE, LPPROCESSENTRY32)) GetProcAddress(hLib, "Process32Next");
359 
360       if (CreateToolhelp32SnapshotPtr && Process32NextPtr && Process32FirstPtr)
361       {
362         // Get a handle to a Toolhelp snapshot of all the systems processes.
363         if ((hSnapShot=(*CreateToolhelp32SnapshotPtr)(TH32CS_SNAPPROCESS, 0)) != INVALID_HANDLE_VALUE)
364         {
365           // Get the first process' information.
366           pe.dwSize=sizeof(PROCESSENTRY32);
367           bResult=(*Process32FirstPtr)(hSnapShot, &pe);
368 
369           // While there are processes, keep looping and checking.
370           while (bResult)
371           {
372             //Get file name
373             for (pName=pe.szExeFile + lstrlen(pe.szExeFile) - 1; *pName != '\\' && *pName != '\0'; --pName);
374 
375 			++pName;
376 
377 #ifdef UNICODE
378 			MultiByteToWideChar(CP_ACP, 0, pName, lstrlenA(pName)+1, szName, MAX_PATH);
379 #else
380 			lstrcpyn(szName, pName, MAX_PATH);
381 #endif
382 
383             if (!lstrcmpi(szName, szProcessName))
384             {
385               // Process found
386               bFound=TRUE;
387 
388               if (bTerminate == TRUE)
389               {
390                 // Open for termination
391 				  NiceTerminate(pe.th32ProcessID, bClose, &bSuccess, &bFailed);
392               }
393               else break;
394             }
395             //Keep looking
396             bResult=(*Process32NextPtr)(hSnapShot, &pe);
397           }
398           CloseHandle(hSnapShot);
399         }
400         else uError=611;
401       }
402       else uError=610;
403 
404       FreeLibrary(hLib);
405     }
406     else uError=609;
407   }
408 
409   if (bFound == FALSE) return 603;
410   if (bTerminate == TRUE)
411   {
412     if (bSuccess == FALSE) return 601;
413     if (bFailed == TRUE) return 602;
414   }
415   return 0;
416 }
417