阻止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++再也捕捉不到界面的任何東西了.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM