见字如面,我是东北码农。
上文我们介绍了硬件断点,大家可以回顾一下。本文将介绍使用硬件断点+veh,实现硬件断点hook。
关注后,聊天框回复“硬件断点hook”,可以获取本文源码。
硬件断点这个手法,我还是分析外挂时学到的。开始做反外挂时候,只会用xuetr、pchunter等工具查看游戏进程的inlinehook,分析修改了游戏的哪些代码,然后再防御。然后有一天,我发现了一个外挂不按套路出牌,没有修改任何代码实现了透视功能,我就很纳闷这个外挂是怎么实现的呢,不改代码我怎么防啊?
后来经过不断学习,才知道hook的方式有很多种,硬件断点hook就是其中一种比较隐蔽的hook方式,可以在不修改源函数的前提实现hook,这一点比inlinehook强。
我们先来介绍一下VEH,先放一段微软官方描述。
参考资料:https://docs.microsoft.com/en-us/windows/win32/debug/vectored-exception-handling
<font color=gray size=2> Vectored exception handlers are an extension to structured exception handling. An application can register a function to watch or handle all exceptions for the application. Vectored handlers are not frame-based, therefore, you can add a handler that will be called regardless of where you are in a call frame. Vectored handlers are called in the order that they were added, after the debugger gets a first chance notification, but before the system begins unwinding the stack. </font>
大概意思是,程序可以注册异常回调函数链表。当程序触发异常时,回调函数就会按照用户指定的顺序依次调用。
向VEH链注册一个异常处理函数,可以使用windows提供的API,
接下来看一下异常处理函数,PVECTORED_EXCEPTION_HANDLER 的定义:
唯一的参数_EXCEPTION_POINTERS指向异常信息,定义如下:
定义如下:
异常处理函数的返回值很重要,控制着异常处理的后续行为:
<font color=gray size=2> To return control to the point at which the exception occurred, return EXCEPTION_CONTINUE_EXECUTION (0xffffffff). To continue the handler search, return EXCEPTION_CONTINUE_SEARCH (0x0). </font>
返回-1:异常已处理,继续执行;
返回0:继续调用VEH链的其它处理函数。
介绍完硬件断点和veh后,我们就可以实现硬件断点hook了。我们先介绍一下思路:
设置VEH链异常处理函数。
设置硬件断点,监控原函数的执行事件。
执行原函数时,会触发异常调用我们的异常处理函数。
异常处理函数判断,如果是原函数地址,则修改rip寄存器,跳转到hook函数。
异常处理函数,xx_hw_bp_veh的实现一会再介绍。
先记录一下原函数和hook函数的映射关系,再使用上文硬件断点封装好的xx_set_hw_bp设置硬件断点。
先通过异常地址,找到对应的hook函数地址。若找到,则修改Rip(指令寄存器)实现跳转;找不到则不是我们关心的异常,交给VEH链继续处理吧。
使用时先制作跳板,再hook。制作跳板复用inlinehook的代码。由于不修改代码,所以跳板值需要复制一条指令即可。复制的代码少,所以也基本不用考虑重定位问题。
欢迎大家点赞、转发、再看、留言交流~
PVOID AddVectoredContinueHandler(
ULONG First,
PVECTORED_EXCEPTION_HANDLER Handler
);
PVOID AddVectoredContinueHandler(
ULONG First,
PVECTORED_EXCEPTION_HANDLER Handler
);
LONG
PvectoredExceptionHandler(
[
in
] _EXCEPTION_POINTERS
*
ExceptionInfo
)
LONG
PvectoredExceptionHandler(
[
in
] _EXCEPTION_POINTERS
*
ExceptionInfo
)
typedef struct _EXCEPTION_POINTERS {
PEXCEPTION_RECORD ExceptionRecord;
/
/
异常信息记录
PCONTEXT ContextRecord;
/
/
寄存器信息
} EXCEPTION_POINTERS,
*
PEXCEPTION_POINTERS;
typedef struct _EXCEPTION_POINTERS {
PEXCEPTION_RECORD ExceptionRecord;
/
/
异常信息记录
PCONTEXT ContextRecord;
/
/
寄存器信息
} EXCEPTION_POINTERS,
*
PEXCEPTION_POINTERS;
static
bool
xx_init_hwbp_hook() {
return
xx_add_veh(CALL_FIRST, xx_hw_bp_veh);
}
static
bool
xx_init_hwbp_hook() {
return
xx_add_veh(CALL_FIRST, xx_hw_bp_veh);
}
class
xx_hw_bp
{
public:
struct bp_info {
void
*
src_
=
nullptr;
void
*
dst_
=
nullptr;
};
public:
void hook(void
*
src,void
*
dst,HANDLE thread,
int
idx)
{
/
/
记录原函数与hook函数关系。
/
/
TODO idx check
info_[idx].src_
=
src;
info_[idx].dst_
=
dst;
/
/
设置硬件断点
xx_set_hw_bp(thread, idx, src, RW_EXE);
}
/
/
获取原函数与hook函数映射
void
*
get_dst(void
*
src) {
for
(
int
i
=
0
; i <
4
;
+
+
i) {
if
(src
=
=
info_[i].src_)
{
return
info_[i].dst_;
}
}
return
nullptr;
}
bp_info info_[
4
];
};
xx_hw_bp g_hwbp_;
/
/
全局类,方便异常处理函数访问
class
xx_hw_bp
{
public:
struct bp_info {
void
*
src_
=
nullptr;
void
*
dst_
=
nullptr;
};
public:
void hook(void
*
src,void
*
dst,HANDLE thread,
int
idx)
{
/
/
记录原函数与hook函数关系。
/
/
TODO idx check
info_[idx].src_
=
src;
info_[idx].dst_
=
dst;
/
/
设置硬件断点
xx_set_hw_bp(thread, idx, src, RW_EXE);
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!