当设置HOOK时,如何保存那些函数的起始6 个字节?当取消HOOK时,如何从保存的数据中找到某个函数的起始6个字节?解决这个问题,可以用一个结构体数组来实现,结构体中包含源函数地址、源函数起始位置的6个字节数据等内容。HOOK管理结构体设计如下。
    typedef struct APIHOOKDATA_st {
    DWORD dwSrcFuncAddr; /* 源函数的地址 */
    DWORD dwNewFuncAddr; /* 钩子函数的地址 */
    BYTE byHeaderCode[6]; /* 源函数起始6字节 */
    WORD wFlag; /* 用来表示是否设置了HOOK的标志 */
    } APIHOOKDATA;
    typedef struct APIHOOK_st {
    APIHOOKDATA *pHookData;
    UINT uMaxFunctions;
    } APIHOOK;    APIHOOKDATA结构体用来记录单个函数的HOOK数据,APIHOOK结构体用来管理多个函数的HOOK,里面包含一个APIHOOKDATA结构体数组,uMaxFunctions是数组的长度,表示最多可以HOOK的函数个数。    1. 多个函数的HOOK管理    对多个函数的HOOK管理可以分为以下四个操作步骤。
    ① 初始化;
    ② 设置某个函数的HOOK;
    ③ 取消某个函数的HOOK;
    ④ 关闭。    下面以Windows NT系列操作系统为例来实现以上四个操作的代码。初始化操作主要是为结构体分配内存,将整个数组清零。编码如下。
    /** ApiHook 模块初始化函数
    @param INT nMaxHookFuncCounts——最大可设置的钩子数量
    @return INT (by default) ——返回NULL 表示失败
    */
    HANDLE ApiHook_Init(UINT uMaxFunctions)
    {
        APIHOOK * pApiHook = (APIHOOK *)malloc(sizeof(APIHOOK));
        if ( pApiHook )
        {
            pApiHook->uMaxFunctions = uMaxFunctions;
            pApiHook->pHookData =
            (APIHOOKDATA *)malloc(sizeof(APIHOOKDATA) *uMaxFunctions);
            if ( NULL != pApiHook->pHookData)
            {
                memset(pApiHook->pHookData,0,sizeof(APIHOOKDATA) *uMaxFunctions );
                return (HANDLE)pApiHook;
            }
            free(pApiHook);
        }
    return NULL;
    }    2. 设置HOOK操作    设置某个函数的HOOK操作主要是在数组中查找未使用的节点,将源函数相关信息保存到节点中,修改源函数起始位置的几个字节为一条跳转到钩子函数的指令。
    /** 通过地址来设置某个函数的钩子函数
    @param HANDLE hApiHook——由ApiHook_Init()函数生成的句柄
    @param DWORD dwSrcFuncAddr——源函数地址
    @param DWORD dwNewFuncAddr——钩子函数地址
    @return INT (by default) ——返回-1表示失败;返回0表示在HOOK数组中的序号
    */
INT ApiHook_SetByAddr(HANDLE hApiHook,DWORD dwSrcFuncAddr,DWORD dwNewFuncAddr)
    { 
        DWORD dwOldProtect; 
        DWORD dwNewProtect; 
        DWORD lpSrcFunc; 
        DWORD lppNewFunc; 
        UINT i; 
        INT nAlreadyFlag = 0; 
        if ( NULL == hApiHook ) 
        { 
            return-1; 
        } 
        APIHOOK *pApiHook = (APIHOOK *)hApiHook; 
        lpSrcFunc = dwSrcFuncAddr; 
        /* 查找是否已设置了钩子 */ 
        for ( i = 0; i < pApiHook->uMaxFunctions; i++ ) 
        { 
            if ( pApiHook->pHookData[i].dwSrcFuncAddr == lpSrcFunc ) 
            { 
                /* 如果已经设置了钩子,仅仅改变 */ 
                nAlreadyFlag = 1; 
                break; 
            } 
        } 
        /* 如果没有设置源函数的钩子函数,在表中找出一个可供记录的位置 */ 
        if ( i == pApiHook->uMaxFunctions ) 
        { 
            for ( i = 0; i < pApiHook->uMaxFunctions; i++ ) 
            { 
                if (pApiHook->pHookData[i].wFlag == 0 ) 
                { 
                    break; 
                } 
            } 
        if ( i == pApiHook->uMaxFunctions ) 
        { 
            return-1; 
        }
    }
    /* 将新的钩子函数地址记录到表中 */
    pApiHook->pHookData[i].dwNewFuncAddr = dwNewFuncAddr;
    /* 以下这段代码将源函数头部6个字节保存到表中 */
    lppNewFunc = (DWORD)(&(pApiHook->pHookData[i].dwNewFuncAddr) );
    if ( !nAlreadyFlag )
    { 
        /* 将源函数起始处6个字节保存到 byHeaderCode.中 */ 
        memcpy( pApiHook->pHookData[i].byHeaderCode,(const void *)lpSrcFunc,6);
    }
    /* 以下这段代码将源函数首部6个字节改成为一条跳转到新函数地址的指令 */
    if ( VirtualProtect( (LPVOID)lpSrcFunc,6, PAGE_EXECUTE_READWRITE,&dwOldProtect ) == 0 )
    { 
        return-1;
    }
    *(unsigned char *)lpSrcFunc = (unsigned char)0xff;
    *(((unsigned char *)lpSrcFunc)+1) = (unsigned char)0x25;
    memcpy( (void *)(lpSrcFunc+2),(const void *)&lppNewFunc,4 );
    if ( VirtualProtect( (LPVOID)lpSrcFunc,6,dwOldProtect, &dwNewProtect) == 0 )
    { 
        return-1;
    };
    pApiHook->pHookData[i].wFlag = 1;
    pApiHook->pHookData[i].dwSrcFuncAddr = lpSrcFunc;
    return (INT)i;
    }
3. 取消HOOK操作    取消某个函数的HOOK操作和设置操作相反,主要是在数组中查到要操作的函数的相关记录信息,将源函数起始位置处的6个字节恢复,清除数组中的对应记录信息。编码如下。    /** 取消某个函数的钩子函数设置
    @param HANDLE hApiHook——由ApiHook_Init()函数生成的句柄 
    @param DWORD dwSrcFuncAddr——源函数地址
    @return INT (by default) ——返回-1表示失败;返回0表示在HOOK数组中的序号
    */
    INT ApiHook_UnSetByAddr(HANDLE hApiHook,DWORD dwSrcFuncAddr)
    { 
        UINT i; 
        DWORD dwOldProtect; 
        DWORD dwNewProtect; 
        DWORD lpSrcFunc; 
        APIHOOK *pApiHook = (APIHOOK *)hApiHook; 
        if ( NULL == hApiHook ) 
        { 
            return-1; 
        } 
        for ( i = 0; i < pApiHook->uMaxFunctions; i++ ) 
        { 
            if ( pApiHook->pHookData[i].dwSrcFuncAddr == dwSrcFuncAddr ) 
            { 
                break; 
            } 
        } 
        if ( i == pApiHook->uMaxFunctions ) 
        { 
            return-1; 
        } 
        lpSrcFunc = pApiHook->pHookData[i].dwSrcFuncAddr; 
        /* 将lpSrcFunc指向的内存属性修改为可以读写的 */ 
        if ( VirtualProtect( ( LPVOID)lpSrcFunc,6,PAGE_EXECUTE_READWRITE,&dwOldProtect ) == 0 ) 
        { 
            return-1; 
        } 
        memcpy( (void *)lpSrcFunc,pApiHook->pHookData[i].byHeaderCode,6 ); 
        /* 恢复lpSrcFunc指向的内存属性 */ 
        if ( VirtualProtect( (LPVOID)lpSrcFunc,6,dwOldProtect,&dwNewProtect ) == 0 ) 
        { 
            return-1; 
        } 
        pApiHook->pHookData[i].wFlag = 0; 
        if ( pApiHook->pHookData[i].pszDllName ) 
        { 
            free(pApiHook->pHookData[i].pszDllName); 
            pApiHook->pHookData[i].pszDllName = NULL; 
        } 
        if ( pApiHook->pHookData[i].pszFuncName ) 
        { 
            free( pApiHook->pHookData[i].pszFuncName ); 
            pApiHook->pHookData[i].pszFuncName = NULL; 
        } 
        return (INT)i;
    }
        
       菜鸟一个,但是老师给布置作业要做多个函数的hook
       不知道怎么写成一个DLL
       还有函数具体实现什么功能也不是很清楚,能否举个例子?T  T
       救救我啊~~~~

解决方案 »

  1.   

    就是比如你要hook MessageBoxA,就先复制出来MessageBoxA开头的5个字节,保存起来,备用然后把MessageBoxA开头的5个字节改写成jmp xxxx 跳到事先准备好的myMessageBoxA里,这样调用MessageBoxA的时候就会先进入你的myMessageBoxA在myMessageBoxA里就可以做点手脚了,比如说改改参数神马的然后在myMessageBoxA里还需要调用原来的MessageBoxA,这时候就需要把MessageBoxA开头的5个字节还原成第一步保存起来的那5个字节然后调用MessageBoxA调用完之后再把MessageBoxA前5个字节改成jmp xxxxx
      

  2.   

    http://blog.csdn.net/lactoferrin/article/details/7216207