首页
社区
课程
招聘
[原创]C/C++ 自写补丁-设置硬件断点 x86_x64
发表于: 2024-10-9 11:10 2474

[原创]C/C++ 自写补丁-设置硬件断点 x86_x64

2024-10-9 11:10
2474

硬件断点

描述:
1、与软件断点与内存断点不同,硬件断点不依赖被调试程序,而是依赖于CPU中的调试寄存器。
2、调试寄存器有8个,分别为Dr0-Dr7。
3、用户最多能够设置4个硬件断点,这是由于只有Dr0~Dr3用于存储线性地址。
4、其中,Dr4和Dr5是保留的。

设置硬件断点,硬件断点设置一点不友好,使用时有不大不小的坑

1)Dr0-Dr3用于设置硬件断点,由于只有4个断点寄存器,所以最多只能设置4个硬件调试断点。
2)Dr7是最重要的寄存器:
L0/G0 ~ L3/G3:控制Dr0-Dr3是否有效,局部还是全局;每次异常后,Lx都被清零,Gx不清零。
断点长度(LENx):00(1字节)、01(2字节)、11(4字节)、10(8字节)
断点类型(R/Wx):00(执行断点)、01(写入断点)、11(访问断点)

处理硬件断点

1)硬件调试断点产生的异常是 STATUS_SINGLE_STEP(单步异常)
2)检测Dr6寄存器的B0~B3:哪个寄存器触发的异常

硬件断点的设置与处理

硬件断点设置与线程、寄存器有关,并且还有读、写、访问、字节大小等一些设置,下面用代码实现这一系列设置和删除的操作,创建一个HardwareBreakpoint.cpp,写如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
#include "HardwareBreakpoint.h"
#include <vector>
#include <TlHelp32.h>
 
#define BITSET(a,x) (a|=1<<x)
#define BITGET(a,x) (a&(1<<x))
 
enum HWBP_MODE
{
    MODE_DISABLED = 0,    //00
    MODE_LOCAL = 1,       //01
    MODE_GLOBAL = 2       //10
};
struct DR7
{
    BYTE HWBP_MODE[4];
    BYTE HWBP_TYPE[4];
    BYTE HWBP_SIZE[4];
};
class HardwareBreakpoint
{
public:
 
    ULONG_PTR hwbpAddr;   // 断点位置
    int threadId;         // 线程ID
    HWBP_DRX Drx;         // 第几个寄存器
    HWBP_TYPE Type;       // 读、写、执行
    HWBP_SIZE Size;       // 字节
    HardwareBreakpoint()  // 初始化
    {
        hwbpAddr = 0;
        threadId = 0;
        Drx = Dr0;
        Type = TYPE_EXECUTE;
        Size = SIZE_1;
    }
 
    bool operator ==(const HardwareBreakpoint& p)
    {
        return hwbpAddr == p.hwbpAddr;
    }
};
ULONG_PTR dr7uint(DR7* dr7)
{
    ULONG_PTR ret = 0;
    if (BITGET(dr7->HWBP_MODE[0], 0))
        BITSET(ret, 0);
    if (BITGET(dr7->HWBP_MODE[0], 1))
        BITSET(ret, 1);
    if (BITGET(dr7->HWBP_MODE[1], 0))
        BITSET(ret, 2);
    if (BITGET(dr7->HWBP_MODE[1], 1))
        BITSET(ret, 3);
    if (BITGET(dr7->HWBP_MODE[2], 0))
        BITSET(ret, 4);
    if (BITGET(dr7->HWBP_MODE[2], 1))
        BITSET(ret, 5);
    if (BITGET(dr7->HWBP_MODE[3], 0))
        BITSET(ret, 6);
    if (BITGET(dr7->HWBP_MODE[3], 1))
        BITSET(ret, 7);
    if (BITGET(dr7->HWBP_TYPE[0], 0))
        BITSET(ret, 16);
    if (BITGET(dr7->HWBP_TYPE[0], 1))
        BITSET(ret, 17);
    if (BITGET(dr7->HWBP_SIZE[0], 0))
        BITSET(ret, 18);
    if (BITGET(dr7->HWBP_SIZE[0], 1))
        BITSET(ret, 19);
    if (BITGET(dr7->HWBP_TYPE[1], 0))
        BITSET(ret, 20);
    if (BITGET(dr7->HWBP_TYPE[1], 1))
        BITSET(ret, 21);
    if (BITGET(dr7->HWBP_SIZE[1], 0))
        BITSET(ret, 22);
    if (BITGET(dr7->HWBP_SIZE[1], 1))
        BITSET(ret, 23);
    if (BITGET(dr7->HWBP_TYPE[2], 0))
        BITSET(ret, 24);
    if (BITGET(dr7->HWBP_TYPE[2], 1))
        BITSET(ret, 25);
    if (BITGET(dr7->HWBP_SIZE[2], 0))
        BITSET(ret, 26);
    if (BITGET(dr7->HWBP_SIZE[2], 1))
        BITSET(ret, 27);
    if (BITGET(dr7->HWBP_TYPE[3], 0))
        BITSET(ret, 28);
    if (BITGET(dr7->HWBP_TYPE[3], 1))
        BITSET(ret, 29);
    if (BITGET(dr7->HWBP_SIZE[3], 0))
        BITSET(ret, 30);
    if (BITGET(dr7->HWBP_SIZE[3], 1))
        BITSET(ret, 31);
    return ret;
}
 
// 保存所有下断点的线程ID和相应寄存器
std::vector<HardwareBreakpoint> hwbrk;
// 设置硬件断点,在线程里调用
int RunHwBreakpoint(HANDLE HThread, HWBP_DRX Drx, HWBP_TYPE Type, HWBP_SIZE Size, ULONG_PTR breakpoint)
{
    SuspendThread(HThread);
    CONTEXT context = { 0 };
    context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
    GetThreadContext(HThread, &context);
 
    if (Drx == Dr0) { context.Dr0 = breakpoint; }
    if (Drx == Dr1) { context.Dr1 = breakpoint; }
    if (Drx == Dr2) { context.Dr2 = breakpoint; }
    if (Drx == Dr3) { context.Dr3 = breakpoint; }
 
    HWBP_MODE hwbpMode;
    DR7 dr7;
    hwbpMode = MODE_LOCAL;
    dr7.HWBP_MODE[Drx] = hwbpMode;
    dr7.HWBP_TYPE[Drx] = Type;
    dr7.HWBP_SIZE[Drx] = Size;
    context.Dr7 |= dr7uint(&dr7);
 
    SetThreadContext(HThread, &context);
    ResumeThread(HThread);
    // 将当前断点信息存入 vector
    HardwareBreakpoint* h = new HardwareBreakpoint();
    h->hwbpAddr = breakpoint;
    h->threadId = GetThreadId(HThread);
    h->Drx = Drx;
    hwbrk.push_back(*h);
    delete[] h;
    h = NULL;
    return 1;
}
 
DWORD WINAPI BPThreadProc(LPVOID lpParameter)
{
    HardwareBreakpoint* h = (HardwareBreakpoint*)lpParameter;
    if (!h)return 0;
 
    if (h->threadId) {
        //方式一:对指定的线程下硬件断点
        HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, false, h->threadId);
        if (hThread)
        {
            RunHwBreakpoint(hThread, h->Drx, h->Type, h->Size, h->hwbpAddr);  //下硬件断点
            CloseHandle(hThread);
            return 1;
        }
    }
    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())
                    {
                        HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, false, te.th32ThreadID);
                        if (hThread)
                        {
                            RunHwBreakpoint(hThread, h->Drx, h->Type, h->Size, h->hwbpAddr);  //下硬件断点
                            CloseHandle(hThread);
                        }
                    }
                } while (Thread32Next(hSnap, &te));
            }
        }
        if (hSnap) CloseHandle(hSnap);
    }
    return 1;
}
 
// 设置硬件断点
ULONG_PTR SetHwBreakpoint(int ThreadId, HWBP_DRX Drx, HWBP_TYPE Type, HWBP_SIZE Size, ULONG_PTR breakpoint)
{
    HardwareBreakpoint* h = new HardwareBreakpoint();
    h->threadId = ThreadId;
    h->Drx = Drx;
    h->Type = Type;
    h->Size = Size;
    h->hwbpAddr = breakpoint;
 
    HANDLE handle = CreateThread(NULL, NULL, BPThreadProc, (LPVOID)h, NULL, NULL);
    WaitForSingleObject(handle, INFINITE); //等待异常消息
    CloseHandle(handle);
    delete[] h;
    h = NULL;
    return breakpoint;
}
 
// 删除硬件断点 DelHwBreakpoint(ExceptionInfo->ContextRecord, 0x123456);
bool DelHwBreakpoint(PCONTEXT context, ULONG_PTR breakpoint)
{
    if (hwbrk.size() <= 0) return false;
    for (auto& h : hwbrk)
    {
        if (h.hwbpAddr == breakpoint)
        {
            int FlagBit = 0;
            if (h.Drx == Dr0)
            {
                FlagBit = 0;
                context->Dr0 = 0;
            }
            if (h.Drx == Dr1)
            {
                FlagBit = 2;
                context->Dr1 = 0;
            }
            if (h.Drx == Dr2)
            {
                FlagBit = 4;
                context->Dr2 = 0;
            }
            if (h.Drx == Dr3)
            {
                FlagBit = 6;
                context->Dr3 = 0;
            }
            context->Dr7 &= ~(1 << FlagBit);
            context->Dr7 &= ~(1 << (FlagBit + 1));
 
            // 删除用过的元素
            for (int i = hwbrk.size() - 1; i >= 0; i--) {
                if (hwbrk[i] == h) {
                    hwbrk.erase(hwbrk.begin() + i);
                }
            }
            return true;
        }
    }
    return false;
}

再创建一个HardwareBreakpoint.h文件,写如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#pragma once
#include <Windows.h>
 
enum HWBP_DRX
{
    Dr0 = 0,
    Dr1 = 1,
    Dr2 = 2,
    Dr3 = 3
};
enum HWBP_TYPE
{
    TYPE_EXECUTE = 0,    //00  执行
    TYPE_WRITE = 1,      //01 
    TYPE_READWRITE = 3   //11  /
};
 
enum HWBP_SIZE
{
    SIZE_1 = 0,         //00
    SIZE_2 = 1,         //01
    SIZE_8 = 2,         //10
    SIZE_4 = 3          //11
};
 
/************************************************************************
函数名称: SetHwBreakpoint
函数功能: 设置线程硬件断点
输入参数: ThreadId 线程ID0为所有线程下断,否则指定线程下断
          Drx:     参考 enum HWBP_DRX
          Type:    参考 enum HWBP_TYPE
          Size:    参考 enum HWBP_SIZE
          dwAddr   断点位置
返    回: 当前断点位置
调    用: SetHwBreakpoint(GetCurrentThreadId(), Dr0, TYPE_EXECUTE, SIZE_1, bp1);
/************************************************************************/
ULONG_PTR SetHwBreakpoint(int ThreadId, HWBP_DRX Drx, HWBP_TYPE Type, HWBP_SIZE Size, ULONG_PTR dwAddr);
 
/************************************************************************
函数名称: DelHwBreakpoint
函数功能: 删除硬件断点
输入参数: context  PCONTEXT指针:ExceptionInfo->ContextRecord
          dwAddr   断点地址:0x123456
返    回: 成功返回ture,否则返回false
调    用: DelHwBreakpoint(ExceptionInfo->ContextRecord, 0x123456);
/************************************************************************/
bool DelHwBreakpoint(PCONTEXT context, ULONG_PTR dwAddr);

最后,调用示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// HWBP_Demo.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
 
#include <iostream>
#include "HardwareBreakpoint.h"
 
using namespace std;
 
ULONG_PTR bp1, bp2, bp3;
 
LONG NTAPI ExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo)
{
    cout << "异常地址:" << ExceptionInfo->ExceptionRecord->ExceptionAddress << endl;
 
    if ((ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress == bp2)
    {
        cout << "bp2异常" << endl;
        //DelHwBreakpoint(ExceptionInfo->ContextRecord, bp2);
        ExceptionInfo->ContextRecord->EFlags |= 1 << 16; //0x10000
        return EXCEPTION_CONTINUE_EXECUTION;
    }
    else if ((ULONG_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress == bp3)
    {
        cout << "bp3异常" << endl;
        //DelHwBreakpoint(ExceptionInfo->ContextRecord, bp3);
        ExceptionInfo->ContextRecord->EFlags |= 1 << 16; //0x10000
        return EXCEPTION_CONTINUE_EXECUTION;
    }
    else if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP) {//STATUS_SINGLE_STEP
        cout << "写入异常" << endl;
        DelHwBreakpoint(ExceptionInfo->ContextRecord, bp1);
        //ExceptionInfo->ContextRecord->EFlags |= 1 << 16; //0x10000
        return EXCEPTION_CONTINUE_EXECUTION;
    }
 
    return EXCEPTION_CONTINUE_SEARCH;
}
 
int main()
{
    AddVectoredExceptionHandler(1, ExceptionHandler);
 
    std::string str = "123456789";
    bp1 = (ULONG_PTR)str.c_str();
    bp2 = (ULONG_PTR)GetProcAddress(GetModuleHandle(L"user32.dll"), "IsWindow");
    bp3 = (ULONG_PTR)GetProcAddress(GetModuleHandle(L"user32.dll"), "GetWindow");
 
    cout << hex << "bp1:" << bp1 << endl;
    SetHwBreakpoint(0, Dr0, TYPE_WRITE, SIZE_4, bp1); //设置硬件写入断点
    SetHwBreakpoint(0, Dr1, TYPE_EXECUTE, SIZE_1, bp2);//设置硬件执行断点
    SetHwBreakpoint(0, Dr2, TYPE_EXECUTE, SIZE_1, bp3);//设置硬件执行断点
 
    *(BYTE*)(bp1 + 1) = 0x35//模拟写入数据
    IsWindow(NULL);//模拟调用函数
    GetWindow(NULL, 1);//模拟调用函数
 
    *(BYTE*)(bp1 + 1) = 0x36; //模拟写入数据
    IsWindow(NULL);//模拟调用函数
    GetWindow(NULL, 1);//模拟调用函数
 
    system("pause");
    return 0;
}

执行效果:


工程源码使用VS2022 C++14

也可使用HijackTingMix.zip静态库,库里为加强版避免了GetThreadContext和SetThreadContext被hook了,不能设置的问题,


[峰会]看雪.第八届安全开发者峰会10月23日上海龙之梦大酒店举办!

最后于 2024-10-9 15:34 被wtujoxk编辑 ,原因:
上传的附件:
收藏
免费 3
支持
分享
最新回复 (5)
雪    币: 1392
活跃值: (5002)
能力值: ( LV13,RANK:240 )
在线值:
发帖
回帖
粉丝
2
10年前用这个方案做过war3的外挂,避免crc校验。
2024-10-9 11:21
0
雪    币: 3379
活跃值: (3757)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
希望大佬编译个vs2013版的。
2024-10-9 12:56
0
雪    币: 302
活跃值: (610)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
院士 希望大佬编译个vs2013版的。[em_13]
增加了一个其它语言调用示例,你自己封装一下就是可以在其它版本或语言调用了!
2024-10-9 15:35
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
Safengine Shielden 保护程序 有反硬件断点 无法劫持
2024-10-10 04:04
0
雪    币: 12175
活跃值: (4928)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6


下载凭证已过期,请刷新页面重新尝试下载。

刷新一下网页,可以下

奇怪

最后于 2024-10-10 11:26 被xie风腾编辑 ,原因:
2024-10-10 11:25
0
游客
登录 | 注册 方可回帖
返回
//