【转】提供一些外挂检测方法

2011/06/29 sec 共 5342 字,约 16 分钟

提供一些外挂检测方法:屏幕保护是否开启、是否有显示器、显示器是否关闭、键盘鼠标使用频率、窗口特征检测、模块列表检测、内存特征提取、文件md5检测

1.如果使用外挂挂机一段时间,很可能用户很长一段时间不去操作电脑,电脑变进入屏保状态。

2.如果进行长时间挂机,例如在睡觉的时候挂机,很可能用户会关闭电脑显示器。

3.除上述检测方法外,常规方法就是获取键盘鼠标在一定时间内的使用频率了,这类似于QQ、MSN长时间无操作会变为离开状态,以及APM(Actions Per Minute 每分钟操作的次数)工具。

下面贴一些主要实现代码:

1.检测是否进入屏保状态:

    //是否进入屏保
    BOOL isActive = FALSE;   //一定是BOOL而不是bool否则运行时错误
    SystemParametersInfo(SPI_GETSCREENSAVERRUNNING,0,&isActive, 0);
    if(isActive){
        outfile<<" SCREENSAVE ON ";
    } else {
        outfile<<" SCREENSAVE OFF ";
    }

2.检测显示器是否关闭:

    //显示器是否关闭
    HANDLE hMonitor =     CreateFile("\\\\.\\LCD\\", 
        GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
    if(GetDevicePowerState(hMonitor,&isActive)){ //如果发生错误 往往是句柄参数不正确导致的.
        if(isActive){
            outfile<<", MONITOR ON ";
        }else{
            outfile<<", MONITOR OFF ";
        }
    } else{
        outfile<<", MONITOR FAIL ";
    }

3.检测键盘鼠标使用频率:

这里简单一些的话可以使用GetLastInputInfo来获取最近一次键盘鼠标操作的时间,如果时间离现在很久了并且游戏角色还在进行打怪等动作,则可以认为是使用了外挂。复杂一些的话可以键盘鼠标钩子,来详细记录键盘鼠标的使用频率。如果游戏角色在进行打怪过程中使用键盘鼠标的频率低于某个阀值,可以判断为使用了外挂程序。

1)GetLastInputInfo

    //检测输入是否空闲
    LASTINPUTINFO inputInfo;
    inputInfo.cbSize = sizeof(LASTINPUTINFO);
    GetLastInputInfo(&inputInfo);
    DWORD timenow = GetTickCount();
    if(timenow- inputInfo.dwTime > 5000){ //超过五秒就算空闲
        outfile<<", INPUT IDLE";
    } else{
        outfile<<", INPUT BUSY";
    } 2)键盘鼠标钩子

可以安装WH_CBT钩子,或者同时安装WH_MOUSE_LL和WH_KEYBOARD_LL钩子:

WH_CBT 在以下事件之前,系统都会调用WH_CBT Hook子程,这些事件包括:

  1. 激活,建立,销毁,最小化,最大化,移动,改变尺寸等窗口事件;
  2. 完成系统指令;
  3. 来自系统消息队列中的移动鼠标,键盘事件;
  4. 设置输入焦点事件;
  5. 同步系统消息队列事件。

如何屏蔽系统低级键? Hook子程的返回值确定系统是否允许或者防止这些操作中的一个。 在windows中,通常只有很少的方法能够中断一些系统事件.我们首先考虑的机制是一个hook,因为微软给hook提供了全面的支持,它也存在于系统中,这样他能够中断某种事件.假如hook部工作的话,那么我考虑API hook. 微软并不想正式的支持API hook,所以如果可能的话,我会尽量的避免使用API hook.幸运的是,这个特别的问题可以通过设置hook来解决.在window NT 4.0 Service Pack 3时候,微软为系统增加了一个低级的键盘hook,WH_KEYBOARD_LL..通常,高级的键盘hook,WH_KEYBOARD,是在一个线程的消息队列中被移走的时候截获的.WH_KEYBOARD hook比大多数的应用程序的优先级要高.然而,有一些击键并没有直接发送到线程的消息队列中. Ctrl+Esc,Alt+Tab就是很好的例子.这些击键在系统的raw输入线程中进行内部处理.由于应用程序不能接收到这些消息,所以应用程序没有办法截获到它们,保护正常的进程.这种行为是为了用户能够切换到另外一个应用程序,不管应用程序的线程已经进入循环,或者挂起. 当然,只有很少的应用程序真正的需要截获这些消息.为了适应这些应用程序,微软介绍了一种WH_KEYBOARD_LL hook.这个hook将被用于用户输入后,系统接收到它们之前进行处理.但是这个hook又一个严重的缺点:容易引起无限循环或者挂起. 假如这样发生了,系统就不能正确的处理击键消息了. 为了减轻这种痛苦,微软放了一个时间限制在这个hook上面. 当系统发送一个通知给一个低级键盘hook的过滤函数时,系统给这个函数一定的时间去执行.假如在允许时间内没有返回的话,系统将忽略它.并进行正常处理.这个时间通过LowLevelHooksTimeout值来实现(HKEY_CURRENT_USER\Control Panel\Desktop )

参考资料:

http://www.123flashchat.com/community/swfkit-support/2213-detecting-if-monitor-off.html

HOOK技巧 - 常用消息类型

http://www.cnblogs.com/oplusx/archive/2009/10/22/1588275.html

http://www.cnblogs.com/oplusx/archive/2009/09/14/1566410.html

http://www.cnblogs.com/oplusx/archive/2009/10/25/1589585.html

利用窗口特征检测外挂

获得窗口并枚举其子窗口

可以调用函数FindWindow(窗口类名,窗口标题)获得窗口的句柄,然后调用EnumChildWindows(父窗口,回调函数名,参数)来获得父窗口下的子窗口的句柄,代码实现如下 Code #include BOOL CALLBACK EnumChildProc(HWND hWnd,LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) { char className[]=”notepad”; HWND hWnd=::FindWindow(className,NULL); if(hWnd) { ::EnumChildWindows(hWnd,EnumChildProc,0); return 0; } MessageBox(NULL,”fail!”,”fail”,MB_OK); return 0; } BOOL CALLBACK EnumChildProc(HWND hWnd,LPARAM lParam) { char temp1[256],temp2[256]; ::GetWindowText(hWnd,temp1,255); wsprintf(temp2,”hwnd:%x text: %s”,hWnd,temp1); MessageBox(NULL,temp2,”cwnd”,MB_OK); return true;

}

获得这些句柄以后就可以为所欲为了,能做的事如下: FindWindow 按类名或窗口名(Caption)查找一个窗口 FindWindowEx 类似于FindWindow提供了更多的功能 GetLastActivePopup 针对指定的窗口,取回上一个活动的弹出式窗口的句柄 GetParent 获得指定窗口父窗口的句柄 GetTopWindow 获得指定窗口的第一个子窗口的句柄 GetWindow 如给定一个窗口句柄,该函数能取回具有特定关系的另一个窗口的句柄。如,第一个子窗口、父窗口或窗口列表内的上一个或下一个窗口。 SetParent 改变任何窗口的父窗口。 BringWindowToTop 使指定的窗口进入可见窗口列表的顶部,如它被部分或全部隐藏,则令其全部可见。同时,该窗口成为当前活动窗口。只有从前台线程调用时,才生效。 ChildWindowFromPoint 在规定的坐标取得某子窗口的句柄(如果有的话),这儿的坐标是指相对于父窗口的客户区坐标。 ChildWindowFromPointEx 与ChildWindowFromPoint相同,功能更强。 ClientToScreen 判断指定点在窗口客户区内的屏幕坐标。 GetClientRect 获得对窗口客户区进行表述的一个矩形(RECT)。这是以像素为单位判断客户区大小的一个简便的方法。 GetWindowPlacement 获得指定窗口的一个WINDOWPLACEMENT结构。该结构说明了窗口的状态。 GetWindowRect 用于获得一个矩形(RECT)结构,它描述了窗体在屏幕坐标系统中的位置。 MapWindowPoints 对某窗口客户区坐标内的一个或多个点进行转换,用另一窗口的客户区坐标表示。 MoveWindow 移动指定窗口的位置,并能改变它的大小。 OpenIcon 将一个最小化窗口恢复为原始状态。 ScreenToClient 针对屏幕内一个指定的点,用某个特定窗口内的客户区坐标表示它。 SetWindowsPos 更改窗口的位置和大小,并能修改它在内部窗口列表内的位置(这个列表起着控制窗口先是顺序)。 SetWindowPlacement 在一个WINDOWPLACEMENT结构的基础上,设置某窗口的特征。该结构描述了窗口的状态,以及它在最小化、最大化或正常显示时的位置。 WindowFromPoint 根据屏幕上一个指定的点,判断哪个窗口正位于它的下面。 GetClassInfo 取得指定窗口的类信息结构 GetClassInfoEx 效果类似于GetClassInfo,但增加了一些功能 GetClassLong,GetClassWord 用于获取窗口类信息 SetClassLong,SetClassWord 用于设置窗口类信息 GetClassName 获取窗口类名 GetDesktopWindow 获取整个桌面(屏幕)的窗口句柄 GetWindowLong,GetWindowWord 获取与窗口有关的信息 SetWindowLong,SetWindowWord 设置与窗口有关的信息 GetWindowText 获得窗口文本。它的效果大致等价于窗体或控件的Text属性 GetWindowTextLength 获得窗口文本的长度,用字符数表示。 IsChild 判断某窗口是否为另一窗口的子窗口或从属窗口。 IsIconic 判断某窗口是否处于最小化状态 IsWindow 判断指定的句柄是否为窗口句柄。 IsWindowEnabled 判断指定的窗口是否处于活动状态。 IsWindowVisible 判断某窗口是否可见。 IsZoomed 判断窗口是否处于最大化状态。 SetWindowText 设置窗口文本。大致等价于窗体或控件的Text属性。 AnyPopup 判断是否存在可见的弹出式窗口 CascadeWindows 令窗口在一个父窗口内层叠显示 CloseWindow 对指定的窗口进行最小化处理(如果它是个钉级窗口)对弹出式及子窗口无效 DestroyWindow 清除指定的窗口以及下属所有子窗口与包容窗口 DrawAnimatedRects 获得窗口打开或关闭的动画效果 EnableWindow 激活或屏蔽(禁用)指定窗口 FlashWindow 令指定窗口的标题闪烁显示 GetUpdateRect 判断需要更新的那个窗口的位置 GetWindowContextHelpId 取得与窗口关联在一起的帮助场景 InvalidateRect 指定窗口内需要更新的全部或部分客户区 IsWindowUnicode 判断一个窗口是否期望文本消息采用Unicode格式 LockWindowUpdate 允许或禁止描绘指定的窗口 RedrawWindow 一个功能强大的函数,用于控制全部或部分窗口重画 ScrollWindow,ScrollWindowEx 滚动显示窗口的全部或部分客户区 SetWindowContextHelpId 设置与窗口关联在一起的帮助场景 ShowOwnedPopups 隐藏或显示从属于指定窗口的所有保容弹出窗口 ShowWindow 用于设置窗口的状态,其中包括窗口的隐藏、显示、最小化、最大化以及激活等 ShowWindowAsync 类似于ShowWindow,增加了对其他进程内的窗口进行操作的能力 TileWindows 令窗口在一个父窗口内平铺显示 UpdateWindow 立即更新窗口内需要更新的任何部分 ValidateRect 指出全部或部分矩形已经更新,毋需再更新

文档信息

Search

    Table of Contents