zoukankan      html  css  js  c++  java
  • 内联挂钩API

    内联挂钩API原理在于用JMP指令替换目标函数地址的前几个字节,当程序运行到这里就JMP到自己的函数中.需要注意的是自己的函数和目标函数的调用规范、参数、返回值都要一致以保持堆栈平衡.

    /*
    * 通过修改函数开始的指令,使函数执行跳到指定函数来达到拦截API的目的
    * 跳转的新函数的调用规范必须和要拦截的函数一致
    */
    class  CAPIHook
    {
    private:
        BOOL  m_bAllowHook;  
    //是否允许拦截
        PROC  m_pfnOld;   //保存要替换的函数地址
        BYTE   m_byNew[8];  //保存替换前8个字节的值
        BYTE   m_byOld[8];    //保存替换前的函数前8个字节

        BOOL  InitHookData( PROC pfnOld, PROC pfnNew )
        {
            ATLASSERT( ( pfnOld 
    != NULL ) && ( pfnNew != NULL ) );

            
    // mov eax, [新地址]             --机器码为: B8  [地址值]
            
    // jmp  eax                             --机器码为: FF E0
            BYTE  byNew[8]  =  { 0xB80x000x000x000x000xFF0xE00x00 };
            memcpy( m_byNew, byNew, _countof( byNew ) );  
            
    *(DWORD*)( m_byNew + 1 )  =  (DWORD)pfnNew;  //将新函数地址填充到2、3、4、5字节

            m_pfnOld  
    =  pfnOld;
            
    if( m_pfnOld == NULL )
                
    return FALSE;

            memcpy( m_byOld, m_pfnOld, _countof(m_byOld) );

            
    return TRUE;
        }

    public:
        CAPIHook()
        {
            m_bAllowHook  
    =  FALSE;
        }

        CAPIHook( PROC pfnOld,  PROC pfnNew )
        {
            
    this->HookAPI( pfnOld, pfnNew );
        }

        CAPIHook( LPCTSTR lpszModName, LPCSTR lpszFunName, PROC pfnNew )
        {
            
    this->HookAPI( lpszModName, lpszFunName, pfnNew );
        }

        
    /*
        * 拦截API,传入要拦截的源函数地址和自指定的函数地址
        * pfnOld:源函数地址
        * pfnNew:自指定的函数地址
        
    */
        BOOL  HookAPI( PROC pfnOld,  PROC pfnNew )
        {
            
    return m_bAllowHook  =  this->InitHookData( pfnOld, pfnNew );
        }

        
    /*
        * 拦截API,传入要拦截的源函数的模块句柄和函数名称和自指定的函数地址
        * lpszModName:源函数所在的模块句柄
        * lpszFunName:源函数名称
        * pfnNew:自指定的函数地址
        
    */
        BOOL  HookAPI(  LPCTSTR lpszModName, LPCSTR lpszFunName, PROC pfnNew  )
        {
            HMODULE  hMod  
    =  ::GetModuleHandle( lpszModName ) ;
            
    if( hMod == NULL )
                hMod  
    =  ::LoadLibrary( lpszModName );

            
    if( hMod == NULL )
                
    return  m_bAllowHook = FALSE;

            PROC  pfnOld  
    =  (PROC)::GetProcAddress( hMod, lpszFunName );
            
    if( pfnOld != NULL )
            {
                
    return  m_bAllowHook  =  this->InitHookData( pfnOld, pfnNew );
            }
        }

        
    /*
        *  拦截,用构造好的JMP指令替换函数开始处的几个字节
        
    */
        BOOL  StartHook()
        {
            
    if!m_bAllowHook )
                
    return FALSE;

            
    //首先修改虚拟内存属性,使之可读写,之后再把跳转指令写入
            DWORD  dwOldProtect(0);
            BOOL  bRet 
    = ::VirtualProtect( (LPVOID)m_pfnOld,  _countof(m_byOld), PAGE_READWRITE, &dwOldProtect );
            bRet  
    =  bRet && ::WriteProcessMemory( ::GetCurrentProcess(), (LPVOID)m_pfnOld, m_byNew,  _countof(m_byNew), NULL );
            bRet  
    =  bRet && ::VirtualProtect( (LPVOID)m_pfnOld,  _countof(m_byOld), dwOldProtect, NULL );
            
    return bRet;
        }

        
    /*
        * 取消拦截,还原函数开始处被替换的字节
        
    */
        BOOL  StopHook()
        {
            
    if!m_bAllowHook )
                
    return FALSE;

            
    //首先修改虚拟内存属性,使之可读写,之后再把恢复指令写入
            DWORD  dwOldProtect(0);
            BOOL  bRet 
    = ::VirtualProtect( (LPVOID)m_pfnOld,  _countof(m_byOld), PAGE_READWRITE, &dwOldProtect );
            bRet  
    =  bRet && ::WriteProcessMemory( ::GetCurrentProcess(), (LPVOID)m_pfnOld, m_byOld,  _countof(m_byOld), NULL );
            bRet  
    =  bRet && ::VirtualProtect( (LPVOID)m_pfnOld,  _countof(m_byOld), dwOldProtect, NULL );
            
    return bRet;
        }
    };

    挂接示例:

    int WINAPI MyMessageBoxA(  HWND hWnd,   LPCTSTR lpText,   LPCTSTR lpCaption,   UINT uType );

    CAPIHook  apiHook( (PROC)MessageBoxA, (PROC)MyMessageBoxA );
    apiHook.StartHook();

    int WINAPI MyMessageBoxA(  HWND hWnd,   LPCSTR lpText,   LPCSTR lpCaption,   UINT uType )
    {
        CString str;
        str.Format(
    "fangkm_%s", lpText );
        apiHook.StopHook();
        
    int nRet = MessageBoxA( hWnd, str, lpCaption, uType);
        apiHook.StartHook();
        
    return nRet;
    }
  • 相关阅读:
    js作用域链
    函数声明提升
    18年年终总结之谈谈焦虑这件事
    混合开发中ios兼容问题
    vue 缓存的keepalive页面刷新数据
    vue里监听安卓的物理返回键
    vue根据数组对象中某个唯一标识去重
    Sublime Text3 插件
    全面理解Javascript闭包和闭包的几种写法及用途
    javascript深入理解js闭包
  • 原文地址:https://www.cnblogs.com/fangkm/p/1555912.html
Copyright © 2011-2022 走看看