3 Copyright 2007 Red Hat, Inc.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
11 #define cygwin_internal cygwin_internal_dontuse
16 #include <ddk/ntstatus.h>
17 #include <ddk/ntapi.h>
18 #undef cygwin_internal
22 #define dbg_printf(ARGS) printf ARGS ; fflush (NULL)
23 #else /* !DEBUGGING */
24 #define dbg_printf(ARGS) do { } while (0)
25 #endif /* ?DEBUGGING */
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.
34 At the time of writing, the BLODA amounts to:-
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
43 Embassy Trust Suite fingerprint reader software containing wxvault.dll
48 SONIC
, NORTON
, MACAFFEE
, SYMANTEC
,
49 LOGITECH
, KERIO
, AGNITUM
, ZONEALARM
,
50 IOLO
, LANDESK
, WINDEFENDER
, EMBASSYTS
60 enum bad_app_det_method
62 HKLMKEY
, HKCUKEY
, FILENAME
, PROCESSNAME
, HOOKDLLNAME
67 enum bad_app_det_method type
;
72 static const struct bad_app_det dodgy_app_detects
[] =
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
},
83 static const size_t num_of_detects
= sizeof (dodgy_app_detects
) / sizeof (dodgy_app_detects
[0]);
85 static struct bad_app_info big_list_of_dodgy_apps
[] =
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" },
101 static const size_t num_of_dodgy_apps
= sizeof (big_list_of_dodgy_apps
) / sizeof (big_list_of_dodgy_apps
[0]);
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
;
107 static PSYSTEM_PROCESSES
108 get_process_list (void)
111 PSYSTEM_PROCESSES pslist
= (PSYSTEM_PROCESSES
) malloc (n_procs
* sizeof *pslist
);
113 while (NtQuerySystemInformation (SystemProcessesAndThreadsInformation
,
114 pslist
, n_procs
* sizeof *pslist
, 0) == STATUS_INFO_LENGTH_MISMATCH
)
118 pslist
= (PSYSTEM_PROCESSES
) malloc (n_procs
* sizeof *pslist
);
123 static PSYSTEM_MODULE_INFORMATION
124 get_module_list (void)
126 int modsize
= 0x1000;
127 PSYSTEM_MODULE_INFORMATION modlist
= (PSYSTEM_MODULE_INFORMATION
) malloc (modsize
);
129 while (NtQuerySystemInformation (SystemModuleInformation
,
130 modlist
, modsize
, NULL
) == STATUS_INFO_LENGTH_MISMATCH
)
134 modlist
= (PSYSTEM_MODULE_INFORMATION
) malloc (modsize
);
140 find_process_in_list (PSYSTEM_PROCESSES pslist
, PUNICODE_STRING psname
)
144 if (pslist
->ProcessName
.Length
&& pslist
->ProcessName
.Buffer
)
146 dbg_printf (("%S\n", pslist
->ProcessName
.Buffer
));
147 if (!_wcsicmp (pslist
->ProcessName
.Buffer
, psname
->Buffer
))
150 if (!pslist
->NextEntryDelta
)
152 pslist
= (PSYSTEM_PROCESSES
)(pslist
->NextEntryDelta
+ (char *)pslist
);
158 find_module_in_list (PSYSTEM_MODULE_INFORMATION modlist
, const char * const modname
)
160 PSYSTEM_MODULE_INFORMATION_ENTRY modptr
= &modlist
->Module
[0];
161 DWORD count
= modlist
->Count
;
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
))
174 expand_path (const char *path
, char *outbuf
)
177 const char *end
, *envval
;
178 char envvar
[MAX_PATH
];
181 while ((dst
- outbuf
) < MAX_PATH
)
185 if ((*dst
++ = *path
++) != 0)
189 /* Expand an environ var. */
193 /* Watch out for unterminated % */
200 /* If we didn't find the end, can't expand it. */
201 if ((end
== NULL
) || (end
== (path
+ 1)))
203 /* Unterminated % so copy verbatim. */
207 /* Expand the environment var into the new path. */
208 if ((end
- (path
+ 1)) >= MAX_PATH
)
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. */
219 /* Check enough room before copying. */
220 len
= strlen (envval
);
221 if ((dst
+ len
- outbuf
) >= MAX_PATH
)
223 memcpy (dst
, envval
, len
);
225 /* And carry on past the end of env var name. */
228 return (dst
- outbuf
) < MAX_PATH
;
232 detect_dodgy_app (const struct bad_app_det
*det
, PSYSTEM_PROCESSES pslist
, PSYSTEM_MODULE_INFORMATION modlist
)
236 UNICODE_STRING unicodename
;
237 ANSI_STRING ansiname
;
240 char expandedname
[MAX_PATH
];
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
)
249 dbg_printf (("found!\n"));
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
)
259 dbg_printf (("found!\n"));
265 dbg_printf (("Detect filename '%s'... ", det
->param
));
266 if (!expand_path (det
->param
, expandedname
))
268 printf ("Expansion failure!\n");
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
)
277 dbg_printf (("found!\n"));
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
)
290 printf ("Ansi to unicode conversion failure $%08x\n", (unsigned int) rv
);
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
);
299 printf ("leaking mem...oops\n");
302 dbg_printf (("found!\n"));
308 dbg_printf (("Detect hookdll '%s'... ", det
->param
));
309 if (find_module_in_list (modlist
, det
->param
))
311 dbg_printf (("found!\n"));
317 dbg_printf (("not found.\n"));
321 static struct bad_app_info
*
322 find_dodgy_app_info (enum bad_app which_app
)
325 for (i
= 0; i
< num_of_dodgy_apps
; i
++)
327 if (big_list_of_dodgy_apps
[i
].app_id
== which_app
)
328 return &big_list_of_dodgy_apps
[i
];
333 /* External entrypoint called from cygcheck.cc/dump_sysinfo. */
335 dump_dodgy_apps (int verbose
)
338 PSYSTEM_PROCESSES pslist
;
339 PSYSTEM_MODULE_INFORMATION modlist
;
341 /* Read system info for detect testing. */
342 pslist
= get_process_list ();
343 modlist
= get_module_list ();
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
++)
349 big_list_of_dodgy_apps
[i
].found_it
= false;
352 for (i
= 0; i
< num_of_detects
; i
++)
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
);
358 /* Not found would mean we coded the lists bad. */
363 found
->found_it
|= (1 << det
->type
);
368 printf ("\nPotential app conflicts:\n\n");
369 for (i
= 0; i
< num_of_dodgy_apps
; i
++)
371 if (big_list_of_dodgy_apps
[i
].found_it
)
373 printf ("%s%s", big_list_of_dodgy_apps
[i
].details
,
374 verbose
? "\nDetected: " : ".\n");
377 const char *sep
= "";
378 if (big_list_of_dodgy_apps
[i
].found_it
& (1 << HKLMKEY
))
380 printf ("HKLM Registry Key");
383 if (big_list_of_dodgy_apps
[i
].found_it
& (1 << HKCUKEY
))
385 printf ("%sHKCU Registry Key", sep
);
388 if (big_list_of_dodgy_apps
[i
].found_it
& (1 << FILENAME
))
390 printf ("%sNamed file", sep
);
393 if (big_list_of_dodgy_apps
[i
].found_it
& (1 << PROCESSNAME
))
395 printf ("%sNamed process", sep
);
398 if (big_list_of_dodgy_apps
[i
].found_it
& (1 << HOOKDLLNAME
))
400 printf ("%sLoaded hook DLL", sep
);
406 /* Tidy up allocations. */