免杀基础-硬断Hook
字数 1146 2025-08-22 12:23:30

硬件断点Hook技术详解

1. 硬件断点Hook概述

硬件断点Hook是一种通过CPU调试寄存器实现函数拦截的技术,相比传统的Inline Hook(通过修改内存指令实现跳转)具有以下优势:

  1. 无需修改内存:Inline Hook需要修改目标函数指令(如E8/E9跳转),容易被内存保护机制检测
  2. 线程级控制:硬件断点只影响安装了它们的线程
  3. 难以检测:不修改原始代码,检测难度较高

2. 硬件断点原理

2.1 调试寄存器

x86/x64架构提供了8个调试寄存器DR0-DR7:

  • DR0-DR3:存储硬件断点的线性地址
  • DR6:调试状态寄存器
  • DR7:调试控制寄存器(最重要)

2.2 DR7寄存器详解

DR7寄存器控制硬件断点的行为,其结构如下(以64位为例):

typedef struct _DR7 {
    DWORD L0 : 1;   // DR0局部启用
    DWORD G0 : 1;   // DR0全局启用
    DWORD L1 : 1;   // DR1局部启用
    DWORD G1 : 1;   // DR1全局启用
    DWORD L2 : 1;   // DR2局部启用
    DWORD G2 : 1;   // DR2全局启用
    DWORD L3 : 1;   // DR3局部启用
    DWORD G3 : 1;   // DR3全局启用
    DWORD LE : 1;   // 局部精确断点
    DWORD GE : 1;   // 全局精确断点
    DWORD Reserved1 : 3;
    DWORD GD : 1;   // 调试寄存器访问保护
    DWORD Reserved2 : 2;
    DWORD RW0 : 2;  // DR0触发条件
    DWORD LEN0 : 2; // DR0监控长度
    DWORD RW1 : 2;  // DR1触发条件
    DWORD LEN1 : 2; // DR1监控长度
    DWORD RW2 : 2;  // DR2触发条件
    DWORD LEN2 : 2; // DR2监控长度
    DWORD RW3 : 2;  // DR3触发条件
    DWORD LEN3 : 2; // DR3监控长度
    DWORD Reserved : 32;
} DR7, *PDR7;

关键字段说明:

  • RWx:触发条件
    • 00:执行断点
    • 01:写入断点
    • 10:未使用
    • 11:读写断点
  • LENx:监控长度
    • 00:1字节
    • 01:2字节
    • 10:8字节(64位)或4字节(32位)
    • 11:4字节

3. 硬件断点Hook实现

3.1 基本实现步骤

  1. 获取线程上下文(GetThreadContext)
  2. 设置DR0-DR3寄存器(存储断点地址)
  3. 配置DR7寄存器(控制断点行为)
  4. 设置线程上下文(SetThreadContext)
  5. 注册异常处理程序(VEH)

3.2 核心代码实现

3.2.1 设置硬件断点

VOID setBP(HANDLE hThread, DRR dbgR) {
    CONTEXT Context = {0};
    Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
    GetThreadContext(hThread, &Context);
    Context.Dr0 = dbgR.DR0;
    Context.Dr7 = ConvertDr7(&dbgR.DR7);
    SetThreadContext(hThread, &Context);
}

3.2.2 移除硬件断点

VOID removeBP(HANDLE hThread) {
    CONTEXT Context = {0};
    Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
    GetThreadContext(hThread, &Context);
    Context.Dr0 = 0;
    Context.Dr7 = 0;
    SetThreadContext(hThread, &Context);
    GetThreadContext(hThread, &Context);
}

3.2.3 异常处理回调

LONG NTAPI ExceptionCallBack(_EXCEPTION_POINTERS* ExceptionInfo) {
    if(ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP) {
        if(ExceptionInfo->ExceptionRecord->ExceptionAddress == (PVOID)ExceptionInfo->ContextRecord->Dr0) {
            removeBP(hThread);
            ExceptionInfo->ContextRecord->EFlags |= (1 << 16); // RF标志位
            
            // 自定义逻辑
            // 修改返回值
            ExceptionInfo->ContextRecord->Rax = 1;
            
            // 跳过原函数执行
            #ifdef _WIN64
                ExceptionInfo->ContextRecord->Rip = (DWORD_PTR)ucRet;
            #else
                ExceptionInfo->ContextRecord->Eip = (DWORD_PTR)ucRet;
            #endif
            
            setBP(hThread, dbgR);
            return EXCEPTION_CONTINUE_EXECUTION;
        }
    }
    return EXCEPTION_CONTINUE_SEARCH;
}

3.3 关键点说明

  1. RF标志位:恢复标志位,防止重复触发断点
  2. 返回值修改:通过修改RAX/EAX寄存器实现
  3. 跳过原函数:将RIP/EIP指向ret指令(0xC3)
  4. 线程安全:每次异常处理后需要重新设置断点

4. 多线程Hook实现

4.1 枚举进程线程

void EnumThreadSetBp(DRR dbgR) {
    HMODULE hNtdll = GetModuleHandle(L"ntdll.dll");
    pNtQuerySystemInformation NtQuerySystemInformation = 
        (pNtQuerySystemInformation)(GetProcAddress(hNtdll, "NtQuerySystemInformation"));
    
    ULONG retLen1, retLen2;
    NtQuerySystemInformation(SystemProcessInformation, NULL, NULL, &retLen1);
    PVOID lpMem = VirtualAlloc(NULL, retLen1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    
    NTSTATUS status = NtQuerySystemInformation(SystemProcessInformation, lpMem, retLen1, &retLen2);
    if(NT_SUCCESS(status)) {
        PSYSTEM_PROCESS_INFORMATION processInfo = (PSYSTEM_PROCESS_INFORMATION)lpMem;
        while(processInfo->NextEntryOffset != 0) {
            PVOID CurrentPid = (PVOID)GetCurrentProcessId();
            if(processInfo->UniqueProcessId != 0) {
                if((PVOID)processInfo->UniqueProcessId == CurrentPid) {
                    PSYSTEM_THREAD_INFORMATION threadInfo = (PSYSTEM_THREAD_INFORMATION)processInfo->Threads;
                    for(ULONG i = 0; i < processInfo->NumberOfThreads; i++) {
                        hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, 
                                           (DWORD)threadInfo->ClientId.UniqueThread);
                        setBP(hThread, dbgR);
                        threadInfo++;
                    }
                }
            }
            processInfo = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)processInfo + processInfo->NextEntryOffset);
        }
    }
    VirtualFree(lpMem, 0, MEM_RELEASE);
}

4.2 多线程Hook注意事项

  1. 线程权限:需要THREAD_ALL_ACCESS权限
  2. 线程同步:确保线程在设置断点时处于安全状态
  3. 性能考虑:每个线程最多4个硬件断点(DR0-DR3限制)

5. 实际应用示例

5.1 修改函数返回值

BOOLEAN testRoutine() {
    return (1 > 100); // 原返回FALSE
}

// 在异常处理中修改返回值
ExceptionInfo->ContextRecord->Rax = 1; // 改为返回TRUE

5.2 修改函数参数

// 修改MessageBox参数
ExceptionInfo->ContextRecord->Rcx = (DWORD_PTR)L"New Title";
ExceptionInfo->ContextRecord->Rdx = (DWORD_PTR)L"New Text";

6. 检测与反制

6.1 检测硬件断点

  1. 检查DR0-DR7寄存器值
  2. 使用GetThreadContext获取线程上下文

6.2 反制措施

  1. 随机化断点位置:不在函数入口下断点
  2. 动态启用/禁用:只在需要时启用断点
  3. 结合其他Hook技术:与Inline Hook交替使用

7. 总结

硬件断点Hook是一种强大的函数拦截技术,相比传统Hook方法具有更好的隐蔽性。通过合理使用调试寄存器,可以实现:

  1. 函数调用监控
  2. 参数修改
  3. 返回值修改
  4. 函数执行流程控制

关键点在于正确配置DR7寄存器、妥善处理异常以及管理多线程环境下的断点状态。

硬件断点Hook技术详解 1. 硬件断点Hook概述 硬件断点Hook是一种通过CPU调试寄存器实现函数拦截的技术,相比传统的Inline Hook(通过修改内存指令实现跳转)具有以下优势: 无需修改内存 :Inline Hook需要修改目标函数指令(如E8/E9跳转),容易被内存保护机制检测 线程级控制 :硬件断点只影响安装了它们的线程 难以检测 :不修改原始代码,检测难度较高 2. 硬件断点原理 2.1 调试寄存器 x86/x64架构提供了8个调试寄存器DR0-DR7: DR0-DR3 :存储硬件断点的线性地址 DR6 :调试状态寄存器 DR7 :调试控制寄存器(最重要) 2.2 DR7寄存器详解 DR7寄存器控制硬件断点的行为,其结构如下(以64位为例): 关键字段说明: RWx :触发条件 00:执行断点 01:写入断点 10:未使用 11:读写断点 LENx :监控长度 00:1字节 01:2字节 10:8字节(64位)或4字节(32位) 11:4字节 3. 硬件断点Hook实现 3.1 基本实现步骤 获取线程上下文(GetThreadContext) 设置DR0-DR3寄存器(存储断点地址) 配置DR7寄存器(控制断点行为) 设置线程上下文(SetThreadContext) 注册异常处理程序(VEH) 3.2 核心代码实现 3.2.1 设置硬件断点 3.2.2 移除硬件断点 3.2.3 异常处理回调 3.3 关键点说明 RF标志位 :恢复标志位,防止重复触发断点 返回值修改 :通过修改RAX/EAX寄存器实现 跳过原函数 :将RIP/EIP指向ret指令(0xC3) 线程安全 :每次异常处理后需要重新设置断点 4. 多线程Hook实现 4.1 枚举进程线程 4.2 多线程Hook注意事项 线程权限 :需要THREAD_ ALL_ ACCESS权限 线程同步 :确保线程在设置断点时处于安全状态 性能考虑 :每个线程最多4个硬件断点(DR0-DR3限制) 5. 实际应用示例 5.1 修改函数返回值 5.2 修改函数参数 6. 检测与反制 6.1 检测硬件断点 检查DR0-DR7寄存器值 使用GetThreadContext获取线程上下文 6.2 反制措施 随机化断点位置 :不在函数入口下断点 动态启用/禁用 :只在需要时启用断点 结合其他Hook技术 :与Inline Hook交替使用 7. 总结 硬件断点Hook是一种强大的函数拦截技术,相比传统Hook方法具有更好的隐蔽性。通过合理使用调试寄存器,可以实现: 函数调用监控 参数修改 返回值修改 函数执行流程控制 关键点在于正确配置DR7寄存器、妥善处理异常以及管理多线程环境下的断点状态。