转载请标明是引用于 http://blog.csdn.net/chenyujing1234 

欢迎大家拍砖

 

在我们编写远程控制软件的时候,我们会发现要想解锁server端我们就得发送这三个键的虚拟。

下面我说一下解决过程:


1.一开始,决定通过keybd_event()来模拟键盘

  1. keybd_event(VK_CONTROL,MapVirtualKey(VK_CONTROL,0),0,0);   
  2.      keybd_event(VK_MENU,MapVirtualKey(VK_MENU,0),0,0);   
  3.      keybd_event(VK_DELETE,MapVirtualKey(VK_DELETE,0),0,0);  
  4.         keybd_event(VK_DELETE,MapVirtualKey(VK_DELETE,0),KEYEVENTF_KEYUP,0);  
  5.      keybd_event(VK_MENU,MapVirtualKey(VK_MENU,0),KEYEVENTF_KEYUP,0);   
  6.      keybd_event(VK_CONTROL,MapVirtualKey(VK_CONTROL,0),KEYEVENTF_KEYUP,0);   


发现只能模拟ctrl+alt两个键的效果,然而其他的两个键的都可以模拟比如win+d。不知道是不是keybd_event()只能模拟两键还是因为
ctrl+alt+delete的特殊性,望高手告之,在此谢过。

 

2.运用PostMessage(HWND_BROADCAST, WM_HOTKEY, 0, MAKELONG(MOD_ALT | MOD_CONTROL, VK_DELETE));来发送虚拟键盘,

但是在winNT以后的系统里我们还有很多事情要做,比如:OpenDesktop()、OpenInputDesktop()、GetThreadDesktop()、SetThreadDesktop()、CloseDesktop()、GetUserObjectInformation()

代码如下:

 

  1. /** 
  2.  * @brief 模拟ctrl+alt+delete三键  
  3.  * 
  4.  * @param[in] NULL      
  5.  * 
  6.  * @return  TRUE    成功 
  7.  *          FALSE   失败   
  8.  * @note 
  9.  */  
  10. BOOL SimulateAltControlDel()  
  11. {  
  12.     HDESK   hdeskCurrent;  
  13.     HDESK   hdesk;  
  14.     HWINSTA hwinstaCurrent;  
  15.     HWINSTA hwinsta;  
  16.   
  17.     // Save the current Window station  
  18.     hwinstaCurrent = GetProcessWindowStation();  
  19.     if (hwinstaCurrent == NULL)  
  20.         return FALSE;  
  21.   
  22.     // Save the current desktop  
  23.     hdeskCurrent = GetThreadDesktop(GetCurrentThreadId());  
  24.     if (hdeskCurrent == NULL)  
  25.         return FALSE;  
  26.       
  27.     // Obtain a handle to WinSta0 - service must be running  
  28.     // in the LocalSystem account  
  29.     hwinsta = OpenWindowStation(L"winsta0", FALSE,  
  30.         WINSTA_ACCESSCLIPBOARD   |  
  31.         WINSTA_ACCESSGLOBALATOMS |  
  32.         WINSTA_CREATEDESKTOP     |  
  33.         WINSTA_ENUMDESKTOPS      |  
  34.         WINSTA_ENUMERATE         |  
  35.         WINSTA_EXITWINDOWS       |  
  36.         WINSTA_READATTRIBUTES    |  
  37.         WINSTA_READSCREEN        |  
  38.         WINSTA_WRITEATTRIBUTES);  
  39.     if (hwinsta == NULL)  
  40.         return FALSE;  
  41.   
  42.     // Set the windowstation to be winsta0  
  43.     if (!SetProcessWindowStation(hwinsta))  
  44.         return FALSE;  
  45.   
  46.     // Get the default desktop on winsta0  
  47.     hdesk = OpenDesktop(L"Winlogon", 0, FALSE,  
  48.         DESKTOP_CREATEMENU |  
  49.         DESKTOP_CREATEWINDOW |  
  50.         DESKTOP_ENUMERATE    |  
  51.         DESKTOP_HOOKCONTROL  |  
  52.         DESKTOP_JOURNALPLAYBACK |  
  53.         DESKTOP_JOURNALRECORD |  
  54.         DESKTOP_READOBJECTS |  
  55.         DESKTOP_SWITCHDESKTOP |  
  56.         DESKTOP_WRITEOBJECTS);  
  57.     if (hdesk == NULL)  
  58.     {  
  59.         return FALSE;  
  60.     }  
  61.   
  62.     // Set the desktop to be "default"  
  63.     if (!SetThreadDesktop(hdesk))  
  64.         return FALSE;  
  65.   
  66.     PostMessage(HWND_BROADCAST, WM_HOTKEY, 0, MAKELPARAM(MOD_ALT|MOD_CONTROL,VK_DELETE));  
  67.   
  68.   
  69.     // Reset the Window station and desktop  
  70.     if (!SetProcessWindowStation(hwinstaCurrent))  
  71.         return FALSE;  
  72.   
  73.     if (!SetThreadDesktop(hdeskCurrent))  
  74.         return FALSE;  
  75.   
  76.     // Close the windowstation and desktop handles  
  77.     if (!CloseWindowStation(hwinsta))  
  78.         return FALSE;  
  79.     if (!CloseDesktop(hdesk))  
  80.         return FALSE;  
  81.   
  82.     return TRUE;  
  83. }  


 

偶一开始试验了发现不成功,后来冰河大哥告诉我说OpenDesktop("Winlogon", ......)本身需要LocalSystem权限,
果然如此,把它注册成服务
,然后效果实现。相信如何注册成服务不用我说了吧。ok,我们想要的功能实现了。

2、1  在win7下存在的问题

参考: http://topic.csdn.net/u/20110503/11/4d0c6fc5-592b-4f76-90b5-3201e509185f.html

可能原因

(1)windows7 安全要求高;

(2)我写测试代码检查了下发现:
WTSGetActiveConsoleSessionId返回值ProcessIdToSessionId(GetCurrentProcessId(),&sessionid)后的sessionid值不相等,请问列林大神,我要怎么做呢?
(3)

可能解决方法:

(1)使用服务方式运行
         关闭WIN7 UAC
(2)DuplicateToken,SetTokenInformation,把token的sessionid设置为WTSGetActiveConsoleSessionId,再使用CreateProcessAsUser创建进程

(3)XP下面服务session跟第一个用户在同一个,Win7中服务有自己独立的session 0,用户session从1开始

使用WinObj工具我们可以看到XP下只有会话0,而Win7下有两个会话0、1:

 

再具体一点,我们通过任务栏管理器,我们来看一下各进程运行的会话情况:

(使用任务栏管理器时先把会话ID勾起来:查看->选择列)

从下图可以看出winlogon.exe在XP下是运行在会话0中,且所有的进程都是在0中;(除非是用RDP登录的才是新的会话)

而在Win7下winlogon.exe却运行在会话1中。

总结:现在终于明白为什么在XP下可以模拟的组合键,在Win7下却没作用。

            其实整个代码没有错,错在PostMessage消息的进程运行在会话0,而接收解锁序列ATL+CTRL+DEL的进程winlogon.exe运行在会话1。

            而窗口消息是不能在不同的会话间传递的。

 

关于win7不同session之间的进程通信

WIN7下服务程序与一般应用程序位于不用的会话层,以下那几种方式能实现他们直接的通信?
1.窗口消息(COPYDATA)
2.管道
3.SOCKET
4.内存映射
5.剪贴板

===========================================================================================================

以上方法中2、3、4是可行的。

 

在WIN7中虽然把发送窗口消息放到了winlogon.exe里,但还是没有效果,这是因为Win7下的Winlogon没有SAS窗口(参考看雪网文章《http://bbs.pediy.com/showthread.php?p=1122220》),

后来经网友介绍去查看TightVNC服务端源码,找到了实现方法:

参考文章《VNC源码研究(十)XP、Win7实现模拟发送ATL+CTRL+DEL
 

3.还有一种方法

Dos下键盘的完全控制 ------- 一系列的BIOS级别的键盘控制函数!
http://dev.csdn.net/develop/article/7/7181.shtm
我没有试验,不知道可否,哪位大哥试验后告诉我一声

在此再次感谢黄鑫大哥!!

10-02 22:18