SetWindowsHookEx WH_KEYBOARD_LL 问题锁屏

Posted

技术标签:

【中文标题】SetWindowsHookEx WH_KEYBOARD_LL 问题锁屏【英文标题】:SetWindowsHookEx WH_KEYBOARD_LL issue lock screen 【发布时间】:2019-08-21 10:30:38 【问题描述】:

我试图在用户按下某些组合键时触发我们的应用程序中的事件(没有恶意只是提醒我们的服务)

所以带有 WH_KEYBOARD_LL 的 SetWindowsHookEx 应该能够实现这一点,在某些 Windows 版本中对于锁定和正常状态都可以正常工作,问题来自“某些”版本,例如:

Windows 10 Pro 1803 17134.885 不工作

Windows 10 Pro 1803 17134.950 在这里可以正常工作

但可以是其他与版本不同的东西,一些防病毒软件? [检查/不检查] 一些注册密钥条目?

我阅读了许多文章并尝试了不同的方法,但结果都相同,所以任何人都可以帮助我检查哪些内容?因为在某些 pc 的作品中,而另一些则没有,看起来与代码不同...

问题只是在锁屏中(在不同的电脑上尝试过),“正常”模式在任何地方都可以工作,在大约 7 台电脑(使用不同的 Win10 版本)的锁屏图像期间尝试和工作,但在大约 4 个( Windows 7,其他具有不同用户/位置的 Windows 10)看起来没有共同点(也许,但不知道在哪里搜索)

使用的代码(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);
        
    

上面的代码在某些情况下可以在锁屏图像中工作(我在输入密码时不需要它),想知道为什么在某些情况下可以工作,而在其他情况下则不能

也尝试过改变


  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;
        

【问题讨论】:

您不能在托管模块上使用 GetModuleHandle(),这解释了 Win7 中的失败。 Win10中的锁屏不允许任何程序观察按键,这是阻止任何人窥探密码的非常基本的方法。 ***.com/a/11615389/17034 感谢@HansPassant 我将尝试更改 w7 的 GetModuleHandle,关于 Win10 锁定屏幕,何时使用上面的代码锁定图像(不是密码输入)您可以获得按键但不是在所有电脑中这是我主要关心的为什么在某些电脑上工作(如果是安全问题,它不应该在任何人身上工作,在 Win10 专业版/企业版和不同的位置/用户中使用)... 这个demo能给你一些帮助吗?它在我的电脑上运行良好。 感谢@JeffreyShao-MSFT 的回复,是的,我已经尝试过“在我的机器上工作”,但在其他一些机器上不行,也尝试以管理员身份运行,结果相同 【参考方案1】:

某些版本的 Windows 10(我不知道确切的版本)会显示默认桌面,直到它被关闭以显示 LogonUI.exe。此时,它显示 Winlogon 桌面。这就是该挂钩适用于这些版本的 Windows 10 的原因。

您可以使用以下代码检查当前输入的桌面是什么:

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");
    

如果 Winlogon,OpenInputDesktop 会失败。

【讨论】:

以上是关于SetWindowsHookEx WH_KEYBOARD_LL 问题锁屏的主要内容,如果未能解决你的问题,请参考以下文章

为啥必须将 SetWindowsHookEx 与 Windows 消息队列一起使用

在我的线程上下文中调用“SetWindowsHookEx”函数

用于 DeviceIOControl 的 SetWindowsHookEx,要使用啥 hookid?

增加 Windows 7 中的 SetWindowsHookEx 限制

SetWindowsHookEx c#

SetWindowsHookEx 其他进程的 记录