425 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			425 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* bloda.cc
 | 
						|
 | 
						|
   Copyright 2007, 2008, 2011, 2012 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 <stdio.h>
 | 
						|
#include <assert.h>
 | 
						|
#define WIN32_NO_STATUS	/* Disable status codes in winnt.h since we include
 | 
						|
			   ntstatus.h for extended status codes below. */
 | 
						|
#include <windows.h>
 | 
						|
#undef WIN32_NO_STATUS
 | 
						|
#include <psapi.h>
 | 
						|
#include <winternl.h>
 | 
						|
#include <ntstatus.h>
 | 
						|
#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
 | 
						|
    ByteMobile laptop optimization client
 | 
						|
 | 
						|
  A live version is now being maintained in the Cygwin FAQ, at
 | 
						|
    http://cygwin.com/faq/faq.using.html#faq.using.bloda
 | 
						|
 | 
						|
*/
 | 
						|
 | 
						|
enum bad_app
 | 
						|
{
 | 
						|
  SONIC,    NORTON,  MACAFFEE,    SYMANTEC,
 | 
						|
  LOGITECH, KERIO,   AGNITUM,     ZONEALARM,
 | 
						|
  IOLO,     LANDESK, WINDEFENDER, EMBASSYTS,
 | 
						|
  BYTEMOBILE
 | 
						|
};
 | 
						|
 | 
						|
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   },
 | 
						|
  { FILENAME,    "%windir%\\System32\\bmnet.dll",                                BYTEMOBILE },
 | 
						|
};
 | 
						|
 | 
						|
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" },
 | 
						|
  { BYTEMOBILE,  "ByteMobile laptop optimization client"                                  },
 | 
						|
};
 | 
						|
 | 
						|
static const size_t num_of_dodgy_apps = sizeof (big_list_of_dodgy_apps) / sizeof (big_list_of_dodgy_apps[0]);
 | 
						|
 | 
						|
struct system_module_list
 | 
						|
{
 | 
						|
  LONG count;
 | 
						|
  PVOID *pid;
 | 
						|
  PCHAR *name;
 | 
						|
};
 | 
						|
 | 
						|
static PSYSTEM_PROCESS_INFORMATION
 | 
						|
get_process_list (void)
 | 
						|
{
 | 
						|
  int n_procs = 0x100;
 | 
						|
  PSYSTEM_PROCESS_INFORMATION pslist = (PSYSTEM_PROCESS_INFORMATION) malloc (n_procs * sizeof *pslist);
 | 
						|
 | 
						|
  while (NtQuerySystemInformation (SystemProcessInformation,
 | 
						|
    pslist, n_procs * sizeof *pslist, 0) == STATUS_INFO_LENGTH_MISMATCH)
 | 
						|
    {
 | 
						|
      n_procs *= 2;
 | 
						|
      free (pslist);
 | 
						|
      pslist = (PSYSTEM_PROCESS_INFORMATION) malloc (n_procs * sizeof *pslist);
 | 
						|
    }
 | 
						|
  return pslist;
 | 
						|
}
 | 
						|
 | 
						|
static system_module_list *
 | 
						|
get_module_list (void)
 | 
						|
{
 | 
						|
  DWORD modsize = 0;
 | 
						|
  system_module_list *modlist = (system_module_list *)
 | 
						|
				calloc (1, sizeof (system_module_list));
 | 
						|
  while (!EnumDeviceDrivers (modlist->pid, modsize, &modsize))
 | 
						|
    {
 | 
						|
      free (modlist->pid);
 | 
						|
      free (modlist->name);
 | 
						|
      modlist->count = modsize / sizeof (PVOID);
 | 
						|
      modlist->pid = (PVOID *) calloc (modlist->count, sizeof (PVOID));
 | 
						|
      modlist->name = (PCHAR *) calloc (modlist->count, sizeof (PCHAR));
 | 
						|
    }
 | 
						|
  for (int i = 0; i < modlist->count; ++i)
 | 
						|
    {
 | 
						|
      modlist->name[0] = (PCHAR) calloc (256, sizeof (CHAR));
 | 
						|
      GetDeviceDriverBaseNameA (modlist->pid[i], modlist->name[i], 256);
 | 
						|
    }
 | 
						|
  return modlist;
 | 
						|
}
 | 
						|
 | 
						|
static bool
 | 
						|
find_process_in_list (PSYSTEM_PROCESS_INFORMATION pslist, PUNICODE_STRING psname)
 | 
						|
{
 | 
						|
  while (1)
 | 
						|
    {
 | 
						|
      if (pslist->ImageName.Length && pslist->ImageName.Buffer)
 | 
						|
	{
 | 
						|
	  dbg_printf (("%S\n", pslist->ImageName.Buffer));
 | 
						|
	  if (!_wcsicmp (pslist->ImageName.Buffer, psname->Buffer))
 | 
						|
	    return true;
 | 
						|
	}
 | 
						|
      if (!pslist->NextEntryOffset)
 | 
						|
	break;
 | 
						|
      pslist = (PSYSTEM_PROCESS_INFORMATION)(pslist->NextEntryOffset + (char *)pslist);
 | 
						|
    };
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
static bool
 | 
						|
find_module_in_list (system_module_list * modlist, const char * const modname)
 | 
						|
{
 | 
						|
  for (int i = 0; i < modlist->count; ++i)
 | 
						|
    {
 | 
						|
      dbg_printf (("name '%s' ", modlist->name[i]));
 | 
						|
      if (!_stricmp (modlist->name[i], modname))
 | 
						|
	return true;
 | 
						|
    }
 | 
						|
  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_PROCESS_INFORMATION pslist, system_module_list * 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);
 | 
						|
      RtlFreeUnicodeString (&unicodename);
 | 
						|
      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_PROCESS_INFORMATION pslist;
 | 
						|
  system_module_list * 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);
 | 
						|
  for (int i = 0; i < modlist->count; ++i)
 | 
						|
    free (modlist->name[i]);
 | 
						|
  free (modlist->name);
 | 
						|
  free (modlist->pid);
 | 
						|
}
 | 
						|
 |