0

I was trying to get when the user press some combination of keys trigger an event in our app (nothing malicious just and alert to our service)

so SetWindowsHookEx with WH_KEYBOARD_LL should acomplish that, works as expectect in some Windows version for both cases locked and normal state, the issue comes with "some" versions, for example in:

Windows 10 Pro 1803 17134.885 doesn't work

Windows 10 Pro 1803 17134.950 here it works

But can be other thing different from the version, some antivirus? [checked with/without] some register key entry?

I read many articles and tried different approachs but all with the same result, so anyone can help me with what should I check? because in some pc's works but others doesn't, looks something apart from the code...

The issue is just in lock screen (tried in different pcs), "normal" mode works everywhere, tried and working during the lock screen image in about 7 pc's (with different Win10 versions) but doesn't in about 4 (Windows 7, other Windows 10 with different users/locations) doesn't looks have something in common (maybe, but don't know where to search it)

The code used (C# Net Framework 4.5, Windows Forms):

public class KeyboardListener
    {
        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;
        private const int WM_SYSKEYDOWN = 0x0104;

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook, KeyboardListenerProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        public delegate IntPtr KeyboardListenerProc(int nCode, IntPtr wParam, IntPtr lParam);

        private KeyboardListenerProc _proc;
        private IntPtr _hookID = IntPtr.Zero;

        public KeyboardListener()
        {
            _proc = HookCallback;
        }

        public void HookKeyboard()
        {
            _hookID = SetHook(_proc);
        }

        public void UnHookKeyboard()
        {
            UnhookWindowsHookEx(_hookID);
        }

        private IntPtr SetHook(KeyboardListenerProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
            }
        }

        private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            //In some cases doesn't send anything in lock screen here, just the key "enter" after the password
            //while in most of the cases before you put the password you get the combination
            if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN)
            {
                int vkCode = Marshal.ReadInt32(lParam);

                //TODO: send to service vkCode
            }

            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }
    }

The above code works in some cases in the lock screen image (I don't need it while the password input is present), want to know why in some cases works while in others doesn't

Tried also changing


  private IntPtr SetHook(LowLevelKeyboardProc proc)
        {
            //using (Process curProcess = Process.GetCurrentProcess())
            //using (ProcessModule curModule = curProcess.MainModule)
            //{
            //    return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
            //}

            IntPtr hook = SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle("user32"), 0);
            if (hook == IntPtr.Zero)
            {
                throw new System.ComponentModel.Win32Exception();
            }
            return hook;
        }

MPelaezE
  • 1
  • 1
  • You must not use GetModuleHandle() on a managed module, that explains the failure in Win7. The lock screen in Win10 does not allow any program to observe keypresses, a very basic way to stop anybody from snooping passwords. https://stackoverflow.com/a/11615389/17034 – Hans Passant Aug 21 '19 at 12:23
  • Thanks @HansPassant I will try changing the GetModuleHandle for w7, about Win10 lock screen when is the lock image (not the password input) with the code above you can get the keypresses BUT not in all the pcs that's my main concern why in some pcs works (it shouldn't work in anyone if is a security thing, triend in Win10 pro/enterprise and differente locations/users)... – MPelaezE Aug 21 '19 at 13:58
  • Can this [demo](https://www.codeproject.com/Articles/19004/A-Simple-C-Global-Low-Level-Keyboard-Hook) give you some help? It works well in my PC. – Jeffreys Aug 22 '19 at 10:01
  • thanks for the reply @JeffreyShao-MSFT yes, I already tried that one too "works on my machine" but not in some others, also tried running as admin, same result – MPelaezE Aug 23 '19 at 09:06

1 Answers1

0

Windows 10 from some version (I don’t know the exact version) shows Default Desktop until it is dismissed to show LogonUI.exe. At that point, it shows Winlogon Desktop. That is why the hook works on those versions of Windows 10.

You can use the following code to check what the current input desktop is:

HDESK activeDesktop = OpenInputDesktop(0, FALSE, DESKTOP_READOBJECTS | DESKTOP_JOURNALPLAYBACK | DESKTOP_JOURNALRECORD);

    if (activeDesktop)
    {
        WCHAR desktopName[MAX_PATH];
        DWORD lengthNeeded;
        if (GetUserObjectInformation(activeDesktop, UOI_NAME, desktopName, ARRAYSIZE(desktopName), &lengthNeeded))
        {
            OutputDebugString(desktopName);
            OutputDebugString(L"\r\n");
        }
        else
        {
            OutputDebugString(L"Failed 1\r\n");
        }
        CloseDesktop(activeDesktop);
    }
    else
    {
        OutputDebugString(L"Failed 2\r\n");
    }

If Winlogon, OpenInputDesktop would fail.

Jeffreys
  • 431
  • 2
  • 8