Win7 禁止Ctrl+Alt+Del、Win+L等任意系统热键

来源:互联网 发布:淘宝达人直播申请入口 编辑:程序博客网 时间:2024/06/07 00:41

由于想做个屏幕锁程序,因此想研究了下Win7的Ctrl+Alt+Del,我对win7的安全机制一点都不懂,希望有不对的地方来大家多多指点

首先说下xp下的快捷键,xp下的快捷键是通过CreateWindowEx函数创建标题为"SAS Window"的窗口。
而Ctrl+Alt+Del、Ctrl+Shift+Esc快捷键以热键的方式注册到SAS Window上,因此注入到Winlogon.exe进程调用UnregisterHotKey就可以取消快捷键,但取消后无法恢复

那win7下的是怎样的呢?起码在Winlogon.exe的输入表没看到CreateWindowEx,另外我通过注入Winlogon.exe进程,枚举窗口,一个窗口都枚举不了,这说明在安全桌面一个窗口都没有,那Winlogon.exe到底是怎样响应Ctrl+Alt+Del的呢?



想法一
我以前有一个想法,就是Hook SwitchDesktop来禁止Winlogon.exe切换到安全桌面,这样Ctrl+Alt+Del就自然失效了,但这样还是有一些问题,看下面的这段Winlogon.exe切换桌面的代码,发现如果SwitchDesktop调用失败后并不会立马返回,而是重复调用SwitchDesktop,直到SwitchDesktop调用成功
代码:
DWORD __stdcall sub_100212B(HDESK hDesktop, int a2, int a3){  unsigned int v3; // ebx@1  DWORD i; // edi@1  DWORD v5; // esi@2  int v6; // eax@3  v3 = 0;  for ( i = 0; ; Sleep(i) )  {    v5 = 0;    v6 = a3 ? SwitchDesktopWithFade(hDesktop, a3) : SwitchDesktop(hDesktop);    if ( v6 )      break;    v5 = GetLastError();    if ( off_103C144 != &off_103C144 )    {      if ( *((_BYTE *)off_103C144 + 28) & 4 )      {        if ( *((_BYTE *)off_103C144 + 25) >= 2u )          sub_1002A84(*((_DWORD *)off_103C144 + 4), *((_DWORD *)off_103C144 + 5), 11, dword_1010308, v5, a3);      }    }    if ( v3 >= 0xA )    {      if ( !a2 )        return v5;    }    else    {      ++v3;      i += 100;    }  }  return v5;}


想法二
另外一个想法是直接挂起Winlogon.exe进程,由于Winlogon.exe只负责登录和注销等工作,因此挂起它也没什么,但还是上面的问题,如果在挂起Winlogon.exe进程期间,按下了Ctrl+Alt+Del,等我们恢复掉挂起的Winlogon.exe进程,Ctrl+Alt+Del还是会得到响应



想法三
难道禁止Ctrl+Alt+Del真的不可能吗?这是我对Ctrl+Alt+Del的一点分析流程,希望能对大家有帮助

众所周知Ctrl+Shift+Esc是打开任务管理器的快捷键,因此我打算从任务管理器入手,由于我虚拟机装不了win7 32位,只能拿我的真实机win7 64位来做实验,相信win7 32和64区别应该不大

用IDA打开winlogon.exe后,我们打开字符串窗口,点击SoftwareSASGeneration往上查看,
俨然看到几个字符串"osk.exe -s","DisableChangePassword","DisableSwitchUserOption","DisableTaskMgr","taskmgr.exe /%lu "。

双击对"taskmgr.exe /%lu "的引用,来到下面这段代码,很明显这是打开任务管理器,我最在意的是谁调用的这段代码,可惜IDA没显示谁调用了函数,但是有数据引用。后来通过WinDbg才知道这个函数名字叫WLGeneric_TaskManager_Enter
代码:
int __stdcall sub_102916D(int a1){  void *v1; // esi@1  int v3; // [sp+10h] [bp-B0h]@5  char Dst; // [sp+14h] [bp-ACh]@5  int v5; // [sp+18h] [bp-A8h]@18  int v6; // [sp+3Ch] [bp-84h]@18  __int16 v7; // [sp+40h] [bp-80h]@18  void *v8; // [sp+54h] [bp-6Ch]@21  HANDLE hObject; // [sp+58h] [bp-68h]@22  int v10; // [sp+64h] [bp-5Ch]@5  wchar_t *v11; // [sp+68h] [bp-58h]@18  int v12; // [sp+6Ch] [bp-54h]@9  wchar_t Dest; // [sp+70h] [bp-50h]@19  CPPEH_RECORD ms_exc; // [sp+A8h] [bp-18h]@5  v1 = off_103C144;  if ( off_103C144 != &off_103C144 )  {    if ( *((_DWORD *)off_103C144 + 7) & 0x100 )    {      if ( *((_BYTE *)off_103C144 + 25) >= 4u )      {        sub_1001838(*((_DWORD *)off_103C144 + 4), *((_DWORD *)off_103C144 + 5), 160, dword_1001F40);        v1 = off_103C144;      }    }  }  v3 = 0;  memset(&Dst, 0, 0x40u);  v10 = *(_DWORD *)(a1 + 4);  ms_exc.disabled = 0;  if ( v1 != &off_103C144 )  {    if ( *((_BYTE *)v1 + 28) & 1 )    {      if ( *((_BYTE *)v1 + 25) >= 5u )        sub_1001F55(*((_DWORD *)v1 + 4), *((_DWORD *)v1 + 5), 161, dword_1001F40, *(_DWORD *)(a1 + 24));    }  }  sub_1004BC9(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", L"DisableTaskMgr", 0, &v12);  sub_1004BC9(L"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", L"DisableTaskMgr", v12, &v12);  if ( v12 )  {    if ( off_103C144 != &off_103C144 )    {      if ( *((_BYTE *)off_103C144 + 28) & 1 )      {        if ( *((_BYTE *)off_103C144 + 25) >= 4u )          sub_1001838(*((_DWORD *)off_103C144 + 4), *((_DWORD *)off_103C144 + 5), 162, dword_1001F40);      }    }  }  else  {    if ( off_103C144 != &off_103C144 )    {      if ( *((_BYTE *)off_103C144 + 28) & 1 )      {        if ( *((_BYTE *)off_103C144 + 25) >= 5u )          sub_1001838(*((_DWORD *)off_103C144 + 4), *((_DWORD *)off_103C144 + 5), 163, dword_1001F40);      }    }    v3 = 68;    v6 = 1;    v7 = 5;    v5 = 0;    v11 = 0;    if ( *(_DWORD *)(a1 + 24) )    {      if ( sub_1004D43(&Dest, 26, L"taskmgr.exe /%lu ", *(_DWORD *)(a1 + 24)) >= 0 )        v11 = &Dest;    }    if ( !sub_1008379(L"taskmgr.exe", v11, 0, &v3, &v8, 0) )    {      CloseHandle(hObject);      CloseHandle(v8);    }  }  ms_exc.disabled = -2;  sub_1029343();  return sub_1001D07(0, 0);}
什么都别说了,用64位WinDbg附加winlogon.exe进程,在WLGeneric_TaskManager_Enter函数下断点,按下Ctrl+Alt+Del,程序停在WLGeneric_TaskManager_Enter,继续往上返回,我们看到最终的调用来自StateMachineRun

说起StateMachineRun函数,我们查看winlogon.exe的调用堆栈,可以看到winlogon.exe从WinMain执行,然后进入StateMachineRun,StateMachineRun内部会调用SignalManagerWaitForSignal循环等待系统快捷键的来临
代码:
winlogon!StateMachineRun+0x404winlogon!WinMain+0x13a3winlogon!I_WMsgkSendMessage+0x252kernel32!BaseThreadInitThunk+0xdntdll!RtlUserThreadStart+0x1d
在SignalManagerWaitForSignal下一行下断点,可以看到一旦Win+L,Win+U,Ctrl+Alt+Del任何一个快捷键按下都会断下来
按下Ctrl+Shift+Esc,我们往下跟踪,我们会发现winlogon.exe会调用WLGeneric_TaskManager_Enter例程
按下Win+U,我们可以看到,Winlogon.exe调用了WLGeneric_AccesNotifyAsUser_Enter例程
Win+L和Ctrl+Alt+Del有点特殊,下SwitchDesktop断点

查看Win+L的堆栈,Win+L的例程应该是WLGeneric_InitiateLock_Execute
代码:
USER32!SwitchDesktopwinlogon!ResilientSwitchDesktopWithFade+0x32winlogon!CSession::SwitchDesktop+0x2a2winlogon!WlAccessibilitySwitchDesktop+0x20winlogon!WLGeneric_InitiateLock_Execute+0xffwinlogon!StateMachineWorkerCallback+0x7fntdll!TppWorkpExecuteCallback+0xa4ntdll!TppWorkerThread+0x5ffkernel32!BaseThreadInitThunk+0xdntdll!RtlUserThreadStart+0x1d
Ctrl+Alt+Del的堆栈是,Ctrl+Alt+Del例程应该是WLGeneric_CAD_Execute
代码:
USER32!SwitchDesktopwinlogon!ResilientSwitchDesktopWithFade+0x32winlogon!CSession::SwitchDesktop+0x2a2winlogon!WlAccessibilitySwitchDesktop+0x20winlogon!HandleSecurityOptions+0x51winlogon!WLGeneric_CAD_Execute+0x76winlogon!StateMachineWorkerCallback+0x7fntdll!TppWorkpExecuteCallback+0xa4ntdll!TppWorkerThread+0x5ffkernel32!BaseThreadInitThunk+0xdntdll!RtlUserThreadStart+0x1d
我们先看一下SignalManagerWaitForSignal函数,主要看红色标注地方,修改我说的那个判断标记的地方,别让程序出SignalManagerWaitForSignal,让它一直用WaitForSingleObject函数处等待。如果按我说的做了,然后快捷键都将不会响应,而且是可恢复的,但还是有上面几个想法的问题
代码:
int __stdcall sub_1001C19(int a1, unsigned int a2, int a3, int a4, int a5, int a6){  void *v6; // eax@2  unsigned int v7; // eax@6  int v8; // ecx@6  int result; // eax@10  int v10; // esi@16  char v11; // al@22  signed int v12; // [sp+Ch] [bp-4h]@1  *(_DWORD *)a5 = -1;  v12 = 0;//标记,设置为FALSE  *(_DWORD *)a6 = 0;  *(_DWORD *)(a6 + 4) = 0;  *(_DWORD *)(a6 + 8) = 0;  *(_DWORD *)(a6 + 12) = 0;LABEL_2:  v6 = off_103C144;LABEL_3:  if ( v6 != &off_103C144 )  {    if ( *((_BYTE *)v6 + 28) & 2 )    {      if ( *((_BYTE *)v6 + 25) >= 5u )        sub_1001838(*((_DWORD *)v6 + 4), *((_DWORD *)v6 + 5), 25, dword_1025A24);    }  }  while ( 1 )  {    RtlEnterCriticalSection(a1);    v7 = 0;    if ( a2 )    {      v8 = a3;      while ( 1 )      {        *(_DWORD *)a5 = v7;        if ( *(_DWORD *)(*(_DWORD *)(a1 + 32) + 4 * *(_DWORD *)v8) )\\这里有个ja跳转,nop掉,函数就不会出去          break;        ++v7;        v8 += 12;        if ( v7 >= a2 )          goto LABEL_10;      }      v10 = *(_DWORD *)(a1 + 36) + 16 * *(_DWORD *)v8;      v8 = 4 * *(_DWORD *)v8;      *(_DWORD *)a6 = *(_DWORD *)v10;      v10 += 4;      *(_DWORD *)(a6 + 4) = *(_DWORD *)v10;      v10 += 4;      *(_DWORD *)(a6 + 8) = *(_DWORD *)v10;      v12 = 1;  //标记,设置TRUE           *(_DWORD *)(a6 + 12) = *(_DWORD *)(v10 + 4);      if ( off_103C144 != &off_103C144 )      {        if ( *((_BYTE *)off_103C144 + 28) & 2 )        {          if ( *((_BYTE *)off_103C144 + 25) >= 5u )            sub_1001F55(              *((_DWORD *)off_103C144 + 4),              *((_DWORD *)off_103C144 + 5),              26,              dword_1025A24,              *(_DWORD *)(*(_DWORD *)(a1 + 32) + v8));        }      }    }LABEL_10:    result = RtlLeaveCriticalSection(v8, a1);    if ( v12 )//这里判断标记,修改这里,把这里的跳转nop掉,函数照样也出不去      return result;    if ( WaitForSingleObject(*(HANDLE *)(a1 + 24), 0xFFFFFFFFu) )    {      v11 = GetLastError();      if ( off_103C144 != &off_103C144 )      {        if ( *((_BYTE *)off_103C144 + 28) & 2 )        {          if ( *((_BYTE *)off_103C144 + 25) >= 2u )            sub_1001F55(*((_DWORD *)off_103C144 + 4), *((_DWORD *)off_103C144 + 5), 27, dword_1025A24, v11);        }      }      Sleep(0x3E8u);    }    v6 = off_103C144;    if ( off_103C144 != &off_103C144 )    {      if ( *((_BYTE *)off_103C144 + 28) & 2 && *((_BYTE *)off_103C144 + 25) >= 5u )      {        sub_1001838(*((_DWORD *)off_103C144 + 4), *((_DWORD *)off_103C144 + 5), 28, dword_1025A24);        goto LABEL_2;      }      goto LABEL_3;    }  }}


想法四,最终完美实现一个字节更改并且可恢复
我们想下winlogon.exe是怎样判断是哪个快捷键的
代码:
switch(快捷键ID){case Ctrl+Alt+Del://我们修改改ID,让程序无法执行该方法{  打开桌面安全选项();}break;case Win+L://我们修改改ID,让程序无法执行该方法{  锁定桌面();}break;case Ctrl+Shift+Esc://我们修改改ID,让程序无法执行该方法{  打开任务管理器();}break;case Win+P://我们修改改ID,让程序无法执行该方法{  切换窗口();}break;default://不做任何操作,让winlogon.exe最终走到这里{}
我的思路就是这样, 在xp可以通过窗口消息处理过程很容易找到上述代码,但Win7怎么找呢?

现在总结下Winlogon.exe是怎样处理系统快捷键的,Winlogon.exe从WinMain进入到StateMachineRun,StateMachineRun调用SignalManagerWaitForSignal函数循环等待系统快捷键。

SignalManagerWaitForSignal函数应该是微软自己使用的一种同步机制,它内部的实现就是调用WaitForSingleObject函数等待某个事件,那是谁把该事件设置了信号?

我们下断点SetEvent,按下Ctrl+Alt+Del,程序被断下来了,这是查看堆栈,因为太长了,我直接发截图吧
可以看到SignalManagerSetSignal应该就是设置信号的,它内部调用了SetEvent。
我们可以得出结论,Winlogon.exe内部通过RPC来接收系统快捷键到来的信息,然后设置信号让主线程恢复运行,处理快捷键

我们还发现其中WMsgKMessageHandler调用了WlStateMachineSetSignal,听名字是处理消息的。我们尝试去跟踪WMsgKMessageHandler函数,下WMsgKMessageHandler函数断点,重新按下Ctrl+Alt+Del。

我发现了一个有趣的现象,跟踪程序到了这里,我们可以看到这里比较EDX,如果EDX不等于4的就继续跳转比较,而Win+L到这里的EDX是不同的,我们可以肯定这里EDX就是快捷键的ID,如果快捷键的ID和某个ID相等,程序就会跳到相应的位置执行
直接发证据,我的Win7 64位是这样的
代码:
.text:00000001000170B0                 cmp     ebx, 4.text:00000001000170B3                 jnz     short loc_10001710B;不等于4跳转省略。。。.text:000000010001710B                 cmp     ebx, 5.text:000000010001710E                 jnz     short loc_10001713D;不等于5跳转省略。。。.text:000000010001713D                 cmp     ebx, 6.text:0000000100017140                 jnz     short loc_10001717D;不等于6跳转省略。。。.text:000000010001717D                 cmp     ebx, 7.text:0000000100017180                 jnz     short loc_1000171B0;不等于7跳转省略。。。.text:00000001000171B0                 cmp     ebx, 8.text:00000001000171B3                 jnz     short loc_1000171E3;不等于8跳转省略。。。text:00000001000171E3                 cmp     ebx, 9.text:00000001000171E6                 jnz     short loc_100017219;不等于9跳转省略。。。.text:0000000100017219                 test    ebx, ebx.text:000000010001721B                 jnz     loc_1000173CA;不等于0跳转省略。。。
可以看出一共有7个快捷键,其中Ctrl+Alt+Del的ID位0,Win+L的ID为5,文章在这里要说声结束了,至于怎么屏蔽。比喻我们要屏蔽Win+L,可以把和000000010001710B处的"cmp     ebx, 5"改成"cmp     ebx, aa",这样程序永远也不能跳到本应该属於它的处理例程,该方法应该不会有任何问题,我反正测试通过

向32位Win7的朋友左旭东要了个他的Winlogon.exe逆向了,再次表示感谢他,我在Win7 32照样发现了上述代码处,32位Win7的朋友也可以仿照
代码:
.text:0101621A                 cmp     eax, 4.text:0101621D                 jz      loc_101B779.text:01016223                 cmp     eax, 5.text:01016226                 jz      loc_101B7BA.text:0101622C                 cmp     eax, 6.text:0101622F                 jz      loc_101B7E6.text:01016235                 cmp     eax, 7.text:01016238                 jz      loc_101B810.text:0101623E                 cmp     eax, 8.text:01016241                 jz      loc_101B83A.text:01016247                 cmp     eax, 9.text:0101624A                 jz      loc_101B864.text:01016250                 test    eax, eax.text:01016252                 jnz     short loc_1016296
0 0