如何: 在Windows2000中動態禁用/啓用Ctrl-Alt-Delete
--------------------------------------------------------------------------------
此文章的信息應用於:
Microsoft Windows 2000
--------------------------------------------------------------------------------
單擊這裏下載本文的代碼。
概要
此文章的信息來自CSDN論壇VC/MFC版的討論
在NT/2000中怎麼禁用Ctrl+Alt+Delete?(不能用gina,鍵盤驅動)
在Windows2000中Ctrl-Alt-Delete組合鍵的處理如下:
Winlogon初始化的時候,在系統中註冊了CTRL+ALT+DEL Secure Attention Sequence(SAS)熱鍵,並且在WinSta0 Windows 系統中創建三個桌面。
SAS熱鍵的註冊使得Winlogon成爲第一個處理CTRL+ALT+DEL的進程,所以保證了沒有其他應用程序能夠處理這個熱鍵。
在 Windows NT/Windows 2000/Windows XP中, WinSta0 是表示物理屏幕、鼠標和鍵盤的Windows系統對象的名字。Winlogon在WinSta0 Windows系統中創建了SAS窗口(窗口標題是"SAS Window")和如下三個桌面。
Winlogon 桌面
應用程序 桌面
屏幕保護 桌面
當用戶按下Ctrl-Alt-Delete組合鍵時,Winlogon桌面上的SAS窗口收到它註冊的系統熱鍵消息(WM_HOTKEY)
SAS Window窗口處理這個消息調用Graphical Identification and Authentication(GINA)動態連接庫中的相關函數
要中斷Ctrl-Alt-Delete組合鍵的處理,可以有以下方式
從鍵盤驅動層捕獲Ctrl-Alt-Delete
替換Winlogon
替換GINA
Hook Winlogon 上SAS窗口的窗口過程(需要當前登錄用戶有調試權限)
Hook GINA裏邊的函數WlxLoggedOnSAS,然後返回WLX_SAS_ACTION_NONE(未研究)
更多信息
鑑於系統的更新可能造成我們替換的系統文件和其他系統文件不兼容(著名的DLL地獄),所以不推薦替換Winlogon.exe和GINA的方法。這裏我們討論Hook Winlogon 上的SAS窗口的窗口過程的方法。
因爲SAS窗口和我們的程序內存地址空間不同,所以要寫一個動態連接庫,加載到SAS窗口的內存空間中。下面是動態連接庫的源代碼。
//---------------------------------------------------------------------------
//作者 :韋覃武
//網上呢稱:BCB_FANS(四大名捕之追殺令)(此爲CSDN和www.driverdevelop.com之帳號)
//E-Mail :[email protected]
//日期 :2002-10-20
//
//功能 :在2000下屏蔽Ctrl + Alt + Del組合鍵。(在Windows 2000 Professional SP3
// 中文版平臺下面測試通過)
//原理 :採用遠程線程注入技術,裝載一個DLL到Winlogon進程,然後截獲SAS窗口的窗
// 口過程,接管WM_HOTKEY消息,以達到屏蔽Ctrl + Alt + Del之目的。
//開發語言:Borland C++Builder 5.0 Patch2
//技術比較:關於在2000下面如何屏蔽Ctrl + Alt + Del組合鍵,一種常被提到的解決方法就
// 是使用自己寫的GINA去替換MSGINA.DLL,然後在WlxLoggedOnSAS裏邊直接返回
// WLX_SAS_ACTION_NONE。嘿嘿,說到底這並不是真正地屏蔽了這個組合鍵,只是
// 直接返回WLX_SAS_ACTION_NONE時,Winlogon進程又自動從"Winlogon"桌面切換
// 回原來的"Default"桌面了,而不是顯示安全對話框,所以看起來被屏蔽了:),
// 使用那種方法明顯地看到桌面在閃爍!但是使用本文的方法時,你不會看到任
// 何閃爍!
//鳴謝 :www.driverdevelop.com上的icube和lu0。
//版權 :轉載請註明原作者:)
//---------------------------------------------------------------------------
#include "stdafx.h"
#include <string>
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;
}
//---------------------------------------------------------------------------
//查找"Winlogon"桌面的窗口
BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam)
{
char ClassBuf[128];
GetWindowText(hwnd,ClassBuf,sizeof(ClassBuf));
//我自己寫了一個系統服務,然後在裏邊查詢"Winlogon"桌面上的窗口,發現桌面上存在
//窗口"SAS window"。
string ClassName(ClassBuf);
if(ClassName.find("SAS window") != -1)
{
hSASWnd = hwnd;
return false;
}
return true;
}
//---------------------------------------------------------------------------
//SAS窗口的窗口過程
LRESULT CALLBACK SASWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
//屏蔽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);
//按下Ctrl + Alt + Del組合鍵
if(IsCtrlDown && IsAltDown && wKey == VK_DELETE)
{
return 1;
}
//按下Ctrl + Shift + Esc組合鍵,這個組合鍵將顯示任務管理器,可根據需要是否屏蔽。
else if(IsCtrlDown && IsShiftDown && wKey == VK_ESCAPE)
{
// Do nothing
}
}
return CallWindowProc((WNDPROC)FOldProc,hwnd,uMsg,wParam,lParam);
}
//---------------------------------------------------------------------------
這樣,如果Winlogon加載了這個動態連接庫,那麼就替換了SAS窗口的窗口過程。如果Winlogon卸載了這個動態連接庫,則恢復了SAS窗口的窗口過程。
爲了讓Winlogon加載我們的動態連接庫,首先要找到Winlogon進程,然後在進程中分配空間存放我們的代碼,再通過創建遠程線程賴執行我們的代碼。下面是Hook部分的代碼
//---------------------------------------------------------------------------
//作者 :韋覃武,jiangsheng
//網上呢稱:BCB_FANS(四大名捕之追殺令)(此爲CSDN和www.driverdevelop.com之帳號)jiangsheng(此爲CSDN帳號)
//E-Mail :[email protected]
//日期 :2002-10-20
//2002-11-5 jingsheng修改
//功能 :在2000下屏蔽Ctrl + Alt + Del組合鍵。(在Windows 2000 Professional SP3
// 中文版平臺下面測試通過)
//原理 :採用遠程線程注入技術,裝載一個DLL到Winlogon進程,然後截獲SAS窗口的窗
// 口過程,接管WM_HOTKEY消息,以達到屏蔽Ctrl + Alt + Del之目的。
//開發語言:Borland C++Builder 5.0 Patch2,Visual C++ 6.0 SP5
//技術比較:關於在2000下面如何屏蔽Ctrl + Alt + Del組合鍵,一種常被提到的解決方法就
// 是使用自己寫的GINA去替換MSGINA.DLL,然後在WlxLoggedOnSAS裏邊直接返回
// WLX_SAS_ACTION_NONE。嘿嘿,說到底這並不是真正地屏蔽了這個組合鍵,只是
// 直接返回WLX_SAS_ACTION_NONE時,Winlogon進程又自動從"Winlogon"桌面切換
// 回原來的"Default"桌面了,而不是顯示安全對話框,所以看起來被屏蔽了:),
// 使用那種方法明顯地看到桌面在閃爍!但是使用本文的方法時,你不會看到任
// 何閃爍!
//鳴謝 :www.driverdevelop.com上的icube和lu0。
//版權 :轉載請註明原作者:)
//---------------------------------------------------------------------------
#include "stdafx.h"
#include <tlhelp32.h>
#include <lmerr.h>
#include "Hook.h"
//add by jiangsheng 2002-11-5
#include "TaskKeyMgr.h"
#include "Wrappers.h"//複製自MSDN雜誌Windows XP Escape from DLL Hell with Custom Debugging and Instrumentation Tools and Utilities的代碼
extern BOOL Is_Terminal_Services () ;//複製自Platform SDK文檔: Windows System Information /Verifying the System Version
//end add by jiangsheng 2002-11-5
//---------------------------------------------------------------------------
//錯誤代碼格式化函數
//replaced by jiangsheng 2002-11-5
//from Q149409 HOWTO: Get Message Text from Networking Error Codes
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), // 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)
FreeLibrary(hModule);
return strRet;
}
//end replaced by jiangsheng 2002-11-5
//---------------------------------------------------------------------------
#ifdef UNICODE
LPCSTR LoadLibraryFuncStr = "LoadLibraryW";
LPCSTR GetModuleHandleFuncStr = "GetModuleHandleW";
#else
LPCSTR LoadLibraryFuncStr = "LoadLibraryA";
LPCSTR GetModuleHandleFuncStr = "GetModuleHandleA";
#endif
LPCSTR 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-5
LPCTSTR 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;
//---------------------------------------------------------------------------
//遠程線程,用來裝載DLL
static 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);
}
//---------------------------------------------------------------------------
//佔位函數,用來計算ThreadFuncAttach的大小
static void AfterThreadFuncAttach(void)
{
}
//---------------------------------------------------------------------------
//遠程線程,用來卸載DLL
static DWORD WINAPI ThreadFuncDetach(DEINJECTLIBINFO *pInfo)
{
HINSTANCE hDll = NULL;
BOOL bResult=FALSE;
BOOL bHasFoundModule = FALSE;
pInfo->dwReturnValue = 0;//意味成功,如果這個值不是0,則是一個錯誤代碼。
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;
}
//---------------------------------------------------------------------------
//佔位函數,用來計算ThreadFuncDetach的大小
static void AfterThreadFuncDetach(void)
{
}
//---------------------------------------------------------------------------
//修改本進程的權限
BOOL __fastcall EnablePrivilege(LPCTSTR lpszPrivilegeName,BOOL bEnable)
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID luid;
if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES |
TOKEN_QUERY | TOKEN_READ,&hToken))
return FALSE;
if(!LookupPrivilegeValue(NULL, lpszPrivilegeName, &luid))
return TRUE;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = (bEnable) ? SE_PRIVILEGE_ENABLED : 0;
AdjustTokenPrivileges(hToken,FALSE,&tp,NULL,NULL,NULL);
CloseHandle(hToken);
return (GetLastError() == ERROR_SUCCESS);
}
//---------------------------------------------------------------------------
//通過進程名稱得到進程的ID(這裏使用方法Toolhelp函數,也可使用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){
//複製自MSDN雜誌Windows XP Escape from DLL Hell with Custom Debugging and Instrumentation Tools and Utilities的代碼
//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 < ProcessCount; CurrentProcess++){
CString strCurExePath(pProcessInfo[CurrentProcess].pProcessName);
CString strRemoteProc(lpszProcName);
strCurExePath.MakeLower();
strRemoteProc.MakeLower();
bFound = (strCurExePath.Find(strRemoteProc) != -1);
if(bFound && dwCurSessionID==pProcessInfo[CurrentProcess].SessionId) {
dwProcessID = pProcessInfo[CurrentProcess].ProcessId;
break;
}
}
}
WTS.WTSFreeMemory(pSessionInfo);
}
}
}
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;
}
//---------------------------------------------------------------------------
// 插入代碼
//---------------------------------------------------------------------------
//InjectFunc
void __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;
//提升本進程權限然後打開目的進程
//當前用戶必須具有調試權限
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;
}
//初始化參數
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);
//在遠程線程分配內存來存放參數
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;
}
//拷貝線程體
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 Remote Process.Err = ") + SysErrorMessage(GetLastError()),
NULL,MB_OK | MB_APPLMODAL | MB_ICONWARNING);
return;
}
//啓動遠程線程
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
{
;
}
//讀卸載返回值
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);
}
}
//恢復權限
EnablePrivilege(SE_DEBUG_NAME,false);
CloseHandle(hRemoteProcess);
}
//---------------------------------------------------------------------------
// 卸載線程
//---------------------------------------------------------------------------
//DeinjectFunc
void __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;
//提升本進程權限然後打開目的進程
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;
}
//初始化參數
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);
//在遠程線程分配內存來存放參數
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;
}
//拷貝線程體
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()),
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 = ") + SysErrorMessage(GetLastError()),
NULL,MB_OK | MB_APPLMODAL | MB_ICONWARNING);
return;
}
//啓動遠程線程
HANDLE hRemoteThread;
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);
}
//讀卸載返回值
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);
}
}
//恢復權限
CloseHandle(hRemoteProcess);
EnablePrivilege(SE_DEBUG_NAME,false);
}
//---------------------------------------------------------------------------
//使用方法
BOOL CTaskKeyMgr::IsCtrlAltDeleteDisabled(){return bInjectFuncLoaded;}
if (dwFlags & CTRLALTDEL) {
if(bDisable&&!IsCtrlAltDeleteDisabled()){
InjectFunc();
bInjectFuncLoaded=TRUE;
}
if(!bDisable&&IsCtrlAltDeleteDisabled()){
DeinjectFunc();
bInjectFuncLoaded=FALSE;
}
}
注意
如果Windows的後續版本更改了Ctrl+Alt+Delete的處理,本文所提供的技術可能不再工作。如果你在你的代碼中使用了本文的技術,請注意你可能必須在未來修改你的代碼。
已知問題
尚無Unicode版本
VirtualAllocEx分配的內存沒有用VirtualFreeEx釋放
在Debug方式下運行會造成Winlogon出錯(出錯後請不要確認或取消那個出錯對話框,然後保存打開的所有文檔,關閉所有程序,通過正常的途徑關機,否則Windows會立刻關機)
參考
如果需要更多信息,單擊下面的連接查看CSDN論壇中的討論
在NT/2000中怎麼禁用Ctrl+Alt+Delete?(不能用gina,鍵盤驅動) 。