How to: Pismostatic Disable / Enable Ctrl-Alt-Delete in Windows2000
-------------------------------------------------- ------------------------------
Information about this article is applied to:
Microsoft Windows 2000
-------------------------------------------------- ------------------------------
Click here to download the code of this article.
Summary of this article from 9CBS Forum VC / MFC version discussion
How to disable Ctrl Alt DELETE in NT / 2000 (can not use Gina, keyboard driver) The processing of Ctrl-Alt-delete combinations in Windows 2000 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) Dynamic connection library to interrupt the processing of Ctrl-Alt-delete key combination, can have the following way
Ctrl-alt-delete from the keyboard drive layer Replace Winlogon Replace the window process of the SAS window on the GINA Hook Winlogon (requires the current login user with the privilege permission) Hook Gina, then returns WLX_SAS_Action_NONE (not studied) More information Given the system Updates may cause our replacement system files and other system files that are not compatible (famous DLL hell), so it is not recommended to replace Winlogon.exe and Gina method. 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
Using namespace std;
/ / -------------------------------------------------------------------------------------------- ---------------------------
HWND HSASWND; FARPROC FOLDPROC;
LResult Callback SaswindowProc (HWND HWND, UINT UMSG, WPARAM WPARAM, LPARAM LPARAM);
Bool Callback EnumwindowsProc (HWND HWND, LPARAM LPARAM);
/ / -------------------------------------------------------------------------------------------- ---------------------------
Handle hthread = null; dword dwthreadID;
DWORD WINAPI Threadfunc ();
/ / -------------------------------------------------------------------------------------------- --------------------------- Bool Apientry Dllmain (Handle HModule, DWORD UL_REASON_FOR_CALL, LPVOID LPRESERVED) {Switch (ul_reason_for_call) {Case DLL_Process_attach: hthread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) ThreadFunc, NULL, 0, & dwThreadId); break; case DLL_PROCESS_DETACH: if (! FOldProc = NULL) {SetWindowLong (hSASWnd, GWL_WNDPROC, long (FOldProc));} CloseHandle (hThread); Break;} Return True;} // ----------------------------------------- ---------------------------------- DWORD WINAPI Threadfunc () {HDESK HDESK;
HDESK = OpenDesktop ("Winlogon", 0, False, Maximum_Allowed;
FoldProc = NULL; hsaswnd = null;
EnumdesktopWindows (HDESK, (WndenumProc) EnumWindowsProc, 0);
IF (HSASWND! = NULL) {foldproc = (farproc) setWindowlong (HSASWND, GWL_WNDPROC, Long (SaswindowProc);} closehandle (HDESK);
Return 1;} // ------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------ / / Find "Winlogon" desktop window Bool Callback EnumWindowsProc (HWND HWND, LPARAM LPARAM) {Char Classbuf [128];
GetWindowText (HWND, ClassBuf, Sizeof (Classbuf));
// I wrote a system service, then query the window on the "Winlogon" desktop and discovered that there is // 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
#include "hook.h" // address by jiangsheng 2002-11-5 # include "taskkeymgr.h" #include "wrappers.h" // Copy from MSDN Magazine Windows XP Escape from DLL Hell with Custom Debugging and Instrumentation Tools and Utilities EXTERN BOOL IS_TERMINAL_SERVICES (); // Copy from Platform SDK Document: Windows System Information / Verifying The System Version // End ISHEENG 2002-11-5 / / ------------ -------------------------------------------------- ------------- // Error code formatting function // replaced by jiangsheng 2002-11-5 // from Q149409 HOWTO: GET Message Text from network networking error codecstring __fastcall syserrorMessage (DWORD dwlasterror) { CSTRING STRET (_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;
///////////// 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 support of module handle. //
if (dwBufferLength = FormatMessageA (dwFormatFlags, hModule, // module to get message from (NULL == system) dwLastError, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // default 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 // -------------- -------------------------------------------------- -----------
#ifdef UNICODELPCSTR LoadLibraryFuncStr = "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 removed 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 pfnLoadLibrary; 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-footing function, used to calculate the size of Threadfuncattach Static void AfThreadFuncattach (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;}}
IF (Pinfo-> dwreturnvalue == 0 &&! bhasfoundmodule) {Pinfo-> dwreturnValue = Pinfo-> pfNgetLastError ();}
Return 1;}
/ / -------------------------------------------------------------------------------------------- -------------------------- // Place-footing function, used to calculate the size static void atThreadFuncDetAC Void AfThreadFuncDetAC Void AfTerThreadFuncdetA (Void) {} // -------------------------------------------------- ------------------------ // Modify the Permissions of this process BOOL __FASTCALL ENABLEPRIVILEGE (LPCTSTSTCALL ENABLEPRIVILEGE (LPCTSTSZPSZPRIVILENAME, BOOL BENABLE) {Handle Htoken; Token_Privies TP; Luid Luid ;
if (! OpenProcessToken (GetCurrentProcess (), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_READ, & hToken)) return FALSE; if return TRUE; (LookupPrivilegeValue (NULL, lpszPrivilegeName, & luid)!)
Tp.privilegegount = 1; tp.privileges [0] .luid = Luid; tp.privileges [0] .attributes = (BENABLE)? SE_PRIVILE_ENABED: 0;
AdjustTokenPrivileges (HToken, False, & TP, NULL, NULL, NULL);
CloseHandle (HTOKEN);
Return (GetLastError () == Error_suCcess);} // ------------------------------------- ------------------------------------- // Get the ID of the process (here The method Toolhelp function, 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) {
// copy 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; // Open to improve this process and the destination process permissions // current user must have permission to debug 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 = ") 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 in remote thread To store the parameter 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 (hRemoteProcess, 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 (pRemoteThread == 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 remove process.err = ") syserrorMesS, NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING); RETURN;} // Start 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 =") SySerror (), NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING);} else {; // the return value of the read unloading dwRet = ReadProcessMemory (hRemoteProcess, pRemoteParam, (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 rights enablePrivilege (SE_DEBUG_NAME, false); CloseHandle (hRemoteProcess);} // ------- -------------------------------------------------- ------------------ // Uninstall thread // -------------------------- ------------------------------------- / / Deinjectfuncvoid __fastcall deinjectfunc () {handle hremoteprocess = null; dword dwremoteprocess = 0; DWORD dwthreadsize = 0; deinjectlibinfo deinjectlibinfo; PVOID premothetread = null; pvoid premoteparam = null; dword dwriten = 0; dword ret = 0; // Enhance the authority of this process and open the process 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 =.") SysErrorMessage (GetLastError ()), NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING); return ;} // 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 (" kernel32.dll "), getLastErrorFuncstr); Lstrcpyn (deinjectlibinfo.szdllname, ctaskKeymgr :: strremotedllname, ctaskKeymgr :: strremotedllname.getlength () 1); // allocate memory in the remote thread to hold the 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 = ") SYSERRORMES sage (GetLastError ()), NULL, 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 =") SySerror ()), NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING); RETURN;} // Start the remote thread handle hremotheread; hRemoteThread = CreateRemoteThread (hRemoteProcess, 0,0, (DWORD (__ stdcall *) (VOID *)) pRemoteThread, (DEINJECTLIBINFO *) pRemoteParam, 0, & dwWriten); if (hRemoteThread == NULL) {MessageBox (NULL, _T ( "Failed to create remote unload thread.Err = ") SysErrorMessage (GetLastError ()), NULL, MB_OK | MB_APPLMODAL | MB_ICONWARNING);} else {CloseHandle (hRemoteThread);} // return value read 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 permission CloseHandle (HREMOTEPROCESS); EnablePriviege (se_debug_name, false);} // ------------------------------- -------------------------------------------- //Instructions Bool ctaskKeymgr :: isctrlaltdeletedisabled () {return 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. Known Issues No Unicode Version VirtualalalkEx Allocated Memory does not use VirtualFreeEx to release in debug mode to cause Winlogon errors (do not confirm or cancel the error dialog box, then save all documents, close all programs, through normal Way to shut down, otherwise Windows will shut down immediately) Reference If you need more information, click the following connection to see how to disable Ctrl Alt DELETE in NT / 2000 in NT / 2000. (You cannot use Gina, keyboard).