新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 中文XML论坛 - 专业的XML技术讨论区计算机技术与应用『 C/C++编程思想 』 → 屏蔽系统热键的方法总结 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 3410 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: 屏蔽系统热键的方法总结 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客楼主
    发贴心情 屏蔽系统热键的方法总结

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

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

        2. 通过远程注入DLL到winlogon进程,修改winlogon桌面下SAS窗口的回调函数,从而捕获该窗口的WM_HOTKEY消息,并屏蔽它,可以实现屏蔽ctrl+delete+alt。这个方法相对复杂,可以解决第一点中存在的问题,但是也有缺陷,那就是除了Ctrl+Alt+Delete外,大多数的其它系统热键,(包括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);
    }


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2008/3/24 10:47:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/11/28 15:46:56

    本主题贴数1,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    62.500ms