代码实战硬件断点hook

见字如面,我是东北码农。

上文我们介绍了硬件断点,大家可以回顾一下。本文将介绍使用硬件断点+veh,实现硬件断点hook。

关注“东北码农”后,聊天框回复“硬件断点hook”,可以获取本文源码。

1、不修改原函数hook

硬件断点这个手法,我还是分析外挂时学到的。开始做反外挂时候,只会用xuetr、pchunter等工具查看游戏进程的inlinehook,分析修改了游戏的哪些代码,然后再防御。然后有一天,我发现了一个外挂不按套路出牌,没有修改任何代码实现了透视功能,我就很纳闷这个外挂是怎么实现的呢,不改代码我怎么防啊?

后来经过不断学习,才知道hook的方式有很多种,硬件断点hook就是其中一种比较隐蔽的hook方式,可以在不修改源函数的前提实现hook,这一点比inlinehook强。


2、VEH(Vectored Exception Handling)

2.1、VEH介绍

我们先来介绍一下VEH,先放一段微软官方描述。

参考资料:Vectored Exception Handling - Win32 apps | Microsoft Docs

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.

大概意思是,程序可以注册异常回调函数链表。当程序触发异常时,回调函数就会按照用户指定的顺序依次调用。


2.2、VEH 使用

向VEH链注册一个异常处理函数,可以使用windows提供的API,

<span style="background-color:#f5f5f5"><span style="color:#333333">PVOID <span style="color:#795da3">AddVectoredContinueHandler</span><span style="color:#333333">(</span>
  ULONG                       First<span style="color:#333333">,</span>
  PVECTORED_EXCEPTION_HANDLER Handler
<span style="color:#333333">)</span><span style="color:#333333">;</span>
</span></span>
  • First:是否插入VEH链头部。
  • Handler:异常处理函数。

接下来看一下异常处理函数,PVECTORED_EXCEPTION_HANDLER 的定义:

<span style="background-color:#f5f5f5"><span style="color:#333333">LONG <span style="color:#795da3">PvectoredExceptionHandler</span><span style="color:#333333">(</span>
  <span style="color:#333333">[</span>in<span style="color:#333333">]</span> _EXCEPTION_POINTERS <span style="color:#a71d5d">*</span>ExceptionInfo
<span style="color:#333333">)</span>
</span></span>

唯一的参数_EXCEPTION_POINTERS指向异常信息,定义如下:

定义如下:

<span style="background-color:#f5f5f5"><span style="color:#333333"><span style="color:#a71d5d">typedef</span> <span style="color:#a71d5d">struct</span> <span style="color:#795da3">_EXCEPTION_POINTERS</span> <span style="color:#333333">{</span>
  PEXCEPTION_RECORD ExceptionRecord<span style="color:#333333">;</span><span style="color:#969896">// 异常信息记录</span>
  PCONTEXT          ContextRecord<span style="color:#333333">;</span><span style="color:#969896">// 寄存器信息</span>
<span style="color:#333333">}</span> EXCEPTION_POINTERS<span style="color:#333333">,</span> <span style="color:#a71d5d">*</span>PEXCEPTION_POINTERS<span style="color:#333333">;</span>
</span></span>

异常处理函数的返回值很重要,控制着异常处理的后续行为:

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).

  • 返回-1:异常已处理,继续执行;

  • 返回0:继续调用VEH链的其它处理函数。

3、硬件断点 hook 实战代码

介绍完硬件断点和veh后,我们就可以实现硬件断点hook了。我们先介绍一下思路:

  1. 设置VEH链异常处理函数。

  2. 设置硬件断点,监控原函数的执行事件。

  3. 执行原函数时,会触发异常调用我们的异常处理函数。

  4. 异常处理函数判断,如果是原函数地址,则修改rip寄存器,跳转到hook函数。

3.1、设置VEH链异常处理函数

异常处理函数,xx_hw_bp_veh的实现一会再介绍。

<span style="background-color:#f5f5f5"><span style="color:#333333"><span style="color:#a71d5d">static</span> <span style="color:#a71d5d">bool</span> <span style="color:#795da3">xx_init_hwbp_hook</span><span style="color:#333333">(</span><span style="color:#333333">)</span> <span style="color:#333333">{</span>
  <span style="color:#a71d5d">return</span> <span style="color:#795da3">xx_add_veh</span><span style="color:#333333">(</span>CALL_FIRST<span style="color:#333333">,</span> xx_hw_bp_veh<span style="color:#333333">)</span><span style="color:#333333">;</span>
<span style="color:#333333">}</span>
</span></span>

3.2、设置硬件断点

<span style="background-color:#f5f5f5"><span style="color:#333333"><span style="color:#a71d5d">class</span> <span style="color:#795da3">xx_hw_bp</span>
<span style="color:#333333">{</span>
<span style="color:#a71d5d">public</span><span style="color:#a71d5d">:</span>
  <span style="color:#a71d5d">struct</span> <span style="color:#795da3">bp_info</span> <span style="color:#333333">{</span>
    <span style="color:#a71d5d">void</span><span style="color:#a71d5d">*</span> src_ <span style="color:#a71d5d">=</span> <span style="color:#a71d5d">nullptr</span><span style="color:#333333">;</span>
    <span style="color:#a71d5d">void</span><span style="color:#a71d5d">*</span> dst_ <span style="color:#a71d5d">=</span> <span style="color:#a71d5d">nullptr</span><span style="color:#333333">;</span>
  <span style="color:#333333">}</span><span style="color:#333333">;</span>
<span style="color:#a71d5d">public</span><span style="color:#a71d5d">:</span>
  <span style="color:#a71d5d">void</span> <span style="color:#795da3">hook</span><span style="color:#333333">(</span><span style="color:#a71d5d">void</span><span style="color:#a71d5d">*</span> src<span style="color:#333333">,</span><span style="color:#a71d5d">void</span><span style="color:#a71d5d">*</span> dst<span style="color:#333333">,</span>HANDLE thread<span style="color:#333333">,</span><span style="color:#a71d5d">int</span> idx<span style="color:#333333">)</span>
<span style="color:#333333">{</span>
    <span style="color:#969896">//记录原函数与hook函数关系。</span>
    <span style="color:#969896">// TODO idx check</span>
    info_<span style="color:#333333">[</span>idx<span style="color:#333333">]</span><span style="color:#333333">.</span>src_ <span style="color:#a71d5d">=</span> src<span style="color:#333333">;</span>
    info_<span style="color:#333333">[</span>idx<span style="color:#333333">]</span><span style="color:#333333">.</span>dst_ <span style="color:#a71d5d">=</span> dst<span style="color:#333333">;</span>
    <span style="color:#969896">// 设置硬件断点</span>
    <span style="color:#795da3">xx_set_hw_bp</span><span style="color:#333333">(</span>thread<span style="color:#333333">,</span> idx<span style="color:#333333">,</span> src<span style="color:#333333">,</span> RW_EXE<span style="color:#333333">)</span><span style="color:#333333">;</span>
  <span style="color:#333333">}</span>
    <span style="color:#969896">// 获取原函数与hook函数映射</span>
  <span style="color:#a71d5d">void</span><span style="color:#a71d5d">*</span> <span style="color:#795da3">get_dst</span><span style="color:#333333">(</span><span style="color:#a71d5d">void</span><span style="color:#a71d5d">*</span> src<span style="color:#333333">)</span> <span style="color:#333333">{</span>
    <span style="color:#a71d5d">for</span> <span style="color:#333333">(</span><span style="color:#a71d5d">int</span> i <span style="color:#a71d5d">=</span> <span style="color:#0086b3">0</span><span style="color:#333333">;</span> i <span style="color:#a71d5d"><</span> <span style="color:#0086b3">4</span><span style="color:#333333">;</span> <span style="color:#a71d5d">++</span>i<span style="color:#333333">)</span> <span style="color:#333333">{</span>
      <span style="color:#a71d5d">if</span> <span style="color:#333333">(</span>src <span style="color:#a71d5d">==</span> info_<span style="color:#333333">[</span>i<span style="color:#333333">]</span><span style="color:#333333">.</span>src_<span style="color:#333333">)</span>
      <span style="color:#333333">{</span>
        <span style="color:#a71d5d">return</span> info_<span style="color:#333333">[</span>i<span style="color:#333333">]</span><span style="color:#333333">.</span>dst_<span style="color:#333333">;</span>
      <span style="color:#333333">}</span>
    <span style="color:#333333">}</span>
    <span style="color:#a71d5d">return</span> <span style="color:#a71d5d">nullptr</span><span style="color:#333333">;</span>
  <span style="color:#333333">}</span>
  bp_info info_<span style="color:#333333">[</span><span style="color:#0086b3">4</span><span style="color:#333333">]</span><span style="color:#333333">;</span>
<span style="color:#333333">}</span><span style="color:#333333">;</span>

xx_hw_bp g_hwbp_<span style="color:#333333">;</span><span style="color:#969896">// 全局类,方便异常处理函数访问</span>
</span></span>

先记录一下原函数和hook函数的映射关系,再使用上文硬件断点封装好的xx_set_hw_bp设置硬件断点。

3.3、异常处理函数实现

<span style="background-color:#f5f5f5"><span style="color:#333333">LONG NTAPI <span style="color:#795da3">xx_hw_bp_veh</span><span style="color:#333333">(</span>
  <span style="color:#a71d5d">struct</span> <span style="color:#795da3">_EXCEPTION_POINTERS</span><span style="color:#a71d5d">*</span> ExceptionInfo<span style="color:#333333">)</span>
<span style="color:#333333">{</span>
  <span style="color:#969896">// 获取异常地址</span>
  <span style="color:#a71d5d">void</span><span style="color:#a71d5d">*</span> src <span style="color:#a71d5d">=</span> ExceptionInfo<span style="color:#a71d5d">-></span>ExceptionRecord<span style="color:#a71d5d">-></span>ExceptionAddress<span style="color:#333333">;</span>
  <span style="color:#969896">// 查找对应关系</span>
  <span style="color:#a71d5d">void</span><span style="color:#a71d5d">*</span> dst <span style="color:#a71d5d">=</span> g_hwbp_<span style="color:#333333">.</span><span style="color:#795da3">get_dst</span><span style="color:#333333">(</span>src<span style="color:#333333">)</span><span style="color:#333333">;</span>
  <span style="color:#a71d5d">if</span> <span style="color:#333333">(</span><span style="color:#a71d5d">nullptr</span> <span style="color:#a71d5d">!=</span> dst<span style="color:#333333">)</span> <span style="color:#333333">{</span>
    <span style="color:#969896">// 修改rip 跳转</span>
    <span style="color:#795da3">memcpy</span><span style="color:#333333">(</span><span style="color:#a71d5d">&</span>ExceptionInfo<span style="color:#a71d5d">-></span>ContextRecord<span style="color:#a71d5d">-></span>Rip<span style="color:#333333">,</span> <span style="color:#a71d5d">&</span>dst<span style="color:#333333">,</span> <span style="color:#a71d5d">sizeof</span><span style="color:#333333">(</span><span style="color:#a71d5d">void</span><span style="color:#a71d5d">*</span><span style="color:#333333">)</span><span style="color:#333333">)</span><span style="color:#333333">;</span>
    <span style="color:#a71d5d">return</span> EXCEPTION_CONTINUE_EXECUTION<span style="color:#333333">;</span>
  <span style="color:#333333">}</span>
  <span style="color:#969896">// 其它异常,继续veh链处理</span>
  <span style="color:#a71d5d">return</span> EXCEPTION_CONTINUE_SEARCH<span style="color:#333333">;</span>
<span style="color:#333333">}</span>
</span></span>

先通过异常地址,找到对应的hook函数地址。若找到,则修改Rip(指令寄存器)实现跳转;找不到则不是我们关心的异常,交给VEH链继续处理吧。

4、demo验证

<span style="background-color:#f5f5f5"><span style="color:#333333"><span style="color:#a71d5d">int</span> WINAPI <span style="color:#795da3">My_MessageBoxA</span><span style="color:#333333">(</span>
  _In_opt_ HWND hWnd<span style="color:#333333">,</span>
  _In_opt_ LPCSTR lpText<span style="color:#333333">,</span>
  _In_opt_ LPCSTR lpCaption<span style="color:#333333">,</span>
  _In_ UINT uType<span style="color:#333333">)</span>
<span style="color:#333333">{</span>
  <span style="color:#795da3">printf</span><span style="color:#333333">(</span><span style="color:#183691">"[call %s]!\n"</span><span style="color:#333333">,</span> __FUNCTION__<span style="color:#333333">)</span><span style="color:#333333">;</span>

  <span style="color:#a71d5d">auto</span> ori <span style="color:#a71d5d">=</span> <span style="color:#795da3">xx_trampoline_to_func</span><span style="color:#333333">(</span><span style="color:#a71d5d">&</span>MessageBoxA<span style="color:#333333">,</span> trampoline<span style="color:#333333">)</span><span style="color:#333333">;</span>
  <span style="color:#a71d5d">return</span> <span style="color:#333333">(</span><span style="color:#a71d5d">*</span>ori<span style="color:#333333">)</span><span style="color:#333333">(</span>hWnd<span style="color:#333333">,</span> lpText<span style="color:#333333">,</span> lpCaption<span style="color:#333333">,</span> uType<span style="color:#333333">)</span><span style="color:#333333">;</span>
<span style="color:#333333">}</span>

<span style="color:#a71d5d">void</span> <span style="color:#795da3">test_hook</span><span style="color:#333333">(</span><span style="color:#333333">)</span> <span style="color:#333333">{</span>
  <span style="color:#969896">// 制作跳板,只需要复制1条指令,跳过硬件断点即可</span>
  <span style="color:#795da3">xx_mem_unprotect</span><span style="color:#333333">(</span>trampoline<span style="color:#333333">,</span> <span style="color:#0086b3">1024</span><span style="color:#333333">)</span><span style="color:#333333">;</span>
  <span style="color:#795da3">xx_make_trampoline</span><span style="color:#333333">(</span><span style="color:#a71d5d">&</span>MessageBoxA<span style="color:#333333">,</span> trampoline<span style="color:#333333">,</span> <span style="color:#0086b3">4</span><span style="color:#333333">)</span><span style="color:#333333">;</span>

  <span style="color:#795da3">xx_init_hwbp_hook</span><span style="color:#333333">(</span><span style="color:#333333">)</span><span style="color:#333333">;</span>
  g_hwbp_<span style="color:#333333">.</span><span style="color:#795da3">hook</span><span style="color:#333333">(</span><span style="color:#a71d5d">&</span>MessageBoxA<span style="color:#333333">,</span> <span style="color:#a71d5d">&</span>My_MessageBoxA<span style="color:#333333">,</span><span style="color:#795da3">GetCurrentThread</span><span style="color:#333333">(</span><span style="color:#333333">)</span><span style="color:#333333">,</span> <span style="color:#0086b3">0</span><span style="color:#333333">)</span><span style="color:#333333">;</span>
  <span style="color:#333333">::</span><span style="color:#795da3">MessageBoxA</span><span style="color:#333333">(</span><span style="color:#0086b3">0</span><span style="color:#333333">,</span> <span style="color:#183691">"aaa"</span><span style="color:#333333">,</span> <span style="color:#183691">"bbb"</span><span style="color:#333333">,</span> <span style="color:#0086b3">0</span><span style="color:#333333">)</span><span style="color:#333333">;</span>
<span style="color:#333333">}</span>
</span></span>

使用时先制作跳板,再hook。制作跳板复用inlinehook的代码。由于不修改代码,所以跳板值需要复制一条指令即可。复制的代码少,所以也基本不用考虑重定位问题。

欢迎大家点赞、转发、再看、留言交流~

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在iOS越狱开发中,常用的Hook检测包括以下几种: 1. 检测当前进程是否被其他进程注入 ``` void anti_injection() { char path[1024]; int ret = proc_pidpath(getpid(), path, sizeof(path)); if (ret <= 0) { NSLog(@"anti_injection: proc_pidpath failed"); exit(1); } if (strstr(path, "/Library/MobileSubstrate") != NULL) { NSLog(@"anti_injection: MobileSubstrate detected"); exit(1); } if (strstr(path, "/Library/Frameworks/CydiaSubstrate.framework") != NULL) { NSLog(@"anti_injection: CydiaSubstrate detected"); exit(1); } } ``` 2. 检测是否被调试 ``` void anti_debugging() { int name[4]; struct kinfo_proc info; size_t info_size = sizeof(info); name[0] = CTL_KERN; name[1] = KERN_PROC; name[2] = KERN_PROC_PID; name[3] = getpid(); if (sysctl(name, 4, &info, &info_size, NULL, 0) == -1) { NSLog(@"anti_debugging: sysctl failed"); exit(1); } if (info.kp_proc.p_flag & P_TRACED) { NSLog(@"anti_debugging: traced"); exit(1); } } ``` 3. 检测是否被hook ``` void anti_hooking() { const char *functionName = "ptrace"; void *handle = dlopen("/usr/lib/libc.dylib", RTLD_GLOBAL | RTLD_NOW); if (handle == NULL) { NSLog(@"anti_hooking: dlopen failed"); exit(1); } void *ptrace_func = dlsym(handle, functionName); if (ptrace_func == NULL) { NSLog(@"anti_hooking: dlsym failed"); exit(1); } if (ptrace_func != (void *)&ptrace) { NSLog(@"anti_hooking: hook detected"); exit(1); } } ``` 4. 检测是否被注入Cycript等调试工具 ``` void anti_cycript() { char *cycript = strstr(getenv("DYLD_INSERT_LIBRARIES"), "cycript"); if (cycript != NULL) { NSLog(@"anti_cycript: cycript detected"); exit(1); } } ``` 此外,还可以在代码中添加闪退检测断点,当程序发生闪退时就可以打断点进行调试,例如: ``` void crash_handler(int signal) { signal(SIGTRAP, NULL); NSLog(@"crash_handler: signal=%d", signal); exit(1); } void set_crash_handler() { signal(SIGTRAP, crash_handler); } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值