CTaskKeyMgr class in the
TrapKeys project is designed to demonstrate the functions mentioned in the title. It is a slight modification of the class
CTaskKeyMgr which is part of the sample code of the MSDN article, TrapKeys. Two functions are added to show/hide applications in the task list and to enable/disable blocking of the Ctrl+Alt+Del key combination. It is designed for Windows 2000, but I found that it works on XP SP2 as well. For more information about blocking Ctrl+Alt+Del or hiding an application in the Task List on other Windows platforms, see Lock Windows Desktop by afeijao.
This version is still under development, in particular for multiple instances, debugging issues, and memory leaks.
Information in this article mainly comes from the discussion "How to Trap Ctrl+Alt+Del Key Combination in Windows NT/2000/XP (without using GINA and keyboard driver technology)" in the CSDN forum (in Simplified Chinese).
I was working on an educational software that broadcasts screen actions from a teacher to a student, and some of my clients asked for the following features frequently:
"Is there any way to prevent the unexpected closing of your application by pressing the Ctrl+Alt+Del key combination and then end the program in the Task List? I don't want my students to close the teaching software and run games."
Note: Who has the right to kill the programs is controversial, and Raymond Chen has an excellent article on this topic (see here).
I posted this question to the forum on CSDN, and got tens of replies soon. Here are some ideas from the replies:
- Trap the Ctrl+Alt+Del key combination.
- Subclassing the Secure Attention Sequence (SAS) window and handling the Ctrl+Alt+Del hotkey combination in a subclassed
- Hooking the keyboard driver (I must admit that I know nothing about the Windows DDK, so I gave up this approach right at the beginning).
- Fooling the operating system into thinking the screen saver was running (only works on Win9x).
- Hooking GINA dynamically, or replacing the GINA DLLs (screen flashed when the desktop is switching).
- Hide the application in the task list.
- Run as a service by calling
RegisterServiceProcess (only works on Win9x).
NtQuerySystemInformatoin (only works on Windows NT/2000/XP).
- Inject the exe into a process (not good for a large exe).
- Hook the
TerminateProcess (just an idea, anybody have a try?).
And this article is my approach after summarizing the discussion.
The Approach I Have Chosen
Note: I got some complaints about the lengthy code in the original Chinese article, so I cut them in this translation. The readers can still read the code in the Chinese article without downloading the source project.
The SAS window shows the default login dialog when it gets a
WM_HOTKEY message with parameters indicating
VK_DELETE and both the Ctrl and Alt key pressed down. This hotkey is registered by winlogon.exe during the system startup, so you have no way to register it yourself. However, you can subclass the SAS window and handle it before the SAS window dispatches it.
In order to subclass a window procedure in another process, you need to first acquire the necessary privileges (
SE_DEBUG_NAME), and then inject some cute code into the process, and finally start a remote thread in it. Because the addresses of Windows API functions vary from process to process, you can not call virtually any API and thus can do almost nothing but simply load a DLL. The system will make the necessary function address adjustments, and the DLL will do the actual subclassing of the SAS window, which is on the WinLogon desktop, not the application desktop. (See Reference 1.)
The core part of this program is the function to be injected into the WinLogon process. It must be neat enough to avoid accessing anything in the current process except something surely existing in the target process, such as kernel Windows APIs, i.e.
LoadLibrary. If the function is not optimized and nothing complicated is silently added by the compiler, you can get the "length" of your function correctly by calculating the offset to the next function. This enables "copying" a function to another process, and may be the reason why the debug version always fails.
If Terminal service is installed, and multiple users logged in, the program needs to decide which WinLogon process should be injected. This can be done by enumerating processes and looking for the current session ID and the executable path. This step can be safely removed if the program will not run under Windows 2000 Server or Windows XP with fast user switch.
Hide the application from being listed is a little easier: simply hook the somewhat reluctantly documented
NtQuerySystemInformation API, and skip the desired processes when the system is looking up processes.
Using the code
Almost the same as
TrapKeys. The following line will disable the Ctrl-Alt-Del key combo and hide the application in the task list:
CTaskKeyMgr::Disable(CTaskKeyMgr::TASKLIST| CTaskKeyMgr::CTRLALTDEL, TRUE);
Save all of your documents before debugging this code. If winlogon.exe crashes, and you choose to terminate winlogon.exe, your Windows will shutdown immediately. Your system will be revived after a reboot.
Please note that this class is using undocumented features of Windows. It may not work on future versions of Windows.
Any suggestions on how to improve it would be greatly appreciated.
- 17 Apr 2006 - added remote execute detection, and removed the Windows 2000 check on start up.
- 18 Sep 2005 - revised a bit.
- 19 Apr 2003 - document translated from Chinese.
- 11 Nov 2002 - document released on CSDN (Simplified Chinese).
- 8 Nov 2002
- Found debug problem (program always crashes when debugging).
- Found network problem (can not access password protected network resource).
- 30 Oct 2002 - second implementation using API hook and DLL injection.
- 22 Oct 2002 - initial implementation using API hook and detours.
- 21 Oct 2002 - first post on CSDN (Simplified Chinese).
WinLogon will always fail to load the debug version of the remote DLL. (Debug and Release modes in Visual C++ are very different...)
WinLogon will fail to load the injected DLL if it is located on a remote resource, because WinLogon is owned by the SYSTEM user, and the application is usually running under a different user context.
Don't use /Gs (Control Stack Checking Calls) switch for Link.exe when compiling the inject function. The switch inserts a stack probe in function bodies, and so inserts references to the current process. A stack probe is a sequence of code that the compiler inserts into every function call.
This code is provided "as is" with no expressed or implied warranty.
You may use this code in a commercial product with or without acknowledgement. However, you may not sell this code or any modification of this code, this includes commercial libraries and anything else for profit.
- MSDN. CtrlAltDel hotkey registration information.
- Programming Applications for Microsoft Windows (Jeffrey Richter): API hooking information.
- TrapKeys: MSDN Home > MSDN Magazine > September 2002 > C++ Q&A: Typename, Disabling Keys in Windows XP with TrapKeys.
- WTSAPI: MSDN Home > MSDN Magazine > June 2002 > Windows XP: Escape from DLL Hell with Custom Debugging and Utilities: Windows Terminal Service topics.
- Lock Windows Desktop by afeijao.
- Extending Task Manager with DLL Injection by rocky_pulley.
CSDN Members (listed with ID (nickname)):
- slwqw / BAB_FANS (a hue and cry of The four excellent head constables).
- nevergrief (lonely knight).
- jennyvenus (his nickname is in Chinese and is too complex for my poor English).
- kingzai (studying C#).
- microran2000 (no nickname).