How to: Pismostatic Disable / Enable Ctrl-Alt-Delete in Windows2000
Information about this article is applied to:
Microsoft Windows 2000
The update information of this article is located at http://blog.joycode.com/jiangsheng/archive/2004/07/20/27909.aspx Click here to download the code of this article.
summary
This article is discussed from the 9CBS Forum VC / MFC version
How to disable Ctrl Alt DELETE in NT / 2000 (can not be driven with Gina, keyboard) (this post is archived, you can
Http://search.9cbs.net Search this post)
The processing of the Ctrl-Alt-delete key combination in Windows2000 is as follows:
When Winlogon is initialized, the Ctrl Alt Del Secure Attertion Sequence (SAS) hot button is registered in the system and three desktops are created in the Winsta0 Windows system. The SAS hotkey registration makes Winlogon a process that handles Ctrl Alt Del, so that no other application can handle this hotkey. In Windows NT / Windows 2000 / Windows XP, WinSTA0 is the name of the Windows system object representing the physical screen, the mouse, and the keyboard. Winlogon creates a SAS window in the Winsta0 Windows system (window title is "SAS Window") and the following three desktops.
Winlogon Desktop Application Desktop Screen Protection Desktop When the user presses the ctrl-alt-delete key button, the SAS window on the Winlogon desktop receives its registered system hot key message (WM_HOTKEY) SAS Window window handling this message call graphical Identification and Authentication (GINA) related functions in dynamic connection libraries
To interrupt the processing of the ctrl-alt-delete key button, you can have the following way
Ctrl-alt-delete (http://dev.9cbs.net/develop/article/12/12173.shtm) replace Winlogon replacement Gina (http://www.9cbs.com.cn/program/) from the keyboard drive layer. 296.htm) Hook Winlogon's window process (requires current login user with adjustment rights) Hook Gina's function WLXLoggedonsas, then return WLX_SAS_Action_NONE (not studied)
More information
Given that the system's update may cause our replacement system files and other system files that are not compatible (famous DLL hell), it is not recommended to replace Winlogon.exe and Gina. Here we discuss the way the Window process of the SAS window on Hook Winlogon.
Because the SAS window is different from our program memory address space, you have to write a dynamic connection library, load it into the memory space of the SAS window. Below is the source code of the dynamic connection library.
/ / -------------------------------------------------------------------------------------------- --------------------------- // author: Tan Wei Wu // online nickname: BCB_FANS (the Four of fatwa) (this Accounts for 9CBS and www.driverdevelop.com) // E-mail: SLWQW@163.com// - Date: 2002-10-20 ////> Mask Ctrl Alt DEL Complete in 2000. (In the Windows 2000 Professional SP3 // Chinese version of the test pass) // Principle: Using Remote Thread Injection Technology, load a DLL to the Winlogon process, then intercept the window // port process of the SAS window, take over the WM_HOTKEY message to achieve the shield Ctrl Alt Del. // Development Language: Borland C Builder 5.0 Patch2 // Technical Comparison: About how to block Ctrl Alt DEL combination in 2000, a commonly mentioned solution is to use the Gina written by yourself. Replace Msgina.dll and then return to // WLX_SAS_Action_none directly over WLXLoggedonsas. Hey, saying that this is not really shielding this combination button, just // When returning to WLX_SAS_Action_NONE, the Winlogon process automatically switches from the "Winlogon" desktop // back to the original "default" desktop, not a security dialog So it looks blocked:), // Use that method clearly see the desktop flicker! But when using this article, you won't see any // Which flicker! // Acknowledgment: Icube and LU0 on www.driverdevelop.com.
// Copyright: reproduced please specify the author:) // ------------------------------------ --------------------------------------- # include "stdafx.h" #include
Desktop Window Bool Callback EnumwindowsProc (HWnd Hwnd, LParam Lparam) {Char Classbuf [128]; getWindowText (hwnd, classbuf, sizeof (classbuf)); // I wrote a system service, then query "Winlogon" desktop The window is discovered, and there is a window "SAS Window" on the desktop. String classname (classbuf); if ("SAS WINDOW")! = -1) {hsaswnd = hwnd; return false;} Return true;} // ------------- -------------------------------------------------- ---------- // SAS window window Process LRESULT CALLBACK SASWINDOWPROC (HWND HWND, UINT UMSG, WPARAM WPARAM, LPARAM LPARAM) {// Mask Ctrl Alt Del IF (UMSG == WM_HOTKEY ) {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); // Press CTRL Alt DEL Complete IF (IsctrLdown && Isaltdown && WKEY == VK_DELETE) {Return 1;} // Press CTRL Shift ESC Combination Key, this The key combination will display the task manager, which can be shielded as needed. Else if (isctrldown && isshiftdown && wkey == vk_escape) {// do nothing}} Return CallWindowProc (WndProc) Foldproc, HWND, UMSG, WPARAM, LPARAM;} // ----------- -------------------------------------------------- ------------- This, if Winlogon loads this dynamic connection library, then the window process of the SAS window is replaced. If Winlogon uninstalls this dynamic connection library, the Window process of the SAS window is restored. To make Winlogon load our dynamic connection library, first find the Winlogon process, then assign space in the process to store our code, and perform our code by creating a remote line. Below is the code of the hook section
/ / -------------------------------------------------------------------------------------------- --------------------------- // author: Tan Wei Wu, jiangsheng // online nickname: BCB_FANS (the Four of fatwa) (This account is 9CBS and www.driverdevelop.com) jiangsheng (this is 9CBS account) // e-mail: SLWQW@163.com/ Date: 2002-10-20 // 2002-11-5 jingsheng modification / / Features: Shield Ctrl Alt Del Combination in 2000. (In the Windows 2000 Professional SP3 // Chinese version of the test pass) // Principle: Using Remote Thread Injection Technology, load a DLL to the Winlogon process, then intercept the window // port process of the SAS window, take over the WM_HOTKEY message to achieve the shield Ctrl Alt Del. // Development Language: Borland C Builder 5.0 Patch2, Visual C 6.0 SP5 // Technical Comparison: About how to block Ctrl Alt Del combination keys below 2000, a solution that is often mentioned is // The Gina written by yourself replaces Msgina.dll and then returns // WLX_SAS_Action_None directly in WLXLoggedonsas. Hey, saying that this is not really shielding this combination button, just // When returning to WLX_SAS_Action_NONE, the Winlogon process automatically switches from the "Winlogon" desktop // back to the original "default" desktop, not a security dialog So it looks blocked:), // Use that method clearly see the desktop flicker! But when using this article, you won't see any // Which flicker! // Acknowledgment: Icube and LU0 on www.driverdevelop.com.
// Copyright: reproduced please specify the author:) // ------------------------------------ --------------------------------------- # include "stdafx.h" #include
CString __fastcall SysErrorMessage (DWORD dwLastError) {CString strRet (_T ( "Unknown error")); HMODULE hModule = NULL; // default to system source LPSTR MessageBuffer; DWORD dwBufferLength; DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM; // // If dwLastError is in the network range, // load the message source // if (dwLastError> = NERR_BASE && dwLastError <= MAX_NERR) {hModule = LoadLibraryEx (TEXT ( "netmsg.dll"), NULL, LOAD_LIBRARY_AS_DATAFILE);. if ( hModule = NULL) dwFormatFlags | = FORMAT_MESSAGE_FROM_HMODULE;!} // // Call FormatMessage () to allow for message // text to be acquired from the system // or from the supplied module handle // if (dwBufferLength = FormatMessageA (dwFormatFlags. , Hmodule, // module to get message from (null == system) DWLASTERROR, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // DE fault language (LPSTR) & MessageBuffer, 0, NULL)) {// // Output message string on stderr // strRet = CString (MessageBuffer, dwBufferLength);. // // Free the buffer allocated by the system // LocalFree (. Messagebuffer;} //// if We loaded a message source, unload it. // if (hmodule! = Null) freeElibrary (hmodule); return strret;} // end replaced by jiangsheng 2002-11-5 // -------------------------------------------------- ------------------------ # neydef unicodelpcstr = "loadLibraryw"; lpcstr getModulehandlefuncstr = "
GetModuleHandleW "; # elseLPCSTR LoadLibraryFuncStr =" LoadLibraryA "; LPCSTR GetModuleHandleFuncStr =" GetModuleHandleA "; # endifLPCSTR FreeLibraryFuncStr =" FreeLibrary "; LPCSTR GetProcAddressFuncStr =" GetProcAddress "; LPCSTR GetLastErrorFuncStr =" GetLastError "; // -------- -------------------------------------------------- ----------------- // Removed by jiangsheng 2002-11-5 // const char * const remotedllname = "remotedll.dll"; // end remoded by jiangsheng 2002-11 -5LPCTSTR szRemoteProcessName = "Winlogon.exe"; typedef HINSTANCE (WINAPI * PLOADLIBRARY) (LPCTSTR); typedef BOOL (WINAPI * PFREELIBRARY) (HINSTANCE); typedef HMODULE (WINAPI * PGETMODULEHANDLE) (LPCTSTR); typedef PVOID (WINAPI * PGETPROCADDRESS) (HINSTANCE, LPCSTR); typedef DWORD (WINAPI * PGETLASTERROR) (VOID); BOOL __fastcall enablePrivilege (LPCTSTR lpszPrivilegeName, BOOL bEnable); DWORD __fastcall GetPIDFromName (LPCTSTR lpszProcName); // ------------ -------------------------------------------------- ------------- TypedEf struct {ploadlibrary PfnLoadLibr ary; PGETLASTERROR pfnGetLastError; TCHAR szDllName [1024]; DWORD dwReturnValue;} INJECTLIBINFO; typedef struct {PFREELIBRARY pfnFreeLibrary; PGETMODULEHANDLE pfnGetModuleHandle; PGETLASTERROR pfnGetLastError; DWORD dwReturnValue; TCHAR szDllName [1024];} DEINJECTLIBINFO; // ------- -------------------------------------------------- ------------------ // Remote thread, used to load DLLSTATIC DWORD WINAPI Threadfuncattach (INJECTLIBINFO * PINFO) {hinstance hdll = null; pinfo-> dwreturnvalue = 0; HDLL = (Hinstance) PINFO-> PfnLoadLibrary (Pinfo-> szdllname); if (hdll == null) Pinfo-> dwreturnValue = Pinfo-> PfNgetLastError ();
Return ((DWORD) HDLL);} // --------------------------------------- ---------------------------------- // Place in the size of Threadfuncattach, Static Void AfTERTHREADFUNCATCH (Void) {} // ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------- // Remote thread, used to uninstall DllStatic DWord WinApi ThreadFuncdetach (DeinjectLibInfo * Pinfo) {Hinstance HDLL = NULL; BOOL BRESULT = FALSE; BOOL BHASFOUNDMODULE = false; pinfo-> dwreturnvalue = 0; // means success, if this value is not 0, it is an error code.
while ((hDll = pInfo-> pfnGetModuleHandle (pInfo-> szDllName)) = NULL!) {bHasFoundModule = TRUE; bResult = pInfo-> pfnFreeLibrary (hDll); if (bResult == FALSE) {pInfo-> dwReturnValue = pInfo- > pfNgetLastError (); Break;}} f (pinfo-> dwreturnvalue == 0 &&! bhasfoundmodule) {Pinfo-> dwreturnValue = Pinfo-> pfNgetLastError ();} return 1;} // -------------- -------------------------------------------------- ----------------- // Place the function, used to calculate the size static void atThreadFuncDetAd (void) {} // ----------- -------------------------------------------------- -------------- // permission to modify this process BOOL __fastcall enablePrivilege (LPCTSTR lpszPrivilegeName, BOOL bEnable) {HANDLE hToken; TOKEN_PRIVILEGES tp; LUID luid;! if (OpenProcessToken (GetCurrentProcess (), Token_adjust_privileges | token_query | token_read, & htokeen) Return False; if (! LookuppprivileGevalue (Null, LpszprivileGename, & Luid) Return True; Tp.privi legeCount = 1; tp.Privileges [0] .Luid = luid; tp.Privileges [0] .Attributes = (bEnable) SE_PRIVILEGE_ENABLED:? 0; AdjustTokenPrivileges (hToken, FALSE, & tp, NULL, NULL, NULL); CloseHandle (hToken ); GetLastError () == error_success);} // ----------------------------------- --------------------------------------- // Get the ID of the process ( The method used here Toolhelp functions, may also be used PSAPI) DWORD __fastcall GetPIDFromName (LPCTSTR lpszProcName) {HANDLE hSnapshot; PROCESSENTRY32 ProcStruct; DWORD dwProcessID = -1; // added by jiangsheng 2002-11-8 BOOL bIsTerminalServices = Is_Terminal_Services ();
if (bIsTerminalServices) {// copied from MSDN Magazine Windows XP Escape from DLL Hell with Custom Debugging and Instrumentation Tools and Utilities Code // get current session ID CWTSWrapper WTS; if (WTS.IsValid ()) {DWORD dwCurSessionID = -1 ; LPTSTR pSessionInfo = NULL; DWORD dwBytes; if (WTS.WTSQuerySessionInformation (WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSSessionId, (LPTSTR *) & pSessionInfo, & dwBytes)) {dwCurSessionID = * ((DWORD *) pSessionInfo); // enumerate processes PWTS_PROCESS_INFO pProcessInfo = NULL ; DWORD ProcessCount = 0; BOOL bFound; if (WTS.WTSEnumerateProcesses (WTS_CURRENT_SERVER_HANDLE, 0, 1, & pProcessInfo, & ProcessCount)) {for (DWORD CurrentProcess = 0; CurrentProcess }}} Else {// end added by jiangsheng 2002-11-8 BOOL bResult; hSnapshot = CreateToolhelp32Snapshot ((DWORD) TH32CS_SNAPPROCESS, 0); ProcStruct.dwSize = sizeof (PROCESSENTRY32); bResult = Process32First (hSnapshot, & ProcStruct); while (bResult) {BOOL bFound; CString strCurExePath (ProcStruct.szExeFile); CString strRemoteProc (lpszProcName); strCurExePath.MakeLower (); strRemoteProc.MakeLower (); bFound = (! strCurExePath.Find (strRemoteProc) = -1); if ( bFound) {dwProcessID = ProcStruct.th32ProcessID; break;} bResult = Process32Next (hSnapshot, & ProcStruct);} CloseHandle (hSnapshot);} return dwProcessID;} // ---------------- -------------------------------------------------- --------- // Insert code // ----------------------------------- ---------------------------------------- // Injectfuncvoid __ fastcall InjectFunc () {HANDLE hRemoteProcess = NULL; DWORD dwRemoteProcess = NULL; DWORD dwThreadSize = 0; INJECTLIBINFO InjectLibInfo; PVOID pRemoteThread = NULL; PVOID pRemoteParam = NULL; DWORD dwWriten = 0; DWORD dwRet = 0; // to improve this process and permissions open the target process // current user must have debug permission enablePrivilege (SE_DEBUG_NAME, true); dwRemoteProcess = GetPIDFromName (szRemoteProcessName); if (dwRemoteProcess == (DWORD) -1) {MessageBox (NULL, _T ( "Failed to Query process ID. "), NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING; Return; HREMOTEPROCESS = OpenProcess (Process_Access); if (HREMOTEPROCESS == NULL) {MessageBox (NULL, _T ( "Failed to Open Process Err =.") SysErrorMessage (GetLastError ()), NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING); return;} // initialization parameters ZeroMemory (& InjectLibInfo, sizeof (INJECTLIBINFO )); InjectLibInfo.pfnLoadLibrary = (PLOADLIBRARY) GetProcAddress (GetModuleHandle ( "Kernel32.dll"), LoadLibraryFuncStr); InjectLibInfo.pfnGetLastError = (PGETLASTERROR) GetProcAddress (GetModuleHandle ( "Kernel32.dll"), GetLastErrorFuncStr); lstrcpyn (InjectLibInfo.szDllName , CTaskKeyMgr :: strRemoteDllName, CTaskKeyMgr :: strRemoteDllName.GetLength () 1); // allocate memory to the remote thread storing parameters pRemoteParam = VirtualAllocEx (hRemoteProcess, NULL, sizeof (INJECTLIBINFO), MEM_COMMIT, PAGE_READWRITE); if (pRemoteParam = = NULL) {MessageBox (NULL, _T ( "Failed to Allocate Memory at Remote Process for Param.Err =") SysErrorMessage (GetLastError ()), NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING); return;} dwRet = WriteProcessMemory (hRemote Process, pRemoteParam, (LPVOID) & InjectLibInfo, sizeof (INJECTLIBINFO), & dwWriten); if (dwRet == 0) {MessageBox (NULL, _T ( "Failed to Write Param to Remote Process.Err =") SysErrorMessage (GetLastError () ), NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING); return;} // copy threaded body dwThreadSize = (int) AfterThreadFuncAttach - (int) ThreadFuncAttach 1024 sizeof (INJECTLIBINFO); pRemoteThread = VirtualAllocEx (hRemoteProcess, NULL, dwThreadSize, MEM_COMMIT, Page_readwrite; if (premothetread == null) {MessageBox (null, _t (" Failed to Allocate Memory at Remote Process for Thread Code.Err = ") SysErrorMessage (GetLastError ()), NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING); return;} dwRet = WriteProcessMemory (hRemoteProcess, pRemoteThread, (LPVOID) ThreadFuncAttach, dwThreadSize, & dwWriten); if (dwRet == 0) {MessageBox (NULL, _T ( "Failed to Write Thread Code to Remote Process.Err =") SysErrorMessage (GetLastError ()), NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING); return; } // start the remote thread HANDLE hRemoteThread; hRemoteThread = CreateRemoteThread (hRemoteProcess, 0,0, (DWORD (__ stdcall *) (VOID *)) pRemoteThread, (INJECTLIBINFO *) pRemoteParam, 0, & dwWriten); :: WaitForSingleObject (hRemoteThread, INFINITE ); if (hRemoteThread == NULL) {MessageBox (NULL, _T ( "Failed to create unload thread.Err =") SysErrorMessage (GetLastError ()), NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING);} else {;} / / Read Unloading Return Value DWRET = ReadProcessMemory (HREMOTEPROCESS, Premote Param, (LPVOID) & InjectLibInfo, sizeof (INJECTLIBINFO), & dwWriten); if (dwRet == 0) {MessageBox (NULL, _T ( "Unable to read load return value.Err =") SysErrorMessage (GetLastError ()), NULL , MB_OK | MB_APPLMODAL | MB_ICONWARNING);} else {if (InjectLibInfo.dwReturnValue == 0) {;} else {MessageBox (NULL, _T ( "Failed to load library to Winlogon.Err =") SysErrorMessage (InjectLibInfo.dwReturnValue) , NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING;}} // Restore Permissions EnablePrivilege (SE_Debug_name, false); CloseHandle (HREMOTEPROCESS);} // ------------------------------------------ --------------------------------- // Uninstall thread // ----------- -------------------------------------------------- -------------- // DeinjectFuncvoid __fastcall DeinjectFunc () {HANDLE hRemoteProcess = NULL; DWORD dwRemoteProcess = 0; DWORD dwThreadSize = 0; DEINJECTLIBINFO DeinjectLibInfo; PVOID pRemoteThread = NULL; PVOID pRemoteParam = NULL; DWORD dwWriten = 0; DWORD Ret = 0; // open to improve this process and the destination process privileges enablePrivilege (SE_DEBUG_NAME, true); dwRemoteProcess = GetPIDFromName (szRemoteProcessName); if (dwRemoteProcess == (DWORD) -1) {MessageBox (NULL, _T ( "Failed to Query Process ID."), NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING); return;} hRemoteProcess = OpenProcess (PROCESS_ALL_ACCESS, false, dwRemoteProcess); if (hRemoteProcess == NULL) {MessageBox (NULL, _T ( " Failed to open process. Err = ") syserrorMesS, NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING); RETU rn;} // initialization parameters ZeroMemory (& DeinjectLibInfo, sizeof (DEINJECTLIBINFO)); DeinjectLibInfo.pfnFreeLibrary = (PFREELIBRARY) GetProcAddress (GetModuleHandle ( "Kernel32.dll"), FreeLibraryFuncStr); DeinjectLibInfo.pfnGetModuleHandle = (PGETMODULEHANDLE) GetProcAddress (GetModuleHandle ( " Kernel32.dll "), GetModuleHandleFuncStr); DeinjectLibInfo.pfnGetLastError = (PGETLASTERROR) GetProcAddress (GetModuleHandle (" Kernel32.dll "), GetLastErrorFuncStr); lstrcpyn (DeinjectLibInfo.szDllName, CTaskKeyMgr :: strRemoteDllName, CTaskKeyMgr :: strRemoteDllName.GetLength () 1); // Allocate memory in remote threads to store parameters premoteparam = VirtualAllocEx (hRemoteProcess, NULL, sizeof (DEINJECTLIBINFO), MEM_COMMIT, PAGE_READWRITE); if (pRemoteParam == NULL) {MessageBox (NULL, _T ( "Failed to Allocate Memory at Remote Process.Err =") SysErrorMessage (GetLastError ()) , NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING);} Ret = WriteProcessMemory (hRemoteProcess, pRemoteParam, (LPVOID) & DeinjectLibInfo, sizeof (DEINJECTLIBINFO), & dwWriten); if (Ret == 0) {MessageBox (NULL, _T ( "Failed to Write param to Remote Process.Err = ") SysErrorMessage (GetLastError ()), NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING); return;} // copy threaded body dwThreadSize = (int) AfterThreadFuncDetach - (int) ThreadFuncDetach 1024 sizeof ( DEINJECTLIBINFO); pRemoteThread = VirtualAllocEx (hRemoteProcess, NULL, dwThreadSize, MEM_COMMIT, PAGE_READWRITE); if (pRemoteThread == NULL) {MessageBox (NULL, _T ( "Failed to Allocate Memory at Remote Process for Thread Code.Err =") SysErrorMessage (GetLastError ()), NU LL, MB_OK | MB_APPLMODAL | MB_ICONWARNING); return;} Ret = WriteProcessMemory (hRemoteProcess, pRemoteThread, (LPVOID) ThreadFuncDetach, dwThreadSize, & dwWriten); if (Ret == 0) {MessageBox (NULL, _T ( "Failed to Write Thread Code to remote Process.Err = ") SysErrorMessage (GetLastError ()), NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING); return;} // start the remote thread HANDLE hRemoteThread; hRemoteThread = CreateRemoteThread (hRemoteProcess, 0,0, (DWORD (__ stdcall *) (Void *)) premoteThread, (DeinjectLibInfo *) premoteparam, 0, & dwriten; if (hremotetteread == NULL) {MessageBox (NULL, _T ( "Failed to create remote unload thread.Err =") SysErrorMessage (GetLastError ()), NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING);} else {CloseHandle (hRemoteThread);} // read return value unloading Ret = ReadProcessMemory (hRemoteProcess, pRemoteParam, (LPVOID) & DeinjectLibInfo, sizeof (DEINJECTLIBINFO), & dwWriten); if (Ret == 0) {MessageBox (NULL, _T ( "Unable to read unload return value.Err =") SysErrorMessage (GetLastError ()), NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING);} else {if (DeinjectLibInfo.dwReturnValue == 0) {} else {MessageBox (NULL, _T ( "Failed to unload .Err =") SysErrorMessage (DeinjectLibinfo.dwreturnValue), NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING);}} // Restore Right CloseHandle (HREMOTEPROCESS); EnablePrivilege (se_debug_name, false);} // -------------------------------------------- -------------------------------------------------- ----------- // How to use BOOL CTASKKEYMGR :: IscTrlattelete Disabled () {returna binjectfuncloaded; if (dwFlags & CTRLALTDEL) {if (bDisable && IsCtrlAltDeleteDisabled ()!) {InjectFunc (); bInjectFuncLoaded = TRUE;} if {DeinjectFunc () (bDisable && IsCtrlAltDeleteDisabled ()!); bInjectFuncLoaded = FALSE;}} note If the subsequent version of Windows changes the processing of Ctrl Alt Delete, the techniques provided herein may no longer work. If you use this article in your code, please note that you may have to modify your code in the future. Question There is no Unicode version VirtualalalkEx allocated memory without using VirtualFreeex release If you add a switch, run in the debug mode to cause Winlogon error (please do not confirm or cancel the error dialog box, then save all documents, close all documents Program, shut down through normal way, otherwise Windows will shut down immediately) reference If you need more information, refer to the discussion in the 9CBS forum How to disable CTRL Alt Delete in NT / 2000? (You cannot use Gina, keyboard driver). Click here to download the code of this article. Articles in the MSDN document library Q226359 HOWTO: Disable Task Switching on Win32 Platforms Q195027 STOP 0xC000021A in Winlogon Caused by PCAnywhere Q229033 Programs That Replace Msgina.dll May Cause "STOP 0x0000001E" Error Message Q192298 Third Party GINAs May Fail with Service Pack 4 Causing STOP 0x21A in WINLOGON Q164486 Winlogon May Fail if the third-party gina.dll file is missing or corrupted Q180854 Access Viology in Winlogon with third-part gina.dll Q193361 MSGINA.DLL DOES NOT WINLOGON STRUCTURE Articles in MSDN Magazine MSDN Magazine> September 2002> Typename, Disabling Keys in Windows XP with TrapKeys (Paul DiLascia) MSDN Magazine> June 2002> Windows XP Escape from DLL Hell with Custom Debugging and Instrumentation Tools and Utilities Articles in the VC Knowledge Base How to mask Ctrl Alt Del, Alt Tab, and Ctrl ESC key sequences in the Windows XP system Article type: kbhowto history: Last updated: November 10, 2002