远程线程注入技术 屏蔽ctrl alt del

远程注入线程,屏蔽Ctrl+Alt+Del  关键字     Ctrl,Alt,Delete,Windows 2000,hook,SAS,GINA,WINAPI,API,Thread     如何: 在Windows2000中动态禁用/启用Ctrl-Alt-Delete  -------------------------------------------------------------------------------- 此文章的 阅读详情
在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(四大名捕之追杀令)(此为优快云和www.driverdevelop.com之帐号)
//E-Mail :slwqw@163.com
//日期 :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(四大名捕之追杀令)(此为优快云和www.driverdevelop.com之帐号)jiangsheng(此为优快云帐号)
//E-Mail :slwqw@163.com
//日期 :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 Instru****tion 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 Instru****tion 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会立刻关机)
参考
如果需要更多信息,单击下面的连接查看优快云论坛中的讨论 

在NT/2000中怎么禁用Ctrl+Alt+Delete?(不能用gina,键盘驱动) 。 


MSDN文档库中的文章 

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 Violation in Winlogon with Third-Party Gina.dll 
Q193361 MSGINA.DLL does not Reset WINLOGON Structure
MSDN杂志中的文章

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 Instru****tion Tools and Utilities
VC知识库中的文章

Windows XP系统中如何屏蔽 Ctrl+Alt+Del、Alt+Tab以及Ctrl+Esc键序列 
文章类型 : kbhowto 
-------------------------------------------------
众所周知,在Windows 9X/Me系统中,屏蔽Ctrl+Del+Alt和各种任务开关键可以很轻松地通过API函数 SystemParametersInfo(SPI_SETSCREENSAVERRUNNING,TRUE,&bOldState,0)解决,但在Windows NT/2K/XP系列操作系统中,Ctrl+Del+Alt升级为最高级别组合键序列,成为系统安全预留的紧急出口,上述操作就无法实现了,即使采用WM_KEYBOARD_LL低级键盘钩子也无法拦截,但也不是绝对没有办法,不然也就不会有本文了。

系统启动过程
在Windows NT/2K/XP 中,用户登陆采用新版的WinLogon和GINA(Graphical Identification and Authentication)即图形化身份认证,此外还提供了一个网络服务的动态链接库Network Provider DLL。由于用户认证策略是在Gina DLL中独立设计的,我们可以通过替换此文件的方式进行智能卡或指纹等方面的认证开发。
小知识:WinLogon是Windows操作系统的一部分,提供用户交互式登陆支持,而GINA则是WinLogon实现认证的一个DLL,实际文件名为:Windows NT/system32/msgina.dll。 Windows则是用这个DLL实现用户名+密码进行身份认证。古老的GINA木马就是利用的这一点来获取系统的登陆密码的。
WinSta0 是显示器、鼠标和键盘的Windows系统对象的名称,Winlogon初始化的时候,在WinSta0 Windows系统中创建了SAS窗口(窗口标题是“SAS Window”)并首先注册了CTRL+ALT+DEL Secure Attention Sequence(SAS)热键,接下来创建了三个桌面,即Winlogon 桌面(显示安全登陆界面),应用程序桌面(即正常进入所显示的我的电脑界面),屏幕保护桌面。由于SAS热键的注册使得 Winlogon成为第一个处理CTRL+ALT+DEL的进程,这保证了没有其它应用程序能够处理这个热键。
当用户按下Ctrl+Alt+ Del组合键时,Winlogon桌面上的SAS窗口收到它注册的系统热键消息(WM_HOTKEY)。SAS Window窗口处理这个消息调用 GINA DLL中的WlxInitialize、WlxActivateUserShell函数进行初始化和调用用户外壳程序。Windows就是用这个机制进行用户和密码判断的,所以要中断Ctrl+Alt+Del组合键的处理,可以有以下方式:
1. 使用DDK(驱动程序开发包)编写键盘低层驱动程序捕获Ctrl+Alt+Del。
2. 替换Winlogon。
3. 编写GINA 代理DLL。
4. Hook Winlogon上SAS窗口的窗口过程(需要当前登录用户有调试权限)。
Socket:由于操作系统的升级换代非常容易引起用户自编写的DLL文件与系统文件之间的不兼容(著名的DLL地狱),由此不建议使用Winlogon.exe和GINA的方法,倾向于Hook Winlogon 上的SAS窗口并进行窗口子类化的方法。
开发原理
动态嵌入技术是指将用户自己代码嵌入到正在运行的进程中技术。理论上讲,Windows每个进程都有自己私有内存空间,其它进程禁止访问其私有空间。但实际上我们可用种种方法访问并操作其它进程的私有空间,这就是动态嵌入的DLL木马所采用的技术。在多种嵌入技术(HOOK 窗口,API挂接,远程线程)中,远程线程嵌入技术对用户要求不高,只要有基本的进程线程概念和DLL相关知识即可。
小知识:远程线程技术是指在一个进程中创建远程线程的手段进入目标进程的内存空间。通过CreateRemoteThread函数在目标进程内创建远程线程,共享目标进程的内存空间和其它资源,并且可以任意修改远程进程的数据,所以,此种作法风险极高。
通过将代码直接拷贝到远程线程内运行来完成动态嵌入,这种思想给了在应用程序中可动态屏蔽Ctrl+Alt+Del组合键的思路。在这之前我们要对Windows系统的内存偏移量也即相对内存进行修改,重点应用以下API函数:
1.首先我们要用FindWindow得到SAS窗口的句柄,因为我们要通过它获知运行后所在进程的ID,下面就是FindWindow的用法:
HWND FindWindow(
LPCTSTR lpClassName, // pointer to class name
LPCTSTR lpWindowName // pointer to window name
);  
2.采用GetProcAddress得到窗口相对应的进程ID,函数用法如下:
FARPROC GetProcAddress(
HMODULE hModule, // handle to DLL module
LPCSTR lpProcName // function name
);
3.得到进程ID后,接下来的事是要以最高权限打开进程,所用到的函数OpenProcess的具体使用方法如下:
HANDLE OpenProcess(
DWORD dwDesiredAccess, // access flag
BOOL bInheritHandle, // handle inheritance flag
DWORD dwProcessId // process identifier
);
在DwDesiredAccess之处就是设存取方式的地方,可设的权限很多,这里只使用PROCESS_ALL_ACCESS来打开进程就可以,更详细可查阅MSDN。
4.打开进程后,使用WriteProcessMemory来对内存地址写入数据即可:
BOOL WriteProcessMemory(
HANDLE hProcess, // handle to process whose memory is written to
LPVOID lpBaseAddress, // address to start writing to
LPVOID lpBuffer, // pointer to buffer to write data to
DWORD nSize, // number of bytes to write
LPDWORD lpNumberOfBytesWritten // actual number of bytes written
);
5.创建远程线程以运行所嵌入的代码。
HANDLE CreateRemoteThread(
HANDLE hProcess, // handle to process
LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
DWORD dwStackSize, // initial stack size
LPTHREAD_START_ROUTINE lpStartAddress, // thread function
LPVOID lpParameter, // thread argument
DWORD dwCreationFlags, // creation option
LPDWORD lpThreadId // thread identifier
);
6.CloseHandle(HANDLE hObject)关闭进程句柄。
工程实践
在系统集成的项目中,由于所开发的专业软件往往采用独占方式运行,软件开发中对用户无操作的空闲时段处理是必须考虑的问题。笔者在这种类型的项目中,考虑到后期代码维护和模块集成调试方便,设计时摒弃了传统的DLL(动态链接库)嵌入形式,采用远程线程代码嵌入技术对核心部分也是最困难部分NT/2000平台下屏蔽Ctrl+Alt+Del组合键进行处理。完成后程序运行稳定,实验效果非常良好。以下是核心代码:
1. 定义基本函数
我们需要用来给自身进程加入DEBUG权限的函数(有足够权限对别的进程进行操作),一个通过进程名得到进程ID的函数(Toolhelp 函数和PSAPI函数返回进程标识符(PID)值两种实现方式)。
/*********** 允许/禁止特权 通过调用SE_DEBUG_NAME 参数. ****/
BOOL EnablePrivilege(LPCTSTR lpszPrivilegeName, BOOL bEnable)
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID luid;
BOOL ret;
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_READ, &hToken))
return FALSE;
if (!LookupPrivilegeValue(NULL, lpszPrivilegeName, &luid))
return FALSE;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
ret = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
CloseHandle(hToken);
return ret;
}
/********** 根据进程名称返回进程标识符PID **********/
DWORD GetPIDFromName(char *szProcessName)
{
DWORD dwPID;
OSVERSIONINFO info;
info.dwOSVersionInfoSize = sizeof(info);
GetVersionEx(&info);
// 根据Windows操作系统版本的不同选择不同函数进行处理
if (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
dwPID = GetPIDFromNameToolhelp(szProcessName);
else if (info.dwPlatformId == VER_PLATFORM_WIN32_NT)
dwPID = GetPIDFromNamePSAPI(szProcessName);
else
dwPID = -1;
return dwPID;
}
2. 定义全局数据变量,准备线程的参数结构
定义对第一个处理Ctrl+Alt+Del组合键的WinLogon进程的文件名:
char *szProcessName = "winlogon.exe";
#pragma comment(linker, "/INCRE****L:NO") // 关闭增量链接模式
// 全局变量定义
DWORD PID; // 代码嵌入进程的PID
BYTE *pDataRemote; // INJECTDATA 数据结构在远程线程的地址
BYTE *pSASWinProcRemote; // 函数SASWindowProc()在远程线程的地址
#define DUMMY_ADDR 0x12345678 // INJECTDATA 数据结构的动态地址
// INJECTDATA: 每个远程代码嵌入函数所存贮的内存块,传递每个嵌入函数的地址或字符数据
typedef LONG (WINAPI *SETWINDOWLONG) (HWND, int, LONG);
typedef LRESULT (WINAPI *CALLWINDOWPROC) (WNDPROC, HWND, UINT, WPARAM, LPARAM);
typedef HWND (WINAPI *FINDWINDOW) (LPCTSTR, LPCTSTR);
定义线程所嵌入代码的地址结构:
typedef struct {
SETWINDOWLONG fnSetWindowLong; // SetWindowLong()函数地址
CALLWINDOWPROC fnCallWindowProc; // CallWindowProc()函数地址
FINDWINDOW fnFindWindow; // FindWindow()函数地址
char szClassName[50]; // 类名称为"SAS Window class"
char szWindowName[50]; // 窗口名称为"SAS window"
HWND hwnd; // 进程所嵌入的窗口句柄
WNDPROC fnSASWndProc; // 远程SASWindowProc 地址
WNDPROC fnOldSASWndProc; // 原始SASWindowProc 地址
} INJECTDATA, *PINJECTDATA;
3. 定义嵌入代码的功能函数
对远程线程嵌入的代码进行功能划分,子类化SAS窗口模块、子类化窗口进程的远程线程模块、恢复被子类化的窗口进程的远程线程设置模块、返回远程线程的窗口句柄(Winlogon)模块四个功能函数,下面以子类化SAS窗口进行嵌入代码为演示,其余函数编码与此类似:
/*********** 子类化SAS窗口以进行代码嵌入 ****************/
#pragma optimize("", off)
#pragma check_stack(off)
static LRESULT CALLBACK SASWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// INJECTDATA 结构指针必须在运行时处理
INJECTDATA* pData = (INJECTDATA *)DUMMY_ADDR;
if (uMsg == WM_HOTKEY)
{
// Ctrl+Alt+Del
if (lParam == MAKELONG(MOD_CONTROL | MOD_ALT, VK_DELETE))
return 1;
// Ctrl+Shift+Esc
if (lParam == MAKELONG(MOD_CONTROL | MOD_SHIFT, VK_ESCAPE))
return 1;
}
// 缺省处理
return pData->fnCallWindowProc(pData->fnOldSASWndProc, hwnd, uMsg, wParam, lParam);
}
static int AfterSASWindowProc(void) { return 1; }
Socket:假如这两个函数是上述排列,下面语句可得到嵌入线程代码的长度:
DWORD size = (PBYTE)AfterSASWindowProc - (PBYTE)SASWindowProc;
4. 远程线程嵌入代码实现
此时进行内存分配操作,远程线程空间嵌入用户编写的代码。将上述功能函数和地址结构INJECTDATA复制到远程线程空间,在默认的WinLogon窗口的进程内,远程调用函数InjectFunc(),进行Ctrl+Alt+Del组合热键屏蔽。
具体实现是在远程线程地址空间内依次写入GetSASWnd()代码模块拷贝、SASWindowProc()模块拷贝和初始化的INJECTDATA地址结构的拷贝。上述操作成功后,进行InjectFunc()函数拷贝的执行。
// 在远程线程内分配内存并存放函数InjectFunc()的拷贝
size = (PBYTE)AfterInjectFunc - (PBYTE)InjectFunc;
pCodeRemote = (PBYTE) VirtualAllocEx(hProcess, 0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!pCodeRemote)
__leave;
if (!WriteProcessMemory(hProcess, pCodeRemote, &InjectFunc, size, &dwNumBytesCopied) || dwNumBytesCopied != size)
__leave;
// 远程调用函数InjectFunc()的代码
hThread = CreateRemoteThread(hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE) pCodeRemote,
pDataRemote,
0 ,
&dwThreadId);
if (!hThread)
__leave;
// 等待函数InjectFunc() 执行结束并得到返回码
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, (PDWORD) &nSuccess);
// 成功
if (nSuccess)
MessageBeep(MB_OK);
5. 复原系统设置
在这一步中进行出错处理和内存释放等系统复原工作,利用上述代码嵌入技术执行函数EjectFunc()完成清除卸载工作。
// 释放结构INJECTDATA和函数SASWindowProc()所占内存
if (pDataRemote)
VirtualFreeEx(hProcess, pDataRemote, 0, MEM_RELEASE);
if (pSASWinProcRemote)
VirtualFreeEx(hProcess, pSASWinProcRemote, 0, MEM_RELEASE);
pDataRemote = NULL;
pSASWinProcRemote = NULL;
MessageBeep(MB_OK); // 成功
END: // 如果API调用出错,程序转向此进行清除处理
if (hThread)
CloseHandle(hThread);
// 释放函数EjectFunc() 所占用的内存
if (pCodeRemote)
VirtualFreeEx(hProcess, pCodeRemote, 0, MEM_RELEASE);
CloseHandle(hProcess);
// 恢复原先权限,禁止调试权限
EnablePrivilege(SE_DEBUG_NAME, FALSE);
return nSuccess; // 0 = failure; 1 = success
演示程序在Windows2K+SP4平台上用VC6.0+SP6调试通过,在NT/XP平台上测试正常。程序代码中根据需要实时对编译器环境作了调整,关闭了增量链接模式、优化和堆栈检查功能。由于DEBUG开发环境的设置出现了编译警告,但在RELEASE环境中编译正常。代码经过优化修改后已被某商用项目采用,较圆满实现了锁定NT/2K/XP的特殊组合键Ctrl+Del+Alt,最后感谢《黑客防线》编程类文章给予作者的灵感!
 
VB 远线程注入技术 屏蔽 Ctrl+Alt+Del  在NT平台下,用户登陆是使用Winlogon和GINA——Graphical Identification and Authentication,意思是图形化的身份认证。Winlogon是Windows系统的一部分,它专门提供交互式登陆支持,而GINA则是Winlogon用来实现认证的一个DLL——这个DLL就是msgina.dll。WlxInitialize、WlxActivateUs 阅读详情

相关推荐

屏蔽键盘按键 vc++代码

钩子消息,可以屏蔽键盘按键功能,多多益善,很好用的呀! 大家可以学习一下哦,加油一起为c++奋斗,嘿嘿。

VC实现下屏蔽Ctrl+Alt+Del键

大家知道,Ctrl+Alt+Del是Win2k/NT操作系统默认的系统登录/注销组合键序列,系统级别很高。在应用程序中,想要屏蔽掉该键序列的响应或得到这个"按下"事件,难度是相当大的。本例介绍了一种简单易行的方法,实现在用户登录成功后,按下Ctrl+Alt+Del不再弹出"Windows安全"对话框。需要读者朋友注意的是,本实例必须运行在Windows 2000环境下。   一、 实现方

超越梦想的专栏 3579

利用远程线程屏蔽ctrl+alt+del组合键

利用远程线程屏蔽ctrl+alt+del组合键 此源码有利于大家研究远程控制技术

怎样屏蔽系统热键

怎样屏蔽系统热键在程序开发过程中,为了达到一些特殊的要求,有时需要屏蔽系统热键。这些系统热键包括 Alt+Tab、Ctrl+Alt+Del、Alt+Esc、Ctrl+Esc、Win 键等。由于屏蔽系统热键涉及到系统的安全,所以微软并不推荐这样做,我们只能在一些未公开的文档中去探究它。下面我们分三种情况来讨论屏蔽系统热键的方法。一、              在win95/win98操作

凤之焚的专栏 2704

VC++屏蔽Windows热启键(Ctrl+Alt+Del)程序

内容索引:VC/C++源码,系统相关,热键  VC++屏蔽Windows热启键(Ctrl+Alt+Del)程序,实现动态禁用/启用Window NT/2000/XP的Ctr+Alt+Del组合键,在远程线程分配内存来存放参数。测试发现,本程序在XP下运行好像有点问题,容易导致电脑重启,特别是在勾选选框的时候,大家请注意。

FreeSWITCH安装指南:三种部署方式解析与实践对比

Freeswitch部署方案比较:Yum安装简单快捷但灵活性差;源码安装可定制性强,适合深度开发和性能优化;Docker部署环境一致性好但网络配置复杂。生产环境推荐源码安装以获得最佳性能和定制能力,而Docker适合快速部署和扩展。不同方案各有利弊,需根据具体需求选择。

c_zyer的博客 2138

远程线程注入技术 屏蔽ctrl+alt+del

在NT/2000中怎么禁用Ctrl+Alt+Delete?(不能用gina,键盘驱动) 在Windows2000中Ctrl-Alt-Delete组合键的处理如下:Winlogon初始化的时候,在系统中注册了CTRL+ALT+DEL Secure Attention Sequence(SAS)热键,并且在WinSta0 Windows 系统中创建三个桌面。 SAS热键的注册使得Winlogon成为第

无知人生,记录点滴 5351

手把手教你用VS Code + Codex在WSL中高效编程(避坑指南)

本文提供了一份详细的避坑指南,教你如何在WSL环境中高效配置和使用VS Code与OpenAI Codex。文章核心在于解决WSL内Codex扩展的OAuth登录失败问题,推荐将扩展安装在Windows本地,并通过UNC路径直接访问WSL文件系统,从而实现AI辅助编程与Linux开发环境的无缝结合,提升编码效率。

weixin_28677451的博客 1062

完美屏蔽 Ctrl+Alt+Del 键

完美屏蔽 Ctrl+Alt+Del 键一、前言  在Windows 9x/Me系统中,屏蔽Ctrl+Alt+Del和各种任务开关键的方法是通过下面的方法实现的:BOOL bOldState;SystemParametersInfo(SPI_SETSCREENSAVERRUNNING, TRUE, &bOldState, 0); 但在NT平台下,此方法不再适用,即使使用钩子技术也无法拦截到这个组

荣植华的专栏 8758

SQLSTATE58030

在优化一条SQL的时候遇到了执行错误 gtlions =# select t1.telnumber,t2.ua,t2.url,t1.apply_name,t2.apply_name from tb1 t1 gtlions -# left outer join tb2 t2 on t1.sid = t2.ipsid gtlions-# where t1.sum_date=20141128 a

Gtlions Tracker 3658

深入解析ADC采样电容:从充电误差到LSB精度的关键设计

本文深入解析了ADC采样电容在模数转换中的核心作用,重点探讨了充电时间常数与采样误差的博弈关系。通过推导最小采样时间公式,揭示了精度、速度、源阻抗与内部电容之间的制约关系,并提供了从理论计算到外部驱动电路设计的实战指南,是确保ADC达到LSB精度的关键。

android的专栏 1103

在Win2000中动态禁用/启用Ctrl-Alt-Del

在Win2000中动态禁用/启用Ctrl-Alt-Del 在Win2000中动态禁用/启用Ctrl-Alt-Del分享到QQ微博分享到新浪微博分享到Twitter分享到人人网分享到QQ空间[作者:佚名 来源:vczx 时间:2011-1-5 【我来说两句 大 中 小】此文章的信息来自优快云论坛VC/MFC版的讨论 在NT/2000中怎么禁用C...

weixin_30410119的博客 174

SAP 创建PO时提示“不能确定任何组件”

SAP 创建委外加工的PO时提示“不能确定任何组件” 而如果BOM已经创建了,但还是提示该错误保存。 解决办法:1. BOM selection 未配置好; 2. 由于Purchasing prosessing time的设置,如果PO中的delivery time - Purchasing prosessing time是过去的日期,那么会找不到BOM,BOM的有效期需早 于PO审批的有效期。 3. BOM未...

willieyuan的博客 6114

如何在Windows2000中动态禁用/启用Ctrl-Alt-Delete

单击这里下载本文的代码。概要此文章的信息来自优快云论坛VC/MFC版的讨论 在NT/2000中怎么禁用Ctrl+Alt+Delete?(不能用gina,键盘驱动) 在Windows2000中Ctrl-Alt-Delete组合键的处理如下: Winlogon初始化的时候,在系统中注册了CTRL+ALT+DEL Secure Attention Sequence(SAS

Y___Y的专栏 1706

【推荐100个unity插件】对话系统插件——YarnSpinner-Unity插件

Yarn Spinner是一款专为游戏对话设计的脚本语言,适用于Unity等引擎。本文介绍了在Unity中安装和使用Yarn Spinner的完整流程:首先通过Package Manager添加仓库并安装插件;然后创建Yarn Script和Project文件,配置对话系统;接着编写Yarn脚本定义对话内容,并展示运行效果;最后讲解了按键控制和多语言本地化设置。该工具采用类似剧本的简洁格式,支持分支对话、条件逻辑等功能,能有效提升游戏叙事的开发效率。

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 2210

小红书urlscheme和Activity

本文档详细介绍了小红书App的Deeplink跳转规范,涵盖了多个功能模块的跳转协议。主要内容包括:主页各Tab(关注、发现、购买)的跳转方式;不同类型笔记(图文/视频/长笔记)的详情页跳转参数;用户相关页面(主页/绑定/资料/消息等)的跳转协议;搜索功能(输入页/结果页)的跳转方式;以及话题、标签、专辑、H5页面等特殊场景的跳转实现。文档还提供了各跳转协议所需的参数说明,包括参数类型、默认值、是否必填等详细信息,并标注了不同版本和平台的兼容性要求。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 785

屏蔽Ctrl+alt+del

在Windows2000中Ctrl-Alt-Delete组合键的处理如下:           Winlogon初始化的时候,在系统中注册了CTRL+ALT+DEL   Secure   Attention   Sequence(SAS)热键,并且在WinSta0   Windows   系统中创建三个桌面。           SAS热键的注册使得Winlogon成为第一个处理

阿特图 3316

计算机视觉 | 面试题:01、过拟合和欠拟合的表现与解决方法

问题 过拟合和欠拟合的表现和解决方法。 其实除了欠拟合和过拟合,还有一种是适度拟合,适度拟合就是我们模型训练想要达到的状态,不过适度拟合这个词平时真的好少见,在做酷狗音乐的笔试题时还懵逼了一会,居然还真的有这样的说法。 这应该是基础中的基础了,笔试题都做烂了。那就当做今天周末,继续放个假吧…… 过拟合 过拟合的表现 模型在训练集上的表现非常好,但是在测试集、验证集以及新数据上的表现很差,损失曲线呈现一种高方差状态。(高方差指的是训练集误差较低,而测试集误差比训练集大较多) 过拟合的原因 从两个角度去分析

Mrrunsen的博客 866

MFC:XP下屏蔽Ctrl+Alt+Del等组合键的方法

屏蔽Ctrl+Alt+Del等组合键也是一个老生长谈的话题了,95、98系统中有很多方法试用,但是在Xp下就不能用了,而本文则不考虑Win7系统,因为那又是另一种方法了,本文只介绍XP下屏蔽这些组合键的方法。 屏蔽Ctrl+Alt+Del我知道的有两种,一个是直接改写注册表,这个比较简单,也能禁止,但是会有提示“管理员禁止任务管理器”的字样,这是因为直接关闭了系统服务,虽然效果能达到但是不是我们

q472599451的专栏 2975

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

如何: 在Windows2000中动态禁用/启用Ctrl-Alt-Delete

如何: 在Windows2000中动态禁用/启用Ctrl-Alt-Delete此文章的信息应用于:Microsoft Windows 2000本文的更新信息位于http://blog.joycode.com/jiangsheng/archive/2004/07/20/27909.aspx单击这里下载本文的代码。概要此文章的信息来自

蒋晟的专栏 1万+

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

windows系统屏蔽热键(进程注入 窗口子类化)

系统屏蔽相关热键主要是屏蔽相关系统快捷键功能,例如Alt+F4、Win+Tab、CTRL+ALT+ESC等,通过全局键盘钩子可以屏蔽大部分系统快捷键,但是有一种快捷键与其他的快捷键响应方式不同,其不是在应用程序层次响应,在操作系统启动时,系统就将该热键注册为安全序列,应用程序级别是无法获得该组合键的消息的,经过一周的调研,发现在windows系统系列中,XP和win7及以上系统对于该组合快捷键的处...

liyuanba2dai的博客 2337

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

禁用windows热键Ctrl+Alt+Delete

在网上搜了一通怎么用代码实现,只找到屏蔽常规的win键、alt+tab之类的hook方式,要禁用Ctrl+Alt+Del好像没有现成的代码。在搜资料的过程中找到一篇评论中,有人提议到Microsoft Answer论坛咨询,去该论坛上搜了一下屏蔽该组合,还真找到了。 禁止ctrl+alt+del快捷键 reg add "HKLM\SYSTEM\CurrentControlSet\Control\Keyboard Layout" /v "Scancode Map" /t REG_BINARY /d 00000

weixin_42210846的博客 2646

实现屏蔽 Ctrl + Alt + Del 、Ctrl + Shift + Esc 等热键(二)

在第一篇文章中,我们主要分析了系统热键处理的关键接口以及如何通过选取特征码精准定位接口函数的入口点。在这一篇中,我们将进一步分析 Winlogon 相关例程的机制,并给出挂钩处理的解决方案。需要注意的是“屏蔽 Ctrl + Alt + Del 、Ctrl + Shift + Esc 等热键”系列是 Windows 系统热键拦截技术分析专栏的一个分支,主要复现 heiheiabcd 的旧文给出的拦截思路。该方案并不是最推荐的方案,如果你想要继续了解,可以查阅同专栏的其他文章。Winlogon 进程通过 Sig

溡漪幽博客 2996
上一篇: 机器狗木马源文件
下一篇: 反病毒工具之注册表监视器
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值