[原创]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);
}
