前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PE文件和COFF文件格式分析——导出表的应用——一种摘掉Inline钩子(Unhook)的方法

PE文件和COFF文件格式分析——导出表的应用——一种摘掉Inline钩子(Unhook)的方法

作者头像
方亮
发布2019-01-16 11:02:39
8900
发布2019-01-16 11:02:39
举报
文章被收录于专栏:方亮

        在日常应用中,某些程序往往会被第三方程序下钩子(hook)。如果被下钩子的进程是我们的进程,并且第三方钩子严重影响了我们的逻辑和流程,我们就需要把这些钩子摘掉(Unhook)。本件讲述一种在32位系统上,如何摘掉API钩子的思路和方法。(转载请指明来源于breaksoftware的CSDN博客)

        Hook的相应介绍已经很多了,如果对这个技术不是很了解的,可以先搜索下了解下。

        一般来说,我们比较熟悉的函数的起始指令是:

代码语言:javascript
复制
push        ebp  
mov         ebp,esp 

        这两条指令是为了保存前一个函数的栈基址,并将本函数的栈顶指针保存到ebp寄存器中。这样的设计是非常有意义的,在windows平台上,栈的扩展方向是从大端到小端,即由高地址向低地址扩展以申请更大的栈空间。esp则指向栈顶,然而栈顶会根据栈申请和释放而变化,所以如果以esp作为基址来计算变量的位置,将导致一会儿[esp-10]代表变量A,一会儿[esp-20]代表变量A。

       虽然这样的结构有种种好处,但是这个肯定不是必须的。所以函数的起始地址指令是不确定的。这儿之所以说这么一大堆,是想说明,Hook库对不同的API进行Hook的方式是不同的。有的是修改函数入口地址的代码,比如上面的入口地址指令可以被Hook库以jmp xxxx来代替。这样就实现了API Hook。本文所讨论和实验的方法也是针对jmp型Hook。

        我们以CreateProcessInternalW函数为例,我们看下其汇编代码:

代码语言:javascript
复制
_CreateProcessInternalW@48:
77023BBB  push        654h  
77023BC0  push        77024968h  
77023BC5  call        __SEH_prolog4_GS (7701415Ch)  

        我们使用Hook库下钩子,可以发现其代码变成:

代码语言:javascript
复制
_CreateProcessInternalW@48:
77023BBB  jmp         HookApiByDectours::Mine_CreateProcessInternalW (0A927E0h)  
77023BC0  push        77024968h  
77023BC5  call        __SEH_prolog4_GS (7701415Ch)  

        我们的思路很简单,就是——以其人之道还治其人之身。

        我将从被Hook函数的PE文件中,读取原来的代码,然后和现在内存中的代码做对比。如果不同,则被hook,并将不同的地方改成PE文件中的函数代码。其中涉及的PE知识可以参考《PE文件和COFF文件格式分析》。其中最需要关注的是《PE文件和COFF文件格式分析——导出表》,该文讲述了如何从PE文件中获取代码地址的方法。

        具体的替换代码是:

代码语言:javascript
复制
BOOL CUnHookDllFunc::UnHook()
{
    BOOL bSuc = FALSE;

    do {
        LPBYTE lpFunStart = m_lpStart + m_dwRA;

        HMODULE hModule = GetModuleHandleA(m_strDllPath.c_str());
        if ( NULL == hModule ) {
            break;
        }

        LPBYTE lpOriFuncAddr = (LPBYTE)hModule + m_dwRVA;
        DWORD dwModifyCount = 0;
        for ( int n = 0; n < MAXCOMPCOUNT; n++ ) {
            if ( *(lpOriFuncAddr + n) != *(lpFunStart + n) ) {
                dwModifyCount++;
            }
        }

        if ( dwModifyCount == 0 ) {
            bSuc = TRUE;
        }
        else if ( dwModifyCount == MAXCOMPCOUNT ) {
            // 超过则认为不支持
            break;
        }
        else {
            DWORD dwOldPro = 0;
            if ( FALSE == VirtualProtect(lpOriFuncAddr, dwModifyCount, PAGE_EXECUTE_READWRITE, &dwOldPro )) {
                DWORD dwLastErr = GetLastError();
                break;
            }

            for ( DWORD dwIndex = 0; dwIndex < dwModifyCount; dwIndex++ ) {
                *(lpOriFuncAddr + dwIndex) = *(lpFunStart + dwIndex);
            }

            VirtualProtect(lpOriFuncAddr, dwModifyCount, dwOldPro, &dwOldPro);
            bSuc = TRUE;
        }

    } while (0);
     
    return bSuc;
}

最后附上测试工程。其Hook了和UnHook的状态如下图。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2014年04月21日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档