众所周知VEH hook是为了躲避CRC检测而诞生的一项技术,古老但实用,故在此总结一下关于VEH hook的几种方法
先来简单介绍一下如何添加VEH处理函数,微软开放给了我们一个API:
第一个参数为true则代表插入VEH链表头,第二个参数则是要添加的VEH处理函数
那么来讲讲常见的hook方式
这是最为常见的VEH hook方式,利用硬件断点抛出异常,在异常处理函数里判断发生异常的地址是否和hook的地址一致,如果一致,则修改EIP(RIP)跳转
缺点:容易被检测(当然也可以Hook KiUserExceptionDispatcher来清空Dr寄存器规避检测),且用户最多只能够设置4个硬件断点(Dr0~Dr3)
这里就涉及到一个问题了,咱们想要这个Hook点不止一次被触发,所以该怎么做呢?
这里给出两种方法:
a.利用单步异常
b.利用析构函数(PolyHook做法)
这是个十分巧妙的做法,利用了C++中析构函数的特性,其原理就是构造一个恢复保护的析构函数,并在你的hook函数内初始化一个类,当程序执行完后(包括返回原函数),对象销毁,析构函数执行恢复保护
这里附上大概例子,详细做法各位可以移步 PolyHook 这是个十分优秀的Hook引擎
最后是触发方法,只需:
缺点:容易被查页属性,好处就是没有动DR寄存器(emmmmmm)
将Hook点首字节修改为0xCC,网上有例子,这里不再赘述
这应该说是所有常见VEH hook方法中最为隐蔽的了,将页面修改为只读这种不可执行属性,一但执行便会触发C0000005,只需像上面一样接管他就行
但由于影响的是一整个页面,也就是说这一整个页都会产生异常,所以说一个页面不能存在多个Hook点~但是有菊花说的好,办法总比困难多,这里说一下我的思路(用来Hook模块内函数,比较无脑且垃圾,大佬勿喷)
首先遍历整个进程的模块,找出要Hook的那个函数所在的模块,获取模块的地址以及大小,然后直接新建一块同样大小的内存,然后把整个模块拷贝到这块内存内,将这块内存中的“要Hook的函数”直接Inline Hook,然后通过异常将EIP(RIP)重定向到这块内存中“要Hook的函数”(ImageBase + HookAddress_Offset),直接不走原来的函数
这种方法的缺陷呢就是太太太太慢了,而且做法非常繁琐,所以说只适合Hook某些API,如果大佬们有什么更好的方法可以不吝赐教的话,不胜感激
SuspendThread(hHookThread);
CONTEXT thread_context
=
{ CONTEXT_DEBUG_REGISTERS };
thread_context.Dr0
=
HookAddr;
thread_context.Dr7
=
0x405
;
/
/
设置线程环境 抛出异常
DWORD oldprotect;
VirtualProtect((LPVOID)HookAddr,
5
, PAGE_EXECUTE_READWRITE, &oldprotect);
SetThreadContext(hHookThread, &thread_context);
ResumeThread(hHookThread);
SuspendThread(hHookThread);
CONTEXT thread_context
=
{ CONTEXT_DEBUG_REGISTERS };
thread_context.Dr0
=
HookAddr;
thread_context.Dr7
=
0x405
;
/
/
设置线程环境 抛出异常
DWORD oldprotect;
VirtualProtect((LPVOID)HookAddr,
5
, PAGE_EXECUTE_READWRITE, &oldprotect);
SetThreadContext(hHookThread, &thread_context);
ResumeThread(hHookThread);
LONG
NTAPI ExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo)
{
/
/
判断当前异常码是否为硬件断点异常
if
(ExceptionInfo
-
>ExceptionRecord
-
>ExceptionCode
=
=
EXCEPTION_SINGLE_STEP)
{
/
/
判断hook地址
if
(ExceptionInfo
-
>ExceptionRecord
-
>ExceptionAddress
=
=
HookAddr)
{
/
*
在这里做你想做的事或者直接跳转到你的Hook函数中
........................
*
/
ExceptionInfo
-
>ContextRecord
-
>Eip
=
(DWORD)&OriginalFunc;
return
EXCEPTION_CONTINUE_EXECUTION;
}
}
return
EXCEPTION_CONTINUE_SEARCH;
/
/
继续向下搜索
}
LONG
NTAPI ExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo)
{
/
/
判断当前异常码是否为硬件断点异常
if
(ExceptionInfo
-
>ExceptionRecord
-
>ExceptionCode
=
=
EXCEPTION_SINGLE_STEP)
{
/
/
判断hook地址
if
(ExceptionInfo
-
>ExceptionRecord
-
>ExceptionAddress
=
=
HookAddr)
{
/
*
在这里做你想做的事或者直接跳转到你的Hook函数中
........................
*
/
ExceptionInfo
-
>ContextRecord
-
>Eip
=
(DWORD)&OriginalFunc;
return
EXCEPTION_CONTINUE_EXECUTION;
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)