Search code examples
windows-7user-accountskeyboard-hook

WIN7 Keyboard hook stops working in another user account?


I created my own parental control app using C# to monitor my kids activity. It logs all the keyboard input and screens in the background silently, with the only gui of taskbar icon. So far, I just let it run in my admin account and everybody share the same account and it works fine. The problem is that as kids grow up, they found a way to kill it from the task manager. So, I need to use a more sophisticated way to protect my app. I thought I could solve this problem easily by creating a separate standard account for each kid and I can setup my app to run as an admin to monitor all their activities. However, I faced a lot of issues.

  1. The keyboard hooks seem to stop working once I switched to a different user account. Is it true? I thought it's global hook - is it just global within the user account?

  2. The screen capturing doesn't work on another user account either. This is my code and

it failed at g.CopyFromScreen with error "the handle is invalid":

RECT rc = Win32.GetWindowRect();
using (System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(rc.Width, rc.Height))
{
    using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap))
    {
        g.CopyFromScreen(rc.Location, System.Drawing.Point.Empty, new System.Drawing.Size(rc.Width, rc.Height));
        string fileName = Settings.Instance.GetImageFileName();
        bitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Png);
    }
}   

Your help is much appreciated.


Solution

  • As long as the kids aren't administrators, you can run the program under their accounts and deny access to the process.

    For example (tested):

    static void SetAcl() {
        var sd = new RawSecurityDescriptor(ControlFlags.None,
            new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null),
            null, null, new RawAcl(2, 0));
    
        sd.SetFlags(ControlFlags.DiscretionaryAclPresent | ControlFlags.DiscretionaryAclDefaulted);
        var rawSd = new byte[sd.BinaryLength];
    
        sd.GetBinaryForm(rawSd, 0);
        if (!NativeMethods.SetKernelObjectSecurity(Process.GetCurrentProcess().Handle, SecurityInfos.DiscretionaryAcl, rawSd))
            throw new Win32Exception();
    }
    
    static class NativeMethods {
        [DllImport("Advapi32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool SetKernelObjectSecurity(IntPtr target, SecurityInfos info, byte[] descriptor);
    }