zoukankan      html  css  js  c++  java
  • 阻止SPY++类似的程序捕捉软件窗口

    我以前用Spy++能轻易捕捉360软件界面,除了一些应用DHTML制作的窗体.昨天我再用Spy++捕捉的时候捕捉不到了,甚至连最外围的对话框都捕捉不到,显然是做了类似拦截API的处理.下面我也模拟一下这种效果,让自己的程序窗口不能被捕捉.
    Spy++之类的程序一般通过API函数WindowFromPoint和ChildWindowFromPoint来获取指定位置的窗口句柄。拦截一下WindowFromPoint函数,如果捕捉到的是自己程序的窗口,而且实施捕捉的进程不是自己程序的进程,那就直接返回NULL(这样自己的程序捕捉自己的窗口就不会受影响).拦截API我直接用微软的Detour库,使用起来方便.
    由于是拦截所有进程地址空间的WindowFromPoint函数,我借助于全局WH_SHELL钩子,因此拦截操作放在一单独的DLL项目中.先封装一下Detour操作CInterceptSpyFun类:
    ////////////////////h文件///////////////////////////

    class CInterceptSpyFun
    {
    private:
        //是否已经拦截
        BOOL  m_bIntercepted;
    
    public:
        //保存要屏蔽WindowFromPoint函数的进程ID
        static  DWORD  m_dwValidProcessID;  
    
    public:
        CInterceptSpyFun( );
        ~CInterceptSpyFun( );
    
        BOOL  IsIntercepted() 
        {
            return this->m_bIntercepted;
        }
    
        /*
        * 拦截操作
        * dwValidProcessID: 待屏蔽WindowFromPoint函数的进程ID
        * 返回拦截成功与否
        */
        BOOL  Intercept( DWORD dwValidProcessID  );
    
        /*
        * 取消拦截,还原成原先的操作
        */
        void    UnIntercept();
    };

    ///////////////////////////cpp////////////////////////////

    DWORD  CInterceptSpyFun::m_dwValidProcessID   =  0;
    
    //让Real_WindowFromPoint指针指向实际上的WindowFromPoint函数地址
    DETOUR_TRAMPOLINE( HWND WINAPI Real_WindowFromPoint( POINT pt ), WindowFromPoint );
    
    /*
    * 自定义WindowFromPoint函数的处理
    */
    HWND WINAPI Mine_WindowFromPoint( POINT pt )
    {
        //调用实际上的WindowFromPoint函数,取得窗口句柄
        HWND  hWnd =  Real_WindowFromPoint( pt );
    
        //获取窗口所属的进程ID
        DWORD  dwProcessID(0);
        ::GetWindowThreadProcessId( hWnd, &dwProcessID );
    
        if( ( CInterceptSpyFun::m_dwValidProcessID == dwProcessID ) && ( ::GetCurrentProcessId() != CInterceptSpyFun::m_dwValidProcessID ) )
        {    //如果窗口属于指定的进程并且是被不是指定进程的其他进程调用WindowFromPoint访问时,返回NULL
            return NULL;
        }
    
        return hWnd;
    }
    
    
    
    CInterceptSpyFun::CInterceptSpyFun( )
    {
        m_bIntercepted  =  FALSE;
    }
    
    CInterceptSpyFun::~CInterceptSpyFun( )
    {
    }
    
    BOOL  CInterceptSpyFun::Intercept( DWORD dwValidProcessID )
    {
        CInterceptSpyFun::m_dwValidProcessID   =  dwValidProcessID;
        //Detour库拦截处理
        m_bIntercepted  =  DetourFunctionWithTrampoline( (PBYTE)Real_WindowFromPoint,  (PBYTE)Mine_WindowFromPoint );
        return m_bIntercepted;
    }
    
    void    CInterceptSpyFun::UnIntercept()
    {
        if( m_bIntercepted )
        {
            //取消拦截
            DetourRemove( (PBYTE)Real_WindowFromPoint,(PBYTE)Mine_WindowFromPoint );
            m_bIntercepted  =  FALSE;
        }
    }

    dwValidProcessID(要拦截WindowFromPoint函数的进程ID)需要在LoadLibrary之后,安装钩子之前传递,并且需要保存到共享节中以达到在所有的进程中数据共享的目的. 
    #pragma  data_seg(".unspy")
    HHOOK   hHook   =   NULL;  
    DWORD  dwValidProcessID  =  0;
    #pragma  data_seg()
    #pragma comment(linker,"/section:.unspy,rws")

    HOOK句柄和dwValidProcessID  都保存到共享节”.unspy”中。

    设置dwValidProcessID  的导出函数:
    extern"C" __declspec( dllexport ) void SetValidProcessID( DWORD  dwProcessID )
    {
     dwValidProcessID   =  dwProcessID;
    }

    声明拦截类的全局变量:
    CInterceptSpyFun  interceptSpy;  
    HMODULE   hDllModule   =  NULL;  //保存DLL模块句柄

    SHELL钩子处理:

    LRESULT CALLBACK CustomShellProc (int nCode, WPARAM wParam, LPARAM lParam)
    {    
        if( !interceptSpy.IsIntercepted() )
        {  //拦截API
            interceptSpy.Intercept( dwValidProcessID );
        }
    
        return ::CallNextHookEx( hHook, nCode, wParam, lParam );
    }
    
    
    extern"C" __declspec( dllexport ) void InstallHook( )
    {
        hHook = ::SetWindowsHookEx( WH_SHELL , CustomShellProc ,(HINSTANCE)hDllModule, 0 );
    }
    
    extern"C" __declspec( dllexport ) void UninstallHook()
    {    
        if( hHook != NULL )
        {
            ::UnhookWindowsHookEx( hHook );
        }
        hHook = NULL;
    }

    取消拦截操作应在卸载DLL的时候:

    BOOL APIENTRY DllMain( HMODULE hModule,  DWORD  ul_reason_for_call,   LPVOID lpReserved  )
    {
     hDllModule   =   hModule;
     switch (ul_reason_for_call)
     {
     case DLL_PROCESS_ATTACH: 
      break;
     case DLL_THREAD_ATTACH:
      break;
     case DLL_THREAD_DETACH:
      break;
     case DLL_PROCESS_DETACH:
      {
          interceptSpy.UnIntercept();
      }
      break;
     }
    
        return TRUE;
    }

    至此,DLL部分已经完成.在需要屏蔽WindowFromPoint函数的程序中需加载该DLL,调用DLL的SetValidProcessID,将当前的进程ID传入,随后安装钩子:

    m_hInstance  = ::LoadLibrary(_T("AvoidSpyLib.dll"));
      if ( m_hInstance == NULL )
      {
       ::MessageBox(NULL,_T("LoadLibrary Failed"),_T(""),MB_OK);
      }
    
      if( m_hInstance == NULL )
       return 0;
     
      typedef void (*PSetValidProcessID)( DWORD  dwProcessID );
      PSetValidProcessID pSetFunc;
      pSetFunc = (PSetValidProcessID)::GetProcAddress( m_hInstance , "SetValidProcessID");
      if ( pSetFunc != NULL )
      {
       (*pSetFunc)( ::GetCurrentProcessId() );
      }
    
      typedef void (*PInstallHook)( );
      PInstallHook pInstallFunc;
      pInstallFunc = (PInstallHook)::GetProcAddress( m_hInstance , "InstallHook");
      if ( pInstallFunc != NULL )
      {
        (*pInstallFunc)();
    }
    //卸载钩子
    if( m_hInstance != NULL )
    {
       typedef void (*PUninstallHook)( );
       PUninstallHook pFunc;
       pFunc = (PUninstallHook)::GetProcAddress( m_hInstance , "UninstallHook");
       if ( pFunc != NULL )
       {
        (*pFunc)();
       }
    
       ::FreeLibrary( m_hInstance );
    }

    全部完工,运行了一下,呵呵,和360软件的效果一样,Spy++再也捕捉不到界面的任何东西了.

  • 相关阅读:
    bzoj1059: [ZJOI2007]矩阵游戏
    NEW
    bzoj2438: [中山市选2011]杀人游戏
    bzoj4554: [Tjoi2016&Heoi2016]游戏 二分图匹配
    【高精度】模板 (C++)
    【BZOJ4025】二分图 LCT
    读入/输出模板
    一些 Markdown 语法
    题解 P3732 [HAOI2017]供给侧改革
    题解 CF1598A Computer Game
  • 原文地址:https://www.cnblogs.com/qintangtao/p/3521259.html
Copyright © 2011-2022 走看看