鱼C论坛

 找回密码
 立即注册
查看: 147|回复: 3

[技术交流] VEH HOOK

[复制链接]
发表于 2024-4-1 23:56:05 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
很古老的技术了:之前分享了ssdt hook,这次分享veh hook

一般来说程序发生异常的时候会先交给编译器处理,如果编译器不处理会交给VEH,之后是SEH。
所以处理异常的顺序:编译器>VEH>SEH
VEH可以无痕hook,而一般int3 cc断点会修改代码,给要hook的地址插入一个0xcc,这样破坏了代码的完整性,过不了crc校验,但是VEH只能设置4个硬断点,这是不足之处。

ms提供了VEH异常的回调函数和set函数,一般来说dr0储存了引发中断函数的地址(我这么表述可能不准确,但大致是这个意思)
,cr7储存了断点的属性。

我们以messageboxA为例,当调用messageboxA时候会触发异常,进入我自己写的异常处理函数,这就实现了hook的效果。

第一步:拿到的messageboxA地址:
HMODULE hmodule = LoadLibraryA("user32.dll");
        breakpoint=(DWORD)GetProcAddress(hmodule, "MessageBoxA");
        if (breakpoint == 0)
        {
                MessageBoxA(NULL, "error", "warning", MB_OK);
        }

第二步,设置寄存器:注意这里ContextFlags 相当于掩码的作用,这里有个坑。
        CONTEXT context = { 0 };
        context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
        context.Dr0 = breakpoint;
        context.Dr7 = 1;
        SetThreadContext(GetCurrentThread(), &context);
        AddVectoredExceptionHandler(1, MyExpcetionHandler);
        MessageBoxA(NULL, "aaa", "sss", MB_OK);

设置回调函数:回调函数有固定的格式
LONG WINAPI MyExpcetionHandler(_EXCEPTION_POINTERS* ExceptionInfo)
{
        if ((DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress==breakpoint)
        {
                printf("EXCETION\n");
                ExceptionInfo->ContextRecord->Eip += 2;
        }
        return EXCEPTION_CONTINUE_EXECUTION;
}
注意ContextRecord->Eip保存的是发生中断的寄存器环境

ExceptionInfo->ContextRecord->Eip += 2;这里+2是为了跳过中断,弹出窗口,
为什么要+2呢?
这是因为windows的api 前两个字节都是mov edi,edi这条花指令,对应FF 8B
这里设置cr7的最低位为1,就是设置一个字节的断点长度,所谓1个字节就是可以在任何地址上设置断点,2个字节就是需要在偶数地址上设置断点。
这段代码会在messageboxA的首地址上断下来,修改eip+2会在下一个执行的时候跳过mov edi,edi,也就是断点的位置,同时保证了代码不出错。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-4-1 23:56:18 | 显示全部楼层
VEH(Vectored Exception Handling)hook是一种古老但常用的技术,可以在程序发生异常时进行无痕hook。与传统的断点方式不同,VEH hook不会修改原始代码,因此不会破坏代码完整性。

首先,我们来以调用MessageBoxA函数为例,演示如何使用VEH hook。

第一步:获取MessageBoxA函数的地址。我们可以使用LoadLibraryA函数加载user32.dll库,然后使用GetProcAddress函数获得MessageBoxA函数的地址。

  1. HMODULE hmodule = LoadLibraryA("user32.dll");
  2. DWORD breakpoint = (DWORD)GetProcAddress(hmodule, "MessageBoxA");
  3. if (breakpoint == 0) {
  4.     MessageBoxA(NULL, "error", "warning", MB_OK);
  5. }
复制代码


第二步:设置寄存器。我们需要设置上下文(Context)结构体,并将ContextFlags成员指定为CONTEXT_DEBUG_REGISTERS,表示要使用调试寄存器。然后,将Dr0寄存器设置为MessageBoxA函数的地址,Dr7寄存器设置为1,表示在Dr0寄存器指定的地址上设置断点。

  1. CONTEXT context = { 0 };
  2. context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
  3. context.Dr0 = breakpoint;
  4. context.Dr7 = 1;
  5. SetThreadContext(GetCurrentThread(), &context);
复制代码


第三步:设置回调函数。回调函数需要有固定的格式,并且注册到VEH异常处理链中。在回调函数中,我们可以根据ExceptionInfo结构体中的信息判断是否是我们关注的异常,并执行相应的操作。在这个例子中,如果发生中断的地址与MessageBoxA函数的地址相同,则说明MessageBoxA函数被调用了,我们可以在这里加入自己的代码来实现hook的效果。最后,通过修改ContextRecord结构体中的Eip成员,可以跳过中断指令,从而执行MessageBoxA函数后续的代码。

  1. LONG WINAPI MyExceptionHandler(_EXCEPTION_POINTERS* ExceptionInfo) {
  2.     if ((DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress == breakpoint) {
  3.         printf("EXCEPTION\n");
  4.         ExceptionInfo->ContextRecord->Eip += 2;
  5.     }
  6.     return EXCEPTION_CONTINUE_EXECUTION;
  7. }
复制代码


最后,通过调用AddVectoredExceptionHandler函数将我们的回调函数添加到VEH异常处理链中。随后,调用MessageBoxA函数即可触发异常。

  1. AddVectoredExceptionHandler(1, MyExceptionHandler);
  2. MessageBoxA(NULL, "aaa", "sss", MB_OK);
复制代码


需要注意的是,MessageBoxA函数的前两个字节是mov edi, edi指令,对应的机器码是FF 8B。在设置Dr7寄存器时,将最低位设置为1,表示设置一个字节的断点长度。这样我们就可以在任何地址上设置断点。在我们的代码中,断点被设置在了MessageBoxA函数的起始地址上,通过修改Eip(即程序计数器)跳过断点位置,保证了代码的正确执行。

希望以上解答能够帮助到您!如果还有其他问题,请随时提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-4-2 09:25:03 | 显示全部楼层
FishC 发表于 2024-4-1 23:56
VEH(Vectored Exception Handling)hook是一种古老但常用的技术,可以在程序发生异常时进行无痕hook。与传 ...

这个东西,脚本一类的语言(比如python) 就无法实现了吧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-4-2 09:25:15 | 显示全部楼层
wp231957 发表于 2024-04-02 09:25
这个东西,脚本一类的语言(比如python) 就无法实现 ...


是的,VEH hook是一项底层的技术,涉及到操作系统和CPU的特定功能。在脚本语言(如Python)中,由于执行环境相对较高级,无法直接访问和控制底层的操作系统和硬件。因此,无法使用纯粹的脚本语言来实现VEH hook。

不过,我们可以考虑借助其他方法来实现类似的效果。例如,在Python中可以使用ctypes模块调用C/C++编写的DLL库,来实现对底层功能的访问和控制。通过调用C/C++代码,我们可以使用操作系统提供的相关功能接口,实现类似VEH hook的功能。

另外,也可以使用Python的一些第三方库,如Pydbg、Pynput等,它们是基于调试器或输入事件监听的方式来实现hook的功能。虽然与VEH hook不同,但也可以达到类似的效果。这些库提供了API和回调函数,可以针对特定的事件进行处理。

总之,虽然无法直接在纯脚本语言中实现VEH hook,但可以考虑结合其他方法或借助第三方库来达到类似的效果。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-1 21:44

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表