wtujoxk 发表于 2024-7-28 15:59:19

C/C++ Dll劫持 -- 硬件断点的实现 类型、大小设置

本帖最后由 wtujoxk 于 2024-7-28 16:00 编辑

前言,这是菜鸟学习Dll劫持硬件断点的过程,参考了几篇文章

下面帖上我学习的完整类:HwBreakpoint.cpp



#include "HwBreakpoint.h"

// 保存所有下断点的线程ID和相应寄存器
std::vector<HwBreakpoint> hwbrk;
void SetBits(DWORD_PTR& dw, int lowBit, int bits, int newValue)
{
      DWORD_PTR mask = (1 << bits) - 1;
      dw = (dw & ~(mask << lowBit)) | (newValue << lowBit);
}

// 设置硬件断点,在线程里调用
int RunHwBreakpoint(HANDLE HThread, HWBRK_TYPE Type, HWBRK_SIZE Size, ULONGLONG breakpoint)
{
      SuspendThread(HThread);
      CONTEXT context = { 0 };
      context.ContextFlags = CONTEXT_ALL;
      GetThreadContext(HThread, &context);
      // 找到一个空闲的调试寄存器
      int drIndex = -1, st = 0, le = 0;
      for (int i = 0; i < 4; ++i) {
                if ((context.Dr7 & (3 << (16 + i * 2))) == 0) {
                        drIndex = i;
                        break;
                }
      }
      if (drIndex == -1) {
                MessageBoxW(NULL, L"没有可用的硬件断点", L"提示", MB_OK);
                return -1; // 没有空闲的调试寄存器
      }

      if (drIndex == 0)context.Dr0 = breakpoint;
      if (drIndex == 1)context.Dr1 = breakpoint;
      if (drIndex == 2)context.Dr2 = breakpoint;
      if (drIndex == 3)context.Dr3 = breakpoint;

      SetBits(context.Dr7, 16 + drIndex * 4, 2, Type);// 设置读取、写入、执行
      SetBits(context.Dr7, 18 + drIndex * 4, 2, Size);// 设置1、2、4、8字节
      SetBits(context.Dr7, drIndex * 2, 1, 1);          // 启用断点
      SetThreadContext(HThread, &context);
      ResumeThread(HThread);
      // 将当前断点信息存入 vector
      HwBreakpoint* h = new HwBreakpoint();
      h->hwbpAddr = breakpoint;
      h->threadId = GetThreadId(HThread);
      h->iReg = drIndex;
      hwbrk.push_back(*h);
      return 0;
}

DWORD WINAPI BPThreadProc(LPVOID lpParameter)
{
      HwBreakpoint* h = (HwBreakpoint*)lpParameter;
      if (!h)return false;

      if (h->threadId) {
                //方式一:对指定的线程下硬件断点
                HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, false, h->threadId);
                if (hThread)
                {
                        RunHwBreakpoint(hThread, h->Type, h->Size, h->hwbpAddr);//下硬件断点
                        CloseHandle(hThread);
                        return TRUE;
                }
      }
      else
      {
                //方式二:对所有线程下硬件断点,加壳程序容易出错
                HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, GetCurrentProcessId());
                if (hSnap != INVALID_HANDLE_VALUE)
                {
                        THREADENTRY32 te;
                        te.dwSize = sizeof(THREADENTRY32);
                        if (Thread32First(hSnap, &te))
                        {
                              do
                              {    // 因为线程会挂起,排除自己的线程
                                        if (te.th32OwnerProcessID == GetCurrentProcessId() && te.th32ThreadID != GetCurrentThreadId())
                                        {
                                                //printf("当前进程: %d, 线程: %d, 优先级: %d\n", te.th32OwnerProcessID, te.th32ThreadID, te.tpBasePri);
                                                HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, false, te.th32ThreadID);
                                                if (hThread)
                                                {
                                                      RunHwBreakpoint(hThread, h->Type, h->Size, h->hwbpAddr);//下硬件断点
                                                      CloseHandle(hThread);
                                                }
                                        }
                              } while (Thread32Next(hSnap, &te));
                        }
                }
                if (hSnap) CloseHandle(hSnap);
      }
      return true;
}

// 设置硬件断点
ULONGLONG SetHwBreakpoint(int ThreadId, HWBRK_TYPE Type, HWBRK_SIZE Size, ULONGLONG breakpoint)
{
      HwBreakpoint* h = new HwBreakpoint();
      h->threadId = ThreadId;
      h->Type = Type;
      h->Size = Size;
      h->hwbpAddr = breakpoint;

      HANDLE handle = CreateThread(NULL, NULL, BPThreadProc, (LPVOID)h, NULL, NULL);
      if (handle)CloseHandle(handle);

      return breakpoint;
}

// 删除硬件断点 DelHwBreakpoint(ExceptionInfo->ContextRecord, 0x123456);
bool DelHwBreakpoint(PCONTEXT context, ULONGLONG breakpoint)
{
      if (hwbrk.empty()) return false;
      for (auto& h : hwbrk)
      {
                if (h.hwbpAddr == breakpoint)
                {
                        //std::cout << "dr7:" << breakpoint << std::endl;
                        int FlagBit = 0;
                        if (h.iReg == 0)
                        {
                              FlagBit = 0;
                              context->Dr0 = 0;
                        }
                        if (h.iReg == 1)
                        {
                              FlagBit = 2;
                              context->Dr1 = 0;
                        }
                        if (h.iReg == 2)
                        {
                              FlagBit = 4;
                              context->Dr2 = 0;
                        }
                        if (h.iReg == 3)
                        {
                              FlagBit = 6;
                              context->Dr3 = 0;
                        }
                        // 此设置来自:https://github.com/x64dbg/TitanEngine/
                        //DeleteHardwareBreakPoint 方法
                        context->Dr7 &= ~(1 << FlagBit);
                        context->Dr7 &= ~(1 << FlagBit + 1);
                        // 删除用过的元素
                        //hwbrk.erase(std::find(hwbrk.begin(), hwbrk.end(), h));
                        hwbrk.erase(std::remove(hwbrk.begin(), hwbrk.end(), h), hwbrk.end());
                }
      }
      return true;
}


头文件:HwBreakpoint.h
#include <windows.h>
#include <vector>
#include <TlHelp32.h>
#include <iostream>

enum HWBRK_TYPE
{
      TYPE_EXECUTE = 0,      //00 执行
      TYPE_WRITE = 1,      //01 写
      TYPE_READWRITE = 3,    //10 读
};

enum HWBRK_SIZE
{
      SIZE_1 = 0,      //00
      SIZE_2 = 1,      //01
      SIZE_8 = 2,      //10 64位系统
      SIZE_4 = 3,      //11
};

class HwBreakpoint
{
public:

      ULONGLONG hwbpAddr;    // 断点位置
      int threadId;          // 线程
      int iReg;            // 第几个寄存器
      HWBRK_TYPE Type;       // 读、写、执行
      HWBRK_SIZE Size;       // 字节
      HwBreakpoint()         // 初始化
      {
                hwbpAddr = 0;
                threadId = 0;
                iReg = 0;
                Type = TYPE_EXECUTE;
                Size = SIZE_1;
      }

      bool operator ==(const HwBreakpoint& p)
      {
                return hwbpAddr == p.hwbpAddr;
      }
};

/************************************************************************
SetHwBreakpoint:   设置线程硬件断点
ThreadId:          线程ID,0为所有线程下断,否则指定线程下断
Type:            参考 enum HWBRK_TYPE
Size:            参考 enum HWBRK_SIZE
breakpoint:      断点位置
调用:SetHwBreakpoint(MainThreadId, HWBRK_TYPE_CODE, HWBRK_SIZE_1, bp2);
返回:返回值为传入的断点地址
/************************************************************************/
ULONGLONG SetHwBreakpoint(int ThreadId, HWBRK_TYPE Type, HWBRK_SIZE Size, ULONGLONG dwAddr);

/************************************************************************
DelHwBreakpoint:删除硬件断点
context:          PCONTEXT指针:ExceptionInfo->ContextRecord
dwAddr:         断点地址:0x123456
调用:            DelHwBreakpoint(ExceptionInfo->ContextRecord, 0x123456);
/************************************************************************/
bool DelHwBreakpoint(PCONTEXT context, ULONGLONG dwAddr);

调用:调用很简单,看一下头文件声明,不考虑线程……和对指定线程下断
附件:

飞天梦 发表于 2024-7-28 17:30:07

谢谢分享

htpidk 发表于 2024-7-28 22:18:47

下载下来看看

sunboyzh 发表于 2024-7-29 00:04:15

谢谢楼主分享~

super_king 发表于 2024-7-31 08:02:21

谢谢楼主分享~

ruanjian 发表于 2024-8-5 22:31:01

谢谢分享

tyyabb 发表于 2024-8-7 10:53:22

谢谢楼主分享
页: [1]
查看完整版本: C/C++ Dll劫持 -- 硬件断点的实现 类型、大小设置