title: C# event handler for security log (event 4648) triggering despite logging in successfully
body: <p>I am doing a student project to detect attempted logins into windows with wrong passwords (live-time) and warn the user. I detect when the computer is locked, then start listening for event 4648  written to event log.</p>
  
  <pre><code>4648 : A logon attempt with explicit credentials was attempted
  </code></pre>
  
  <p>My goal is to correctly detect <code>event 4648 when the screen is locked.</code> I have a <code>DateTime.Compare</code> that compares the timestamp when screen is locked and timestamp of 4648 event written. I make sure the handler only triggers if event is written <code>after</code> screen is locked.</p>
  
  <p>What baffles me is how the <code>handler for event 4648</code> <strong>still triggers on correct first-try login attempts.</strong> </p>
  
  <p>I have used these posts as reference </p>
  
  <p><a href="https://stackoverflow.com/questions/40423190/detect-windows-logon-attempts-programmatically-using-c-sharp">Detect windows logon attempts programmatically using C#</a><br>
  <a href="https://stackoverflow.com/questions/25190270/c-sharp-event-handler-is-called-multiple-times-when-event-is-raised-once">c# event handler is called multiple times when event is raised once</a><br>
  <a href="https://stackoverflow.com/questions/44980/programmatically-determine-a-duration-of-a-locked-workstation">Programmatically Determine a Duration of a Locked Workstation?</a> </p>
  
  <p>I have tried unsubscribing from previous event handlers before subscribing again as the post i linked, however to no avail. I can't seem to find the reason why the event handler for 4648 keeps triggering ambiguously. </p>
  
  <pre><code>public static void LoginLogoutDetector()
  {
      Microsoft.Win32.SystemEvents.SessionSwitch += new Microsoft.Win32.SessionSwitchEventHandler(SystemEvents_SessionSwitch);
  }
  
  //if user locks screen
  void SystemEvents_SessionSwitch(object sender, Microsoft.Win32.SessionSwitchEventArgs e)
  {
      //screen locked detection
      if (e.Reason == SessionSwitchReason.SessionLock)
      {
          EventLog logListener = new EventLog("Security");
  
          datetime = (DateTime.Now.ToString("dd:MM:yyyy hh:mm:ss tt")).ToString();//get the time of screenlock
          logListener.EntryWritten -= logListener_EntryWritten;//unregister prev subscribers
          logListener.EntryWritten += logListener_EntryWritten;//register 
          logListener.EnableRaisingEvents = true;
      }
      //screen unlock detection
      else if (e.Reason == SessionSwitchReason.SessionUnlock)
      {
          Console.WriteLine("Screen unlocked!");
      }
  }//sessionswitch
  </code></pre>
  
  <p>This is the code for the handler for <code>events written to event log</code></p>
  
  <pre><code>void logListener_EntryWritten(object sender, EntryWrittenEventArgs e)
  {
      //var eventLog = new EventLog("Security", System.Environment.MachineName);
      //eventLog.Clear();
      var events = new long[] { 4648 };
  
      //only tell me if there is a 4648 event 
      if (events.Contains(e.Entry.InstanceId))
      {
          Console.WriteLine("4648 detected. triggered IF block");
          string eventlogtime = e.Entry.TimeGenerated.ToString();// get timestamp of event log 4648 generated
  
          //get the timestamp the log was generated (after d2!)
          DateTime d1 = DateTime.Parse(eventlogtime);
          Console.WriteLine("D1 (Event Log Timestamp) " + d1);
          bruteforcelogtime = (d1).ToString();
  
          //get the timestamp of computer locked (before d1!)
          DateTime d2 = DateTime.ParseExact(datetime, "dd:MM:yyyy hh:mm:ss tt", CultureInfo.InvariantCulture);
          Console.WriteLine("D2 (Computer Locked) :" + d2);
  
          //d1 = event written
          //d2 = computer locked 
          //event log should always be written after pc lock. d1&gt;d2
          int result = DateTime.Compare(d1, d2);
          Console.WriteLine("Comparing d1,d2 = " + result);
          if (result &gt;= 0)//d1 later than d2
          {
              Console.WriteLine("Login with wrong password was attempted at " + e.Entry.TimeWritten);
              Console.Write("\n");
              MessageBox.Show("bad login detected");
          }
      }
      else
      {
          Console.WriteLine("there were no brute force attempts ( no 4648) ");
      }
  }//LoginLogoutDetector
  </code></pre>
  
  <p>I expect the event handler <code>logListener_EntryWritten</code> to only trigger when there are wrong login attempts. However it triggers even if there is a correct login attempt! </p>
  
  <p>Outputs: even when I login with correct credentials on first try</p>
  
  <pre><code>Screen unlocked!
  4648 detected. triggered IF block
  
  
  D1 (Event Log Timestamp) 2/8/2019 2:44:03 PM
  D2 (Computer Locked) :2/8/2019 2:43:59 PM
  Comparing d1,d2 = 1
  Login with wrong password was attempted at 2/8/2019 2:44:03 PM
  
  there were no brute force attempts ( no 4648) 
  there were no brute force attempts ( no 4648) 
  there were no brute force attempts ( no 4648) 
  there were no brute force attempts ( no 4648) 
  there were no brute force attempts ( no 4648) 
  </code></pre>