欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]Inline hook中继函数通用汇编宏

[原创]Inline hook中继函数通用汇编宏

标 题:【原创】Inline hook中继函数通用汇编宏

大神们都在讲解如何hook,我就不讲hook了,分享一个hook中经常见到,却又被大家忽视的东西:中继函数。
大家都知道在hook的时候需要一个中继函数,通常是一个naked的嵌入汇编函数,目的是为了作为一个桥梁,执行真正的hook函数,
而大家都有感触,内容都差不多,但是又不得不为每一个hook都重复的写,有时候不小心参数压错了,还会造成函数无法返回或者堆栈异常。
工欲善其事,必先利其器。
我们就先来打造一个宏,让他帮助我们自动生成中继函数,而我们就只用关心hook函数的实现即可。
先看一下宏的参数:
#define DECLARE_HOOKPROXY(proxyFunc, hookFunc, argc, shellcode)
proxyFunc:就是中继函数,当然,这里就是填入你要的中继函数的名字
hookFunc:就是你真正实现功能的hook函数咯,这里要求必须是stdcall(当然你可以改)
argc:被hook的函数参数个数,中继函数压参数以及返回的时候平衡堆栈需要这个信息
shellcode:事先构造好的一段机器码,保存了被hook掉的机器码,以及返回到原函数的一个长跳转(注意内存要有执行属性)
看具体实现前需要先注意该中继函数的适用范围:
1、Hook函数头:如果需要hook任意合适位置,需要稍微改一下宏的内容
2、Hook跳转表:我们知道有的函数call进去之后是一个jmp xxx,其实也是hook函数头
3、Hook Call xxx:把跳转地址xxx改成中继函数的地址
先用嵌入汇编的函数来看一下实现的功能:
void __declspec(naked) proxyFunc()
{
    mov     edi, edi        /* 让我们的函数看起来跟WIN API更像一点 */
    push    ebp
    mov     esp, ebp
    push    ebx
    mov     eax, argc        /* 取参数个数 */
    add     eax, 1           /* 加1是为了跳过返回地址,如果hook的不是上边提到的位置 */
                             /* 那就需要自己去计算应该跳过多少堆栈数据,修改这里 */
    jmp     l2
l1:
    lea     ebx, [ebp + eax * 4]  /* 这里取的是参数的地址,目的是能够修改参数 */
    push    ebx                   /* 例如让MessageBox改成显示"Hook..." */
    sub     eax, 1
l2:
    cmp     eax, 1
    jne     l1
    call    hookFunc              /* 参数压好了,该干嘛干嘛去吧 */
    pop     ebx
    mov     esp, ebp
    pop     ebp                   /* 恢复堆栈,注意不需要平衡esp */
    cmp     eax, 0x4E52454B       /* MAGIC: 如果hook函数返回的值不是这个,*/
                                  /* 就将作为该API调用的返回值,我叫这个为GOON */
    je      l3                    /* 如果是MAGIC,就跳到shellcode继续执行原函数 */
    ret     argc * 4              /* 标准WIN API是stdcall的,需要我们平衡堆栈 */
l3:
    jmp     offset shellcode      /* 注意这里是取offset,千万不要在宏里边用高级语言的符号 */
}
差不多OK了,来看一下宏汇编,大体上差不多,只是一些跳转需要硬编码:
#define DECLARE_HOOKPROXY(proxyFunc, hookFunc, argc, shellcode) \
void __declspec(naked) proxyFunc() \
{ \
    _asm mov    edi, edi \
    _asm push   ebp \
    _asm mov    ebp, esp \
    _asm push   ebx \
    _asm mov    eax, argc \
    _asm add    eax, 1 \
    _asm _emit  0xEB \
    _asm _emit  0x08 \
    _asm lea    ebx, [ebp + eax * 4] \
    _asm push   ebx \
    _asm sub    eax, 1 \
    _asm cmp    eax, 1 \
    _asm _emit  0x75 \
    _asm _emit  0xF3 \
    _asm call   hookFunc \
    _asm pop    ebx \
    _asm mov    esp, ebp \
    _asm pop    ebp \
    _asm cmp    eax, 0x4E52454B \
    _asm _emit  0x74 \
    _asm _emit  0x03 \
    _asm ret    argc * 4 \
    _asm jmp    offset shellcode \
}
举个例子,中继函数proxyMessageBox就直接声明一下就OK了,是不是佷方便?
#define HOOKAPI     unsigned int __stdcall
#define GOON        0x4E52454B
HOOKAPI hookMessageBox(
  HWND *hWnd,          // handle to owner window
  LPCTSTR *lpText,     // text in message box
  LPCTSTR *lpCaption,  // message box title
  UINT *uType          // message box style
)
{
    *lpText = "Hook";
    return GOON;
}
RET_SHELLCODE scMessageBox;
DECLARE_HOOKPROXY(proxyMessageBox, hookMessageBox, 5, scMessageBox);
void main()
{
    /* 这个函数作用当然就是保存函数头,构造shellcode,然后hook掉 */
    HookApiHeader(MessageBox, proxyMessageBox, 5, &scMessageBox);
    MessageBox(NULL, "TEST", "TEST", MB_OK);
}

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功