From 64b94981dce92ddbdabe1e6d75ae3aa50350ed47 Mon Sep 17 00:00:00 2001 From: Dave Korn Date: Fri, 3 Aug 2007 19:41:48 +0000 Subject: [PATCH] * Makefile.in (cygcheck.exe): Add bloda.o as prerequisite, adjusting dependency-filtering $(wordlist ...) call appropriately. Link ntdll. (bloda.o): New rule to build bloda.o * cygcheck.cc (dump_sysinfo): Call bloda function dump_dodgy_apps(). * bloda.cc: New file implements detection of applications from the Big List Of Dodgy Apps. --- winsup/utils/ChangeLog | 9 + winsup/utils/Makefile.in | 18 +- winsup/utils/bloda.cc | 410 +++++++++++++++++++++++++++++++++++++++ winsup/utils/cygcheck.cc | 6 + 4 files changed, 438 insertions(+), 5 deletions(-) create mode 100644 winsup/utils/bloda.cc diff --git a/winsup/utils/ChangeLog b/winsup/utils/ChangeLog index 2c778097d..66936fd59 100644 --- a/winsup/utils/ChangeLog +++ b/winsup/utils/ChangeLog @@ -1,3 +1,12 @@ +2007-08-03 Dave Korn + + * Makefile.in (cygcheck.exe): Add bloda.o as prerequisite, adjusting + dependency-filtering $(wordlist ...) call appropriately. Link ntdll. + (bloda.o): New rule to build bloda.o + * cygcheck.cc (dump_sysinfo): Call bloda function dump_dodgy_apps(). + * bloda.cc: New file implements detection of applications from the + Big List Of Dodgy Apps. + 2007-07-24 Corinna Vinschen * COPYING.dumper: New file. diff --git a/winsup/utils/Makefile.in b/winsup/utils/Makefile.in index 10f7d6550..b354f43d0 100644 --- a/winsup/utils/Makefile.in +++ b/winsup/utils/Makefile.in @@ -1,6 +1,6 @@ # Makefile for Cygwin utilities # Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, -# 2005, 2006 Red Hat, Inc. +# 2005, 2006, 2007 Red Hat, Inc. # This file is part of Cygwin. @@ -99,15 +99,15 @@ else $(CXX) $(MINGW_CXXFLAGS) -o $@ ${wordlist 1,2,$^} -B$(mingw_build)/ $(MINGW_LDFLAGS) endif -cygcheck.exe: cygcheck.o path.o dump_setup.o $(MINGW_DEP_LDLIBS) +cygcheck.exe: cygcheck.o bloda.o path.o dump_setup.o $(MINGW_DEP_LDLIBS) ifeq "$(libz)" "" @echo '*** Building cygcheck without package content checking due to missing mingw libz.a.' endif ifdef VERBOSE - $(CXX) $(MINGW_CXXFLAGS) -o $@ ${wordlist 1,3,$^} -B$(mingw_build)/ $(MINGW_LDFLAGS) $(libz) + $(CXX) $(MINGW_CXXFLAGS) -o $@ ${wordlist 1,4,$^} -B$(mingw_build)/ $(MINGW_LDFLAGS) $(libz) -lntdll else - @echo $(CXX) -o $@ ${wordlist 1,3,$^} ${filter-out -B%, $(MINGW_CXXFLAGS) $(MINGW_LDFLAGS)} $(libz);\ - $(CXX) $(MINGW_CXXFLAGS) -o $@ ${wordlist 1,3,$^} -B$(mingw_build)/ $(MINGW_LDFLAGS) $(libz) + @echo $(CXX) -o $@ ${wordlist 1,4,$^} ${filter-out -B%, $(MINGW_CXXFLAGS) $(MINGW_LDFLAGS)} $(libz) -lntdll;\ + $(CXX) $(MINGW_CXXFLAGS) -o $@ ${wordlist 1,4,$^} -B$(mingw_build)/ $(MINGW_LDFLAGS) $(libz) -lntdll endif dumper.o: dumper.cc dumper.h @@ -150,6 +150,14 @@ else $(MINGW_CXX) $(zconf_h) $(zlib_h) $c -o $(@D)/$(basename $@)$o $(MINGW_CXXFLAGS) $< endif +bloda.o: bloda.cc +ifdef VERBOSE + ${MINGW_CXX} $c -o $(@D)/$(basename $@)$o $(MINGW_CXXFLAGS) -I$(updir) $< +else + @echo $(MINGW_CXX) $c -o $(@D)/$(basename $@)$o $(MINGW_CXXFLAGS) ... $^;\ + ${MINGW_CXX} $c -o $(@D)/$(basename $@)$o $(MINGW_CXXFLAGS) -I$(updir) $< +endif + cygcheck.o: cygcheck.cc ifdef VERBOSE ${MINGW_CXX} $c -o $(@D)/$(basename $@)$o $(MINGW_CXXFLAGS) -I$(updir) $< diff --git a/winsup/utils/bloda.cc b/winsup/utils/bloda.cc new file mode 100644 index 000000000..52aa67c94 --- /dev/null +++ b/winsup/utils/bloda.cc @@ -0,0 +1,410 @@ +/* bloda.cc + + Copyright 2007 Red Hat, Inc. + + This file is part of Cygwin. + + This software is a copyrighted work licensed under the terms of the + Cygwin license. Please consult the file "CYGWIN_LICENSE" for + details. */ + +#define cygwin_internal cygwin_internal_dontuse +#include +#include +#include +#include +#include +#include +#undef cygwin_internal + +#undef DEBUGGING +#ifdef DEBUGGING +#define dbg_printf(ARGS) printf ARGS ; fflush (NULL) +#else /* !DEBUGGING */ +#define dbg_printf(ARGS) do { } while (0) +#endif /* ?DEBUGGING */ + +/* This module detects applications from the Big List of Dodgy Apps, + a list of applications that have at some given time been shown to + interfere with the operation of cygwin. It detects the presence of + applications on the system by looking for any of four traces an + installation might leave: 1) registry keys, 2) files on disk + 3) running executables 4) loaded dlls or drivers. + + At the time of writing, the BLODA amounts to:- + + Sonic Solutions burning software containing DLA component + Norton/MacAffee/Symantec antivirus or antispyware + Logitech webcam software with "Logitech process monitor" service + Kerio, Agnitum or ZoneAlarm Personal Firewall + Iolo System Mechanic/AntiVirus/Firewall + LanDesk + Windows Defender + Embassy Trust Suite fingerprint reader software containing wxvault.dll +*/ + +enum bad_app +{ + SONIC, NORTON, MACAFFEE, SYMANTEC, + LOGITECH, KERIO, AGNITUM, ZONEALARM, + IOLO, LANDESK, WINDEFENDER, EMBASSYTS +}; + +struct bad_app_info +{ + enum bad_app app_id; + const char *details; + char found_it; +}; + +enum bad_app_det_method +{ + HKLMKEY, HKCUKEY, FILENAME, PROCESSNAME, HOOKDLLNAME +}; + +struct bad_app_det +{ + enum bad_app_det_method type; + const char *param; + enum bad_app app; +}; + +static const struct bad_app_det dodgy_app_detects[] = +{ + { PROCESSNAME, "dlactrlw.exe", SONIC }, + { HOOKDLLNAME, "wxvault.dll", EMBASSYTS }, + { HKLMKEY, "SYSTEM\\CurrentControlSet\\Services\\vsdatant", ZONEALARM }, + { FILENAME, "%windir%\\System32\\vsdatant.sys", ZONEALARM }, + { HKLMKEY, "SYSTEM\\CurrentControlSet\\Services\\lvprcsrv", LOGITECH }, + { PROCESSNAME, "LVPrcSrv.exe", LOGITECH }, + { FILENAME, "%programfiles%\\common files\\logitech\\lvmvfm\\LVPrcSrv.exe", LOGITECH }, +}; + +static const size_t num_of_detects = sizeof (dodgy_app_detects) / sizeof (dodgy_app_detects[0]); + +static struct bad_app_info big_list_of_dodgy_apps[] = +{ + { SONIC, "Sonic Solutions burning software containing DLA component" }, + { NORTON, "Norton antivirus or antispyware software" }, + { MACAFFEE, "Macaffee antivirus or antispyware software" }, + { SYMANTEC, "Symantec antivirus or antispyware software" }, + { LOGITECH, "Logitech Process Monitor service" }, + { KERIO, "Kerio Personal Firewall" }, + { AGNITUM, "Agnitum Personal Firewall" }, + { ZONEALARM, "ZoneAlarm Personal Firewall" }, + { IOLO, "Iolo System Mechanic/AntiVirus/Firewall software" }, + { LANDESK, "Landesk" }, + { WINDEFENDER, "Windows Defender" }, + { EMBASSYTS, "Embassy Trust Suite fingerprint reader software containing wxvault.dll" }, +}; + +static const size_t num_of_dodgy_apps = sizeof (big_list_of_dodgy_apps) / sizeof (big_list_of_dodgy_apps[0]); + +/* This function is not in the ntdll export lib, so it has + to be looked up at runtime and called through a pointer. */ +VOID NTAPI (*pRtlFreeUnicodeString)(PUNICODE_STRING) = NULL; + +static PSYSTEM_PROCESSES +get_process_list (void) +{ + int n_procs = 0x100; + PSYSTEM_PROCESSES pslist = (PSYSTEM_PROCESSES) malloc (n_procs * sizeof *pslist); + + while (NtQuerySystemInformation (SystemProcessesAndThreadsInformation, + pslist, n_procs * sizeof *pslist, 0) == STATUS_INFO_LENGTH_MISMATCH) + { + n_procs *= 2; + free (pslist); + pslist = (PSYSTEM_PROCESSES) malloc (n_procs * sizeof *pslist); + } + return pslist; +} + +static PSYSTEM_MODULE_INFORMATION +get_module_list (void) +{ + int modsize = 0x1000; + PSYSTEM_MODULE_INFORMATION modlist = (PSYSTEM_MODULE_INFORMATION) malloc (modsize); + + while (NtQuerySystemInformation (SystemModuleInformation, + modlist, modsize, NULL) == STATUS_INFO_LENGTH_MISMATCH) + { + modsize *= 2; + free (modlist); + modlist = (PSYSTEM_MODULE_INFORMATION) malloc (modsize); + } + return modlist; +} + +static bool +find_process_in_list (PSYSTEM_PROCESSES pslist, PUNICODE_STRING psname) +{ + while (1) + { + if (pslist->ProcessName.Length && pslist->ProcessName.Buffer) + { + dbg_printf (("%S\n", pslist->ProcessName.Buffer)); + if (!_wcsicmp (pslist->ProcessName.Buffer, psname->Buffer)) + return true; + } + if (!pslist->NextEntryDelta) + break; + pslist = (PSYSTEM_PROCESSES)(pslist->NextEntryDelta + (char *)pslist); + }; + return false; +} + +static bool +find_module_in_list (PSYSTEM_MODULE_INFORMATION modlist, const char * const modname) +{ + PSYSTEM_MODULE_INFORMATION_ENTRY modptr = &modlist->Module[0]; + DWORD count = modlist->Count; + while (count--) + { + dbg_printf (("name '%s' offset %d ", &modptr->ImageName[0], modptr->PathLength)); + dbg_printf (("= '%s'\n", &modptr->ImageName[modptr->PathLength])); + if (!_stricmp (&modptr->ImageName[modptr->PathLength], modname)) + return true; + modptr++; + } + return false; +} + +static bool +expand_path (const char *path, char *outbuf) +{ + char *dst = outbuf; + const char *end, *envval; + char envvar[MAX_PATH]; + size_t len; + + while ((dst - outbuf) < MAX_PATH) + { + if (*path != '%') + { + if ((*dst++ = *path++) != 0) + continue; + break; + } + /* Expand an environ var. */ + end = path + 1; + while (*end != '%') + { + /* Watch out for unterminated % */ + if (*end++ == 0) + { + end = NULL; + break; + } + } + /* If we didn't find the end, can't expand it. */ + if ((end == NULL) || (end == (path + 1))) + { + /* Unterminated % so copy verbatim. */ + *dst++ = *path++; + continue; + } + /* Expand the environment var into the new path. */ + if ((end - (path + 1)) >= MAX_PATH) + return -1; + memcpy (envvar, path + 1, end - (path + 1)); + envvar[end - (path + 1)] = 0; + envval = getenv (envvar); + /* If not found, copy env var name verbatim. */ + if (envval == NULL) + { + *dst++ = *path++; + continue; + } + /* Check enough room before copying. */ + len = strlen (envval); + if ((dst + len - outbuf) >= MAX_PATH) + return false; + memcpy (dst, envval, len); + dst += len; + /* And carry on past the end of env var name. */ + path = end + 1; + } + return (dst - outbuf) < MAX_PATH; +} + +static bool +detect_dodgy_app (const struct bad_app_det *det, PSYSTEM_PROCESSES pslist, PSYSTEM_MODULE_INFORMATION modlist) +{ + HANDLE fh; + HKEY hk; + UNICODE_STRING unicodename; + ANSI_STRING ansiname; + NTSTATUS rv; + bool found; + char expandedname[MAX_PATH]; + + switch (det->type) + { + case HKLMKEY: + dbg_printf (("Detect reg key hklm '%s'... ", det->param)); + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, det->param, 0, STANDARD_RIGHTS_READ, &hk) == ERROR_SUCCESS) + { + RegCloseKey (hk); + dbg_printf (("found!\n")); + return true; + } + break; + + case HKCUKEY: + dbg_printf (("Detect reg key hkcu '%s'... ", det->param)); + if (RegOpenKeyEx (HKEY_CURRENT_USER, det->param, 0, STANDARD_RIGHTS_READ, &hk) == ERROR_SUCCESS) + { + RegCloseKey (hk); + dbg_printf (("found!\n")); + return true; + } + break; + + case FILENAME: + dbg_printf (("Detect filename '%s'... ", det->param)); + if (!expand_path (det->param, expandedname)) + { + printf ("Expansion failure!\n"); + break; + } + dbg_printf (("('%s' after expansion)... ", expandedname)); + fh = CreateFile (expandedname, 0, FILE_SHARE_READ | FILE_SHARE_WRITE + | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL); + if (fh != INVALID_HANDLE_VALUE) + { + CloseHandle (fh); + dbg_printf (("found!\n")); + return true; + } + break; + + case PROCESSNAME: + dbg_printf (("Detect proc name '%s'... ", det->param)); + /* Equivalent of RtlInitAnsiString. */ + ansiname.Length = ansiname.MaximumLength = strlen (det->param); + ansiname.Buffer = (CHAR *) det->param; + rv = RtlAnsiStringToUnicodeString (&unicodename, &ansiname, TRUE); + if (rv != STATUS_SUCCESS) + { + printf ("Ansi to unicode conversion failure $%08x\n", (unsigned int) rv); + break; + } + found = find_process_in_list (pslist, &unicodename); + if (!pRtlFreeUnicodeString) + pRtlFreeUnicodeString = (VOID NTAPI (*)(PUNICODE_STRING)) GetProcAddress (LoadLibrary ("ntdll.dll"), "RtlFreeUnicodeString"); + if (pRtlFreeUnicodeString) + pRtlFreeUnicodeString (&unicodename); + else + printf ("leaking mem...oops\n"); + if (found) + { + dbg_printf (("found!\n")); + return true; + } + break; + + case HOOKDLLNAME: + dbg_printf (("Detect hookdll '%s'... ", det->param)); + if (find_module_in_list (modlist, det->param)) + { + dbg_printf (("found!\n")); + return true; + } + break; + + } + dbg_printf (("not found.\n")); + return false; +} + +static struct bad_app_info * +find_dodgy_app_info (enum bad_app which_app) +{ + size_t i; + for (i = 0; i < num_of_dodgy_apps; i++) + { + if (big_list_of_dodgy_apps[i].app_id == which_app) + return &big_list_of_dodgy_apps[i]; + } + return NULL; +} + +/* External entrypoint called from cygcheck.cc/dump_sysinfo. */ +void +dump_dodgy_apps (int verbose) +{ + size_t i, n_det = 0; + PSYSTEM_PROCESSES pslist; + PSYSTEM_MODULE_INFORMATION modlist; + + /* Read system info for detect testing. */ + pslist = get_process_list (); + modlist = get_module_list (); + + /* Go with builtin list for now; later may enhance to + read dodgy apps from a file or download from an URL. */ + for (i = 0; i < num_of_dodgy_apps; i++) + { + big_list_of_dodgy_apps[i].found_it = false; + } + + for (i = 0; i < num_of_detects; i++) + { + const struct bad_app_det *det = &dodgy_app_detects[i]; + struct bad_app_info *found = find_dodgy_app_info (det->app); + bool detected = detect_dodgy_app (det, pslist, modlist); + + /* Not found would mean we coded the lists bad. */ + assert (found); + if (detected) + { + ++n_det; + found->found_it |= (1 << det->type); + } + } + if (n_det) + { + printf ("\nPotential app conflicts:\n\n"); + for (i = 0; i < num_of_dodgy_apps; i++) + { + if (big_list_of_dodgy_apps[i].found_it) + { + printf ("%s%s", big_list_of_dodgy_apps[i].details, + verbose ? "\nDetected: " : ".\n"); + if (!verbose) + continue; + const char *sep = ""; + if (big_list_of_dodgy_apps[i].found_it & (1 << HKLMKEY)) + { + printf ("HKLM Registry Key"); + sep = ", "; + } + if (big_list_of_dodgy_apps[i].found_it & (1 << HKCUKEY)) + { + printf ("%sHKCU Registry Key", sep); + sep = ", "; + } + if (big_list_of_dodgy_apps[i].found_it & (1 << FILENAME)) + { + printf ("%sNamed file", sep); + sep = ", "; + } + if (big_list_of_dodgy_apps[i].found_it & (1 << PROCESSNAME)) + { + printf ("%sNamed process", sep); + sep = ", "; + } + if (big_list_of_dodgy_apps[i].found_it & (1 << HOOKDLLNAME)) + { + printf ("%sLoaded hook DLL", sep); + } + printf (".\n\n"); + } + } + } + /* Tidy up allocations. */ + free (pslist); + free (modlist); +} + diff --git a/winsup/utils/cygcheck.cc b/winsup/utils/cygcheck.cc index b75f38f26..61f7812f5 100644 --- a/winsup/utils/cygcheck.cc +++ b/winsup/utils/cygcheck.cc @@ -50,9 +50,13 @@ typedef long long longlong; typedef __int64 longlong; #endif +/* In dump_setup.cc */ void dump_setup (int, char **, bool); void package_find (int, char **); void package_list (int, char **); +/* In bloda.cc */ +void dump_dodgy_apps (int verbose); + static const char version[] = "$Revision$"; @@ -1623,6 +1627,8 @@ dump_sysinfo () if (!cygwin_dll_count) puts ("Warning: cygwin1.dll not found on your path"); + dump_dodgy_apps (verbose); + if (is_nt) dump_sysinfo_services (); }