屏蔽系统热键的方法总结

2024-01-11 22:18

本文主要是介绍屏蔽系统热键的方法总结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在编写程序的过程中,我们有时需要实现屏蔽操作系统一些热键的功能,如(ctrl+delete+alt,ctrl+shift+esc等)。网络上有很多关于这方面的资料,总结了一下,一般有如下两个方法:

    1. 通过加载低级键盘钩子(WH_KEYBOARD_LL)截获大部分的系统热键,并屏蔽它。这个方法比较简单,但有个缺陷,那就是对ctrl+alt+delete没有办法。

    2. 通过远程注入dll到winlogon进程,修改winlogon桌面下SAS窗口的回调函数,从而捕获该窗口的WM_HOTKEY消息,并屏蔽它,可以实现屏蔽ctrl+delete+alt。这个方法相对复杂,可以解决第一点中存在的问题,但是也有缺陷,那就是除了ctrl+delete+alt外,大多数的其它系统热键,(包括alt+tab,ctrl+esc及左右两个windows键)都无法屏蔽。

    所以如果我们的程序需要屏蔽大量的系统热键,就应当将以上两个方法结合起来使用。dll注入有很多好处,包括可以实现对我们所运行进程的隐藏,这非常有用。当我们的进程运行后,屏蔽掉了系统热键,当然不想用户随便在进程管理器里面就kill掉,因此将以上两个方法结合的办法就是把代码通通写到dll里面,然后再一起注入到winlogon进程中。

    对于上面所讲的第二点,注入到winlogon进程,没问题,可以很好的完成功能(网上有很多相关的文章及代码)。但对于第一点,如果在一个GUI程序中加载钩子,也没有问题。但现在加载的对象是winlogin进程,这个进程很特殊,它不是GUI进程,也不在系统应用程序所处的Default桌面下,因此在这个进程中加载钩子,需要注意以下几点:

    1. 在需要注入的dll代码中的DLL_PROCESS_ATTACH后面开启一个新线程,并在该线程中实现修改SAS窗口回调函数的代码以及设置低级键盘钩子。

    2. 由于钩子所在的线程为非GUI线程,因此,必须在该线程成功设置钩子以后主动接收并分发收到的消息,否则钩子将不会钩到任何消息:
       
MSG msg;
        while(GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

    3. 由于该线程创建时默认与winlogon同属一个桌面(winlogon桌面),而其它包括explorer.exe在内的GUI程序都处在Default桌面,在windows中规定程序只能获得针对同一桌面上创建的窗口消息。所以,要让该线程能接收到用户在Default桌面下操作所产生的消息,必须在该线程中使用如下代码将它的桌面设置为Default桌面:

        HDESK hDesk = OpenDesktop("Default",0,FALSE,MAXIMUM_ALLOWED);
        SetThreadDesktop(hDesk);
        CloseHandle(hDesk);

    我的程序在解决了以上问题之后,能正确将所编写的dll注入到winlogon进程,并在dll加载的时候开启线程,设置钩子,替换SAS窗口回调函数。从而实现屏蔽了我所能想到的所有系统热键。

    附:DLL的完整源码(注入该DLL到winlogon进程的源码大家可以在网上找到)

#define _WIN32_WINNT 0x0500 //Use WH_KEYBOARD_LL

#include <windows.h>
#include <stdio.h>

//SAS window句柄
HWND hSASWnd = NULL;
//原有SAS window回调函数地址
FARPROC FOldProc = NULL;
//起屏蔽作用的新SAS window回调函数
LRESULT CALLBACK SASWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
//枚举所有窗体句柄的回调函数
BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam);

//Dll所创建线程的句柄
HANDLE hThread = NULL;
//Dll所创建线程的ID
DWORD dwThreadId = 0;
//Dll所创建线程的线程函数
DWORD WINAPI ThreadFunc();

//_H钩子句柄
HHOOK hHook = NULL;
//_H低级键盘钩子回调函数
LRESULT CALLBACK KeyboardProc(int,WPARAM,LPARAM);

//对外输出字符串
char szOutput[36];

BOOL APIENTRY DllMain(HANDLE hMoudle, DWORD dwReason, LPVOID lpReserved)
{
    switch(dwReason)
 {
        case DLL_PROCESS_ATTACH:
   sprintf(szOutput,"Dll成功加载于 %d 号进程。",GetCurrentProcessId());
   OutputDebugString(szOutput);

   //创建更替SAS window回调函数的线程
   if(FOldProc == NULL)
    hThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadFunc,NULL,0,&dwThreadId);
   break;
        case DLL_PROCESS_DETACH:
   sprintf(szOutput,"Dll成功卸载。",GetCurrentProcessId());
   //MessageBox(NULL, szOutput, "ZZ", MB_ICONINFORMATION | MB_OK);
   OutputDebugString(szOutput);

   //恢复原有SAS window的回调函数
   if(FOldProc != NULL)
                SetWindowLong(hSASWnd,GWL_WNDPROC,long(FOldProc));
           
   //_H卸载低级键盘钩子
   if(hHook != NULL)
   {
    if(!UnhookWindowsHookEx(hHook))
    {
     OutputDebugString("Unhook failed..");
     //__leave;
     break;
    }
    OutputDebugString("键盘钩子成功取消");
   }
   TerminateThread(hThread,1);
   CloseHandle(hThread);

   break;
        case DLL_THREAD_ATTACH:
   break;
        case DLL_THREAD_DETACH:
   break;
    }
    return TRUE;
}

//Dll所创建线程的线程函数
DWORD WINAPI ThreadFunc()
{
    //打开Winlogon桌面
    HDESK hDesk = OpenDesktop("Winlogon",0,FALSE,MAXIMUM_ALLOWED);

 //枚举桌面所有窗体
    EnumDesktopWindows(hDesk,(WNDENUMPROC)EnumWindowsProc,0);
 //修改SAS window的回调函数
    if(hSASWnd != NULL)
    {
        FOldProc = (FARPROC)SetWindowLong(hSASWnd,GWL_WNDPROC,long(SASWindowProc));
    }
    CloseHandle(hDesk);

 //_H同一桌面上进程之间只能发送窗口消息。无法跨进程与其他桌面发送它们。
 //_H同样,Windows消息是限制应用程序定义挂钩。
 //_H特定桌面中运行的进程挂钩过程将〈〈只获得针对同一桌面上创建窗口消息。〉〉
 //_H详见
http://support.microsoft.com/kb/171890/zh-cn
 //_H所以,这里必须设置钩子所在线程的桌面为Default桌面
 //_H才能使得钩子所在线程能接收到Default桌面的消息
 hDesk = OpenDesktop("Default",0,FALSE,MAXIMUM_ALLOWED);
 SetThreadDesktop(hDesk);
 CloseHandle(hDesk);

 //_H设置低级键盘钩子,屏蔽非SAS window的热键
 //_H需要#define _WIN32_WINNT 0x0500
 hHook = SetWindowsHookEx(WH_KEYBOARD_LL,KeyboardProc,GetModuleHandle(NULL),0);
 if (hHook == NULL)
 {
  OutputDebugString("Set hook failed..");
  //__leave;
  return 1;
 }
 OutputDebugString("键盘钩子成功设置");

 //_H在非GUI线程中使用消息钩子必须主动接收并分发收到的消息
 MSG msg;
 while(GetMessage(&msg, NULL, 0, 0))
 {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }

 return 1;
}

//枚举所有窗体句柄的回调函数
BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam)
{
    char ClassBuf[128];
 //获得当前窗体的显示文本
    GetWindowText(hwnd,ClassBuf,sizeof(ClassBuf));

    //在"Winlogon"桌面中查询窗口"SAS window"。
 if(strstr(ClassBuf,"SAS window")!=NULL)
 {
        //返回SAS window句柄
  hSASWnd = hwnd;
        return FALSE;
    }
    return TRUE;
}

//起屏蔽作用的新SAS window回调函数
LRESULT CALLBACK SASWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
    if(uMsg == WM_HOTKEY)
    {
  //屏蔽所有WM_HOTKEY消息
  OutputDebugString("All SAS window's hotkeys are disabled");
  return 1;

        WORD wKey = HIWORD(lParam);
        WORD wModifier = LOWORD(lParam);
        bool IsCtrlDown = ((wModifier & VK_CONTROL) != 0);
        bool IsAltDown = ((wModifier & VK_MENU) != 0);
        bool IsShiftDown = ((wModifier & VK_SHIFT) != 0);

        //Ctrl + Alt + Del组合键
        if(IsCtrlDown && IsAltDown && wKey == VK_DELETE)
        {
   return 1; //屏蔽
        }
        //Ctrl + Shift + Esc组合键,这个组合键将显示任务管理器,可根据需要是否屏蔽。
        else if(IsCtrlDown && IsShiftDown && wKey == VK_ESCAPE)
        {
            // Do nothing
        }
    }

    return CallWindowProc((WNDPROC)FOldProc,hwnd,uMsg,wParam,lParam);
}

//_H低级键盘钩子回调函数
LRESULT CALLBACK KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam)
{
 if (nCode == HC_ACTION)
 {
        switch (wParam)
  {
   case WM_KEYDOWN:  case WM_SYSKEYDOWN:
   //case WM_KEYUP:    case WM_SYSKEYUP:
   PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT) lParam;

   if (p->vkCode == VK_F12)
   {
    //实现模拟按键代码
    MessageBox(GetForegroundWindow(),"I'm in position..","ZZ",MB_OK);
   }
   //屏蔽ALT+TAB
   else if ((p->vkCode == VK_TAB) && ((p->flags & LLKHF_ALTDOWN) != 0))
   {
    OutputDebugString("ALT+TAB is disabled");
    return 1;
   }
   //屏蔽ALT+ESC
   else if ((p->vkCode == VK_ESCAPE) && ((p->flags & LLKHF_ALTDOWN) != 0))
   {
    OutputDebugString("ALT+ESC is disabled");
    return 1;
   }
   //屏蔽CTRL+ESC
   else if ((p->vkCode == VK_ESCAPE) && ((GetKeyState(VK_CONTROL) & 0x8000) != 0))
   {
    OutputDebugString("CTRL+ESC is disabled");
    return 1;
   }
   //屏蔽CTRL+SHIFT+ESC,(SAS window中也已屏蔽)
   else if ((p->vkCode == VK_ESCAPE) &&
    ((GetKeyState(VK_CONTROL) & 0x8000) != 0) &&
    ((GetKeyState(VK_SHIFT) & 0x8000) != 0))
   {
    OutputDebugString("CTRL+SHIFT+ESC is disabled");
    return 1;
   }
   //屏蔽左右windows键
   else if (p->vkCode == VK_LWIN || p->vkCode == VK_RWIN)
   {
    OutputDebugString("windows key is disabled");
    return 1;
   }
   //此处无法屏蔽CTRL+ALT+DEL,已在SAS window中屏蔽
   else if ((p->vkCode == VK_DELETE) &&
     ((GetKeyState(VK_CONTROL) & 0x8000) != 0) &&
     ((GetKeyState(VK_MENU) & 0x8000) != 0 ))
    return 1;

   break;
  }
 }

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


 

这篇关于屏蔽系统热键的方法总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/595862

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

浅谈主机加固,六种有效的主机加固方法

在数字化时代,数据的价值不言而喻,但随之而来的安全威胁也日益严峻。从勒索病毒到内部泄露,企业的数据安全面临着前所未有的挑战。为了应对这些挑战,一种全新的主机加固解决方案应运而生。 MCK主机加固解决方案,采用先进的安全容器中间件技术,构建起一套内核级的纵深立体防护体系。这一体系突破了传统安全防护的局限,即使在管理员权限被恶意利用的情况下,也能确保服务器的安全稳定运行。 普适主机加固措施:

webm怎么转换成mp4?这几种方法超多人在用!

webm怎么转换成mp4?WebM作为一种新兴的视频编码格式,近年来逐渐进入大众视野,其背后承载着诸多优势,但同时也伴随着不容忽视的局限性,首要挑战在于其兼容性边界,尽管WebM已广泛适应于众多网站与软件平台,但在特定应用环境或老旧设备上,其兼容难题依旧凸显,为用户体验带来不便,再者,WebM格式的非普适性也体现在编辑流程上,由于它并非行业内的通用标准,编辑过程中可能会遭遇格式不兼容的障碍,导致操