12558网页游戏私服论坛

 找回密码
 立即注册
游戏开服表 申请开服
游戏名称 游戏描述 开服状态 游戏福利 运营商 游戏链接
攻城掠地-仿官 全新玩法,觉醒武将,觉醒技能 每周新区 经典复古版本,长久稳定 进入游戏
巅峰新版攻 攻城掠地公益服 攻城掠地SF 新兵种、新武将(兵种) 进入游戏
攻城掠地公 散人玩家的天堂 新开 进入游戏
改版攻城掠 上线即可国战PK 稳定新区 全新改版,功能强大 进入游戏
少年江山 高福利高爆率 刚开一秒 江湖水落潜蛟龙 进入游戏
太古封魔录 开服送10亿钻石 福利多多 不用充钱也可升级 进入游戏
神魔之道 签到送元宝 稳定开新区 送豪华签到奖励 进入游戏
神奇三国 统帅三军,招揽名将 免费玩新区 激情国战,征战四方 进入游戏
龙符 三日豪礼领到爽 天天开新区 助你征战无双 进入游戏
王者之师 免费领豪华奖励 免费玩新区 6元送6888元宝 进入游戏
查看: 1570|回复: 0

硬件断点的原理与实现

[复制链接]

59

主题

59

帖子

128

积分

实习版主

Rank: 7Rank: 7Rank: 7

积分
128
发表于 2019-8-14 20:08:59 | 显示全部楼层 |阅读模式
硬件断点的原理

Intel 80306以上的CPU给我们提供了调试寄存器用于软件调试,硬件断点是通过设置调试寄存器实现的。

​                                        图1 调试寄存器
图1为Intel手册提供的32位操作系统下8个调试寄存器的图示(Intel手册卷3 17章第二节 Debug Registers,有兴趣的朋友可以查阅),根据介绍,DR0-DR3为设置断点的地址,DR4和DR5为保留,
DR6为调试异常产生后显示的一些信息,DR7保存了断点是否启用、断点类型和长度等信息。
我们在使用硬件断点的时候,就是要设置调试寄存器,将断点的位置设置到DR0-DR3中,断点的长度设置到DR7的LEN0-LEN3中,将断点的类型设置到DR7的RW0-RW3中,将是否启用断点设置到DR7的L0-L3中。
设置硬件断点需要的DR0-DR3很简单,就是下断点的地址,DR7寄存器很复杂,位段信息结构体如下:
typedef struct _DBG_REG7{        /*        // 局部断点(L0~3)与全局断点(G0~3)的标记位        */        unsigned L0 : 1;  // 对Dr0保存的地址启用 局部断点        unsigned G0 : 1;  // 对Dr0保存的地址启用 全局断点        unsigned L1 : 1;  // 对Dr1保存的地址启用 局部断点        unsigned G1 : 1;  // 对Dr1保存的地址启用 全局断点        unsigned L2 : 1;  // 对Dr2保存的地址启用 局部断点        unsigned G2 : 1;  // 对Dr2保存的地址启用 全局断点        unsigned L3 : 1;  // 对Dr3保存的地址启用 局部断点        unsigned G3 : 1;  // 对Dr3保存的地址启用 全局断点                                          /*                                          // 【以弃用】用于降低CPU频率,以方便准确检测断点异常                                          */        unsigned LE : 1;        unsigned GE : 1;        /*        // 保留字段        */        unsigned Reserve1 : 3;        /*        // 保护调试寄存器标志位,如果此位为1,则有指令修改条是寄存器时会触发异常        */        unsigned GD : 1;        /*        // 保留字段        */        unsigned Reserve2 : 2;        unsigned RW0 : 2;  // 设定Dr0指向地址的断点类型         unsigned LEN0 : 2;  // 设定Dr0指向地址的断点长度        unsigned RW1 : 2;  // 设定Dr1指向地址的断点类型        unsigned LEN1 : 2;  // 设定Dr1指向地址的断点长度        unsigned RW2 : 2;  // 设定Dr2指向地址的断点类型        unsigned LEN2 : 2;  // 设定Dr2指向地址的断点长度        unsigned RW3 : 2;  // 设定Dr3指向地址的断点类型        unsigned LEN3 : 2;  // 设定Dr3指向地址的断点长度}DBG_REG7, *PDBG_REG7;需要注意的是,设置硬件断点时,断点的长度、类型和地址是有要求的。

​                                                        图2 调试寄存器的设置要求
如图2所示,保存DR0-DR3地址所指向位置的断点类型(RW0-RW3)与断点长度(LEN0-LEN3),状态描述如下:
​        00:执行         01:写入        11:读写
​        00:1字节       01:2字节      11:4字节
设置硬件执行断点时,长度只能为1(LEN0-LEN3设置为0时表示长度为1)
设置读写断点时,如果长度为1,地址不需要对齐,如果长度为2,则地址必须是2的整数倍,如果长度为4,则地址必须是4的整数倍。
原理大概就是这么多了,下面就是实现了。
硬件断点的实现

实现硬件断点,首先要获取当前线程环境
//获取线程环境CONTEXT g_Context = { 0 };g_Context.ContextFlags = CONTEXT_CONTROL;GetThreadContext(hThread, &g_Context);在CONTEXT结构体中,存放了诸多当前线程环境的信息,以下是从winnt.h文件中找到的CONTEXT结构体
typedef struct _CONTEXT {    //    // The flags values within this flag control the contents of    // a CONTEXT record.    //    // If the context record is used as an input parameter, then    // for each portion of the context record controlled by a flag    // whose value is set, it is assumed that that portion of the    // context record contains valid context. If the context record    // is being used to modify a threads context, then only that    // portion of the threads context will be modified.    //    // If the context record is used as an IN OUT parameter to capture    // the context of a thread, then only those portions of the thread's    // context corresponding to set flags will be returned.    //    // The context record is never used as an OUT only parameter.    //    DWORD ContextFlags;    //    // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is    // set in ContextFlags.  Note that CONTEXT_DEBUG_REGISTERS is NOT    // included in CONTEXT_FULL.    //    DWORD   Dr0;    DWORD   Dr1;    DWORD   Dr2;    DWORD   Dr3;    DWORD   Dr6;    DWORD   Dr7;    //    // This section is specified/returned if the    // ContextFlags word contians the flag CONTEXT_FLOATING_POINT.    //    FLOATING_SAVE_AREA FloatSave;    //    // This section is specified/returned if the    // ContextFlags word contians the flag CONTEXT_SEGMENTS.    //    DWORD   SegGs;    DWORD   SegFs;    DWORD   SegEs;    DWORD   SegDs;    //    // This section is specified/returned if the    // ContextFlags word contians the flag CONTEXT_INTEGER.    //    DWORD   Edi;    DWORD   Esi;    DWORD   Ebx;    DWORD   Edx;    DWORD   Ecx;    DWORD   Eax;    //    // This section is specified/returned if the    // ContextFlags word contians the flag CONTEXT_CONTROL.    //    DWORD   Ebp;    DWORD   Eip;    DWORD   SegCs;              // MUST BE SANITIZED    DWORD   EFlags;             // MUST BE SANITIZED    DWORD   Esp;    DWORD   SegSs;    //    // This section is specified/returned if the ContextFlags word    // contains the flag CONTEXT_EXTENDED_REGISTERS.    // The format and contexts are processor specific    //    BYTE    ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];} CONTEXT;从CONTEXT结构体中我们可以看到存放了调试寄存器 Dr0-Dr3和Dr6、Dr7,通过设置这些寄存器我们可以实现硬件断点。
已经获取了当前线程环境,接下来就是设置调试寄存器
//传入下断点的地址、类型、长度void SetHardBP(DWORD addr, BreakPointHard type, BreakPointLen len){    //利用上文中的DR7寄存器位段信息        DBG_REG7 *pDr7 = (DBG_REG7 *)&g_Context.Dr7;    if (len == 1)        {        //两字节的对齐粒度                addr = addr - addr % 2;        }        else if (len == 3)        {        //四字节的对齐粒度                addr = addr - addr % 4;        }        if (pDr7->L0 == 0)        {                g_Context.Dr0 = addr;   //利用Dr0寄存器存放地址                pDr7->RW0 = type;       //Dr7寄存器中的RW0设置类型                pDr7->LEN0 = len;                //Dr7寄存器中的LEN0设置长度                pDr7->L0 = 1;                    //Dr7寄存器中的L0启用断点        }        else if (pDr7->L1 == 0)        {                g_Context.Dr1 = addr;                pDr7->RW1 = type;                pDr7->LEN1 = len;                pDr7->L1 = 1;        }        else if (pDr7->L2 == 0)        {                g_Context.Dr2 = addr;                pDr7->RW2 = type;                pDr7->LEN2 = len;                pDr7->L2 = 1;        }        else if (pDr7->L3 == 0)        {                g_Context.Dr3 = addr;                pDr7->RW3 = type;                pDr7->LEN3 = len;                pDr7->L3 = 1;        }}调试寄存器的信息设置好之后,我们要将当前环境保存
//设置当前环境SetThreadContext(hThread, &g_Context);由此,硬件断点的大致实现思路已经完成。
本人理解有限,如有错误,请批评指正!

来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

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

x
楼主热帖
回复

使用道具 举报

*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|12558网页游戏私服论坛 |网站地图

GMT+8, 2024-4-20 21:22 , Processed in 0.093750 second(s), 31 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

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