]> sourceware.org Git - newlib-cygwin.git/blob - winsup/utils/bloda.cc
* Makefile.in (cygcheck.exe): Add bloda.o as prerequisite, adjusting
[newlib-cygwin.git] / winsup / utils / bloda.cc
1 /* bloda.cc
2
3 Copyright 2007 Red Hat, Inc.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #define cygwin_internal cygwin_internal_dontuse
12 #include <stdio.h>
13 #include <assert.h>
14 #include <windows.h>
15 #include <ntdef.h>
16 #include <ddk/ntstatus.h>
17 #include <ddk/ntapi.h>
18 #undef cygwin_internal
19
20 #undef DEBUGGING
21 #ifdef DEBUGGING
22 #define dbg_printf(ARGS) printf ARGS ; fflush (NULL)
23 #else /* !DEBUGGING */
24 #define dbg_printf(ARGS) do { } while (0)
25 #endif /* ?DEBUGGING */
26
27 /* This module detects applications from the Big List of Dodgy Apps,
28 a list of applications that have at some given time been shown to
29 interfere with the operation of cygwin. It detects the presence of
30 applications on the system by looking for any of four traces an
31 installation might leave: 1) registry keys, 2) files on disk
32 3) running executables 4) loaded dlls or drivers.
33
34 At the time of writing, the BLODA amounts to:-
35
36 Sonic Solutions burning software containing DLA component
37 Norton/MacAffee/Symantec antivirus or antispyware
38 Logitech webcam software with "Logitech process monitor" service
39 Kerio, Agnitum or ZoneAlarm Personal Firewall
40 Iolo System Mechanic/AntiVirus/Firewall
41 LanDesk
42 Windows Defender
43 Embassy Trust Suite fingerprint reader software containing wxvault.dll
44 */
45
46 enum bad_app
47 {
48 SONIC, NORTON, MACAFFEE, SYMANTEC,
49 LOGITECH, KERIO, AGNITUM, ZONEALARM,
50 IOLO, LANDESK, WINDEFENDER, EMBASSYTS
51 };
52
53 struct bad_app_info
54 {
55 enum bad_app app_id;
56 const char *details;
57 char found_it;
58 };
59
60 enum bad_app_det_method
61 {
62 HKLMKEY, HKCUKEY, FILENAME, PROCESSNAME, HOOKDLLNAME
63 };
64
65 struct bad_app_det
66 {
67 enum bad_app_det_method type;
68 const char *param;
69 enum bad_app app;
70 };
71
72 static const struct bad_app_det dodgy_app_detects[] =
73 {
74 { PROCESSNAME, "dlactrlw.exe", SONIC },
75 { HOOKDLLNAME, "wxvault.dll", EMBASSYTS },
76 { HKLMKEY, "SYSTEM\\CurrentControlSet\\Services\\vsdatant", ZONEALARM },
77 { FILENAME, "%windir%\\System32\\vsdatant.sys", ZONEALARM },
78 { HKLMKEY, "SYSTEM\\CurrentControlSet\\Services\\lvprcsrv", LOGITECH },
79 { PROCESSNAME, "LVPrcSrv.exe", LOGITECH },
80 { FILENAME, "%programfiles%\\common files\\logitech\\lvmvfm\\LVPrcSrv.exe", LOGITECH },
81 };
82
83 static const size_t num_of_detects = sizeof (dodgy_app_detects) / sizeof (dodgy_app_detects[0]);
84
85 static struct bad_app_info big_list_of_dodgy_apps[] =
86 {
87 { SONIC, "Sonic Solutions burning software containing DLA component" },
88 { NORTON, "Norton antivirus or antispyware software" },
89 { MACAFFEE, "Macaffee antivirus or antispyware software" },
90 { SYMANTEC, "Symantec antivirus or antispyware software" },
91 { LOGITECH, "Logitech Process Monitor service" },
92 { KERIO, "Kerio Personal Firewall" },
93 { AGNITUM, "Agnitum Personal Firewall" },
94 { ZONEALARM, "ZoneAlarm Personal Firewall" },
95 { IOLO, "Iolo System Mechanic/AntiVirus/Firewall software" },
96 { LANDESK, "Landesk" },
97 { WINDEFENDER, "Windows Defender" },
98 { EMBASSYTS, "Embassy Trust Suite fingerprint reader software containing wxvault.dll" },
99 };
100
101 static const size_t num_of_dodgy_apps = sizeof (big_list_of_dodgy_apps) / sizeof (big_list_of_dodgy_apps[0]);
102
103 /* This function is not in the ntdll export lib, so it has
104 to be looked up at runtime and called through a pointer. */
105 VOID NTAPI (*pRtlFreeUnicodeString)(PUNICODE_STRING) = NULL;
106
107 static PSYSTEM_PROCESSES
108 get_process_list (void)
109 {
110 int n_procs = 0x100;
111 PSYSTEM_PROCESSES pslist = (PSYSTEM_PROCESSES) malloc (n_procs * sizeof *pslist);
112
113 while (NtQuerySystemInformation (SystemProcessesAndThreadsInformation,
114 pslist, n_procs * sizeof *pslist, 0) == STATUS_INFO_LENGTH_MISMATCH)
115 {
116 n_procs *= 2;
117 free (pslist);
118 pslist = (PSYSTEM_PROCESSES) malloc (n_procs * sizeof *pslist);
119 }
120 return pslist;
121 }
122
123 static PSYSTEM_MODULE_INFORMATION
124 get_module_list (void)
125 {
126 int modsize = 0x1000;
127 PSYSTEM_MODULE_INFORMATION modlist = (PSYSTEM_MODULE_INFORMATION) malloc (modsize);
128
129 while (NtQuerySystemInformation (SystemModuleInformation,
130 modlist, modsize, NULL) == STATUS_INFO_LENGTH_MISMATCH)
131 {
132 modsize *= 2;
133 free (modlist);
134 modlist = (PSYSTEM_MODULE_INFORMATION) malloc (modsize);
135 }
136 return modlist;
137 }
138
139 static bool
140 find_process_in_list (PSYSTEM_PROCESSES pslist, PUNICODE_STRING psname)
141 {
142 while (1)
143 {
144 if (pslist->ProcessName.Length && pslist->ProcessName.Buffer)
145 {
146 dbg_printf (("%S\n", pslist->ProcessName.Buffer));
147 if (!_wcsicmp (pslist->ProcessName.Buffer, psname->Buffer))
148 return true;
149 }
150 if (!pslist->NextEntryDelta)
151 break;
152 pslist = (PSYSTEM_PROCESSES)(pslist->NextEntryDelta + (char *)pslist);
153 };
154 return false;
155 }
156
157 static bool
158 find_module_in_list (PSYSTEM_MODULE_INFORMATION modlist, const char * const modname)
159 {
160 PSYSTEM_MODULE_INFORMATION_ENTRY modptr = &modlist->Module[0];
161 DWORD count = modlist->Count;
162 while (count--)
163 {
164 dbg_printf (("name '%s' offset %d ", &modptr->ImageName[0], modptr->PathLength));
165 dbg_printf (("= '%s'\n", &modptr->ImageName[modptr->PathLength]));
166 if (!_stricmp (&modptr->ImageName[modptr->PathLength], modname))
167 return true;
168 modptr++;
169 }
170 return false;
171 }
172
173 static bool
174 expand_path (const char *path, char *outbuf)
175 {
176 char *dst = outbuf;
177 const char *end, *envval;
178 char envvar[MAX_PATH];
179 size_t len;
180
181 while ((dst - outbuf) < MAX_PATH)
182 {
183 if (*path != '%')
184 {
185 if ((*dst++ = *path++) != 0)
186 continue;
187 break;
188 }
189 /* Expand an environ var. */
190 end = path + 1;
191 while (*end != '%')
192 {
193 /* Watch out for unterminated % */
194 if (*end++ == 0)
195 {
196 end = NULL;
197 break;
198 }
199 }
200 /* If we didn't find the end, can't expand it. */
201 if ((end == NULL) || (end == (path + 1)))
202 {
203 /* Unterminated % so copy verbatim. */
204 *dst++ = *path++;
205 continue;
206 }
207 /* Expand the environment var into the new path. */
208 if ((end - (path + 1)) >= MAX_PATH)
209 return -1;
210 memcpy (envvar, path + 1, end - (path + 1));
211 envvar[end - (path + 1)] = 0;
212 envval = getenv (envvar);
213 /* If not found, copy env var name verbatim. */
214 if (envval == NULL)
215 {
216 *dst++ = *path++;
217 continue;
218 }
219 /* Check enough room before copying. */
220 len = strlen (envval);
221 if ((dst + len - outbuf) >= MAX_PATH)
222 return false;
223 memcpy (dst, envval, len);
224 dst += len;
225 /* And carry on past the end of env var name. */
226 path = end + 1;
227 }
228 return (dst - outbuf) < MAX_PATH;
229 }
230
231 static bool
232 detect_dodgy_app (const struct bad_app_det *det, PSYSTEM_PROCESSES pslist, PSYSTEM_MODULE_INFORMATION modlist)
233 {
234 HANDLE fh;
235 HKEY hk;
236 UNICODE_STRING unicodename;
237 ANSI_STRING ansiname;
238 NTSTATUS rv;
239 bool found;
240 char expandedname[MAX_PATH];
241
242 switch (det->type)
243 {
244 case HKLMKEY:
245 dbg_printf (("Detect reg key hklm '%s'... ", det->param));
246 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, det->param, 0, STANDARD_RIGHTS_READ, &hk) == ERROR_SUCCESS)
247 {
248 RegCloseKey (hk);
249 dbg_printf (("found!\n"));
250 return true;
251 }
252 break;
253
254 case HKCUKEY:
255 dbg_printf (("Detect reg key hkcu '%s'... ", det->param));
256 if (RegOpenKeyEx (HKEY_CURRENT_USER, det->param, 0, STANDARD_RIGHTS_READ, &hk) == ERROR_SUCCESS)
257 {
258 RegCloseKey (hk);
259 dbg_printf (("found!\n"));
260 return true;
261 }
262 break;
263
264 case FILENAME:
265 dbg_printf (("Detect filename '%s'... ", det->param));
266 if (!expand_path (det->param, expandedname))
267 {
268 printf ("Expansion failure!\n");
269 break;
270 }
271 dbg_printf (("('%s' after expansion)... ", expandedname));
272 fh = CreateFile (expandedname, 0, FILE_SHARE_READ | FILE_SHARE_WRITE
273 | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
274 if (fh != INVALID_HANDLE_VALUE)
275 {
276 CloseHandle (fh);
277 dbg_printf (("found!\n"));
278 return true;
279 }
280 break;
281
282 case PROCESSNAME:
283 dbg_printf (("Detect proc name '%s'... ", det->param));
284 /* Equivalent of RtlInitAnsiString. */
285 ansiname.Length = ansiname.MaximumLength = strlen (det->param);
286 ansiname.Buffer = (CHAR *) det->param;
287 rv = RtlAnsiStringToUnicodeString (&unicodename, &ansiname, TRUE);
288 if (rv != STATUS_SUCCESS)
289 {
290 printf ("Ansi to unicode conversion failure $%08x\n", (unsigned int) rv);
291 break;
292 }
293 found = find_process_in_list (pslist, &unicodename);
294 if (!pRtlFreeUnicodeString)
295 pRtlFreeUnicodeString = (VOID NTAPI (*)(PUNICODE_STRING)) GetProcAddress (LoadLibrary ("ntdll.dll"), "RtlFreeUnicodeString");
296 if (pRtlFreeUnicodeString)
297 pRtlFreeUnicodeString (&unicodename);
298 else
299 printf ("leaking mem...oops\n");
300 if (found)
301 {
302 dbg_printf (("found!\n"));
303 return true;
304 }
305 break;
306
307 case HOOKDLLNAME:
308 dbg_printf (("Detect hookdll '%s'... ", det->param));
309 if (find_module_in_list (modlist, det->param))
310 {
311 dbg_printf (("found!\n"));
312 return true;
313 }
314 break;
315
316 }
317 dbg_printf (("not found.\n"));
318 return false;
319 }
320
321 static struct bad_app_info *
322 find_dodgy_app_info (enum bad_app which_app)
323 {
324 size_t i;
325 for (i = 0; i < num_of_dodgy_apps; i++)
326 {
327 if (big_list_of_dodgy_apps[i].app_id == which_app)
328 return &big_list_of_dodgy_apps[i];
329 }
330 return NULL;
331 }
332
333 /* External entrypoint called from cygcheck.cc/dump_sysinfo. */
334 void
335 dump_dodgy_apps (int verbose)
336 {
337 size_t i, n_det = 0;
338 PSYSTEM_PROCESSES pslist;
339 PSYSTEM_MODULE_INFORMATION modlist;
340
341 /* Read system info for detect testing. */
342 pslist = get_process_list ();
343 modlist = get_module_list ();
344
345 /* Go with builtin list for now; later may enhance to
346 read dodgy apps from a file or download from an URL. */
347 for (i = 0; i < num_of_dodgy_apps; i++)
348 {
349 big_list_of_dodgy_apps[i].found_it = false;
350 }
351
352 for (i = 0; i < num_of_detects; i++)
353 {
354 const struct bad_app_det *det = &dodgy_app_detects[i];
355 struct bad_app_info *found = find_dodgy_app_info (det->app);
356 bool detected = detect_dodgy_app (det, pslist, modlist);
357
358 /* Not found would mean we coded the lists bad. */
359 assert (found);
360 if (detected)
361 {
362 ++n_det;
363 found->found_it |= (1 << det->type);
364 }
365 }
366 if (n_det)
367 {
368 printf ("\nPotential app conflicts:\n\n");
369 for (i = 0; i < num_of_dodgy_apps; i++)
370 {
371 if (big_list_of_dodgy_apps[i].found_it)
372 {
373 printf ("%s%s", big_list_of_dodgy_apps[i].details,
374 verbose ? "\nDetected: " : ".\n");
375 if (!verbose)
376 continue;
377 const char *sep = "";
378 if (big_list_of_dodgy_apps[i].found_it & (1 << HKLMKEY))
379 {
380 printf ("HKLM Registry Key");
381 sep = ", ";
382 }
383 if (big_list_of_dodgy_apps[i].found_it & (1 << HKCUKEY))
384 {
385 printf ("%sHKCU Registry Key", sep);
386 sep = ", ";
387 }
388 if (big_list_of_dodgy_apps[i].found_it & (1 << FILENAME))
389 {
390 printf ("%sNamed file", sep);
391 sep = ", ";
392 }
393 if (big_list_of_dodgy_apps[i].found_it & (1 << PROCESSNAME))
394 {
395 printf ("%sNamed process", sep);
396 sep = ", ";
397 }
398 if (big_list_of_dodgy_apps[i].found_it & (1 << HOOKDLLNAME))
399 {
400 printf ("%sLoaded hook DLL", sep);
401 }
402 printf (".\n\n");
403 }
404 }
405 }
406 /* Tidy up allocations. */
407 free (pslist);
408 free (modlist);
409 }
410
This page took 0.075239 seconds and 6 git commands to generate.