HidGuardian Whitelist cleanup



  • Originally posted by JoshWobbles


    Figured you are probibly working on a solution that is pretty similiar to this, but ill thow some ideas up anyway. Due to intermittent pipe failure between the Cerberus library and service, applications even when written correctly sometimes aren't able to do their own housekeeping. Because of that and because I wanted to add backwards support for applications I have already written but do not want to go through modifying to add HidGuardian support for; I have written another service that I couple with my apps that uses WMI to detect processes starting and stopping and matches them against a whitelist of process names then uses the WMI info to keep the PID whitelist keys up to date. It will even clean up after other processes that leave their key around after exiting.

    This has the benefit of being independent of my user application making it backwards compatible. The only issue being that since the WMI events are not blocking events but rather fired async of the process creation, there is the possibility of a race condition where the user application may attempt to open a device before the PID is whitelisted. Since my applications pool devices that are not in a open state but are in my own white list of devices I handle this is ok as the device will simply try to open again on the next cycle of the pooling, for others that rely on event driven device arrival and removal weather through system messages or the WMI, this could be an issue if an artificial sleep is not used.

    `using System.IO.Pipes;
    using System.Linq;
    using System.Management;
    using System.ServiceModel;
    using System.ServiceProcess;
    using System.Text;
    using System.Threading.Tasks;
    using System.Xml;

    namespace InputMapperCerberusWhitelister
    {
        public partial class Service1 : ServiceBase
        {
            private static string HidWhitelistRegistryKeyBase => @"SYSTEM\CurrentControlSet\Services\HidGuardian\Parameters\Whitelist";
            private static string[] TrustedApplications = { "inputmapper.exe", "inputmapper1.exe", "inputmapper2.exe" };
    
            private static log4net.ILog log;
            private static NamedPipeServerStream s;
            private static bool isRunning = false;
            private static ManagementEventWatcher startWatch;
            private static ManagementEventWatcher stopWatch;
    
            public Service1()
            {
                InitializeComponent();
            }
    
            protected override void OnStart(string[] args)
            {
                log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
                log4net.Config.XmlConfigurator.Configure();
    
                isRunning = true;
                s = new NamedPipeServerStream("InputMapperCerberusWhitelister", PipeDirection.In, 2);
                Action<NamedPipeServerStream> a = callBack;
                a.BeginInvoke(s, ar => { }, null);
    
                log.DebugFormat("Hooking WMI");
    
                startWatch = new ManagementEventWatcher(new WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace"));
                startWatch.EventArrived += new EventArrivedEventHandler(startWatch_EventArrived);
                startWatch.Start();
    
                stopWatch = new ManagementEventWatcher(new WqlEventQuery("SELECT * FROM Win32_ProcessStopTrace"));
                stopWatch.EventArrived += new EventArrivedEventHandler(stopWatch_EventArrived);
                stopWatch.Start();
    
                log.DebugFormat("WMI Hooked");
            }
    
            protected override void OnStop()
            {
                isRunning = false;
    
                using (var pipe = new NamedPipeClientStream(".", "InputMapperCerberusWhitelister", PipeDirection.Out))
                using (var stream = new StreamWriter(pipe))
                {
                    pipe.Connect();
                    stream.Write("Shutdown");
                }
    
                if (startWatch != null)
                    startWatch.Stop();
    
                if (stopWatch != null)
                    stopWatch.Stop();
    
            }
    
            private void callBack(NamedPipeServerStream pipe)
            {
                while (isRunning)
                {
                    pipe.WaitForConnection();
                    StreamReader sr = new StreamReader(pipe);
                    string message = sr.ReadToEnd();
                    //processPipeMessage(message);
                    pipe.Disconnect();
                }
            }
    
            static void startWatch_EventArrived(object sender, EventArrivedEventArgs e)
            {
                string processName = e.NewEvent.Properties["ProcessName"].Value.ToString().ToLower();
                int processID = Convert.ToInt32(e.NewEvent.Properties["ProcessID"].Value.ToString() ?? "0");
    
                if (TrustedApplications.Contains(processName))
                {
                    log.DebugFormat("Trusted application {0} at PID {1} detected.", processName, processID);
                
                    try
                    {
                        Registry.LocalMachine.CreateSubKey($"{HidWhitelistRegistryKeyBase}\\{processID}");
                    }
                    catch (Exception ex)
                    {
                        log.Error(ex);
                    }
                }
            }
    
            private void stopWatch_EventArrived(object sender, EventArrivedEventArgs e)
            {
                string processName = e.NewEvent.Properties["ProcessName"].Value.ToString().ToLower();
                int processID = Convert.ToInt32(e.NewEvent.Properties["ProcessID"].Value.ToString() ?? "0");
    
                if (TrustedApplications.Contains(processName) || Registry.LocalMachine.OpenSubKey($"{HidWhitelistRegistryKeyBase}\\{processID}") != null)
                {
                    log.DebugFormat("Trusted application {0} at PID {1} exiting.", processName, processID);
    
                    try
                    {
                        Registry.LocalMachine.DeleteSubKey($"{HidWhitelistRegistryKeyBase}\\{processID}");
                    }
                    catch (Exception ex)
                    {
                        log.Error(ex);
                    }
                }
            }
        }
    }`