软件调试


软件断点

调试的本质是什么?

就是在被调试程序中触发异常,然后被调试程序就会向_DEBUG_OBJECT结构体添加调试事件,这里我们调试器就接管这个异常了(调试的过程就是异常处理的过程)

软件断点

在x64dbg中通过快捷键F2能下一个软件中断,当程序运行到这里时,程序就会停下来,得到程序的控制权,也被称之为中断到调试器

本质上就是在当前指定位置的机器码(硬编码)改为了int 3,这里可以用其他内存搜索工具查看这个下断点的地址,可以发现是被改为了int 3(CC)

在这里插入图片描述

执行流程

  • 被调试进程
    1. 当CPU检测到INT 3指令
    2. 查IDT表找到对应中断处理函数
    3. CommonDispatchException
    4. KiDispatchException
    5. DbgkForwardException搜集并发送调试事件 -> DbgkpSendApiMessage(x,x)
  • 调试器进程
    1. 循环判断调试事件
    2. 取出调试事件
    3. 获取CPU寄存器上下文和内存
    4. 用户处理

代码测试

#include<iostream>
#include<windows.h>
#include <stdint.h>
#include <capstone/capstone.h>
#define DEBUGGR_PROCESS L"C:\\Users\\BananaLi\\Desktop\\HookMe.exe"// 保存原始字节
BYTE originalByte;
BYTE int3 = 0xCC;  // INT3 断点指令HANDLE g_hDebugThread;
BOOL bInitCapstone = TRUE;
CONTEXT context = { 0 };
BOOL bIsSystemInt3 = TRUE; // 第一次为系统断点 ntdll!LdrInitializeThunk
DWORD dwContinue DBG_CONTINUE;LPVOID lpAddress;
HANDLE hProcess;// 定义 Capstone 函数指针类型
typedef unsigned int (*cs_open_fn)(unsigned int arch, unsigned int mode, void** handle);
typedef unsigned int (*cs_disasm_fn)(void* handle, const uint8_t* code, size_t code_size, uint64_t address, size_t count, cs_insn** insn);
typedef void (*cs_free_fn)(cs_insn* insn, size_t count);
typedef unsigned int (*cs_close_fn)(void** handle);void DisassembleHex(HANDLE hProcess, LPVOID address, size_t size) {// 1. 加载 capstone.dllHMODULE capstone_dll = LoadLibrary(L"C:\\Users\\BananaLi\\Desktop\\capstone_x64.dll");if (!capstone_dll) {printf("Failed to load capstone.dll! Error: %d\n", GetLastError());}// 2. 获取函数指针cs_open_fn cs_open = (cs_open_fn)GetProcAddress(capstone_dll, "cs_open");cs_disasm_fn cs_disasm = (cs_disasm_fn)GetProcAddress(capstone_dll, "cs_disasm");cs_free_fn cs_free = (cs_free_fn)GetProcAddress(capstone_dll, "cs_free");cs_close_fn cs_close = (cs_close_fn)GetProcAddress(capstone_dll, "cs_close");if (!cs_open || !cs_disasm || !cs_free || !cs_close) {printf("Failed to get Capstone functions!\n");FreeLibrary(capstone_dll);}// 3. 初始化 Capstone(x64 模式)void* handle;if (cs_open(CS_ARCH_X86, CS_MODE_64, &handle) != CS_ERR_OK) {printf("Failed to initialize Capstone!\n");FreeLibrary(capstone_dll);}// 2. 从内存读取指令字节uint8_t code[32];SIZE_T bytesRead;if (!ReadProcessMemory(hProcess, address, code, size, &bytesRead) || bytesRead != size) {printf("Failed to read memory at 0x%p\n", address);cs_close(&handle);return;}// 3. 反汇编cs_insn* insn;size_t count = cs_disasm(handle, code, bytesRead, (uint64_t)address, 0, &insn);if (count > 0) {printf("Disassembly at 0x%p:\n", address);printf("Address    | Bytes       | Assembly\n");printf("----------------------------------\n");for (size_t i = 0; i < count; i++) {printf("0x%08llx | ", insn[i].address);for (size_t j = 0; j < insn[i].size; j++) {printf("%02x ", insn[i].bytes[j]);}printf("%*s | %s %s\n",(int)(15 - insn[i].size * 3), "",insn[i].mnemonic,insn[i].op_str);}cs_free(insn, count);}else {printf("Failed to disassemble at 0x%p\n", address);}// 4. 关闭引擎cs_close(&handle);
}BOOL WaitForUserCommand() {// 模拟调试器等待用户输入命令printf("请输入命令:\n");system("pause");return TRUE;
}BOOL Int3ExcptionProc(EXCEPTION_DEBUG_INFO* pExceptionInfo) {BOOL bRet = FALSE;// 第一次为系统断点if (bIsSystemInt3) {bIsSystemInt3 = FALSE;return TRUE;}else {// 恢复原码BOOL nnn = WriteProcessMemory(hProcess, pExceptionInfo->ExceptionRecord.ExceptionAddress, &originalByte, 1, NULL);printf("error : %d\n", GetLastError());// 显示断点位置printf("Int 3断点地址:0x%p\n",pExceptionInfo->ExceptionRecord.ExceptionAddress);// 获取线程上下文context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;GetThreadContext(g_hDebugThread, &context);// 修正ripcontext.Rip--;printf("rip的值:0x%p\n\n", context.Rip);GetThreadContext(g_hDebugThread, &context);FlushInstructionCache(GetCurrentProcess(),(LPCVOID)context.Rip,1);printf("------------还原后的正确汇编指令------------\n");// 从断点位置解释反汇编代码DisassembleHex(hProcess, lpAddress,16);// 等待用户输入命令while (bRet == FALSE) {bRet = WaitForUserCommand();}}return bRet;
}void setInt3BreakPoint(DEBUG_EVENT* pDebugEvent) {// 获取进程入口点地址LPTHREAD_START_ROUTINE lpStartAddress = (LPTHREAD_START_ROUTINE)pDebugEvent->u.CreateProcessInfo.lpStartAddress;hProcess = pDebugEvent->u.CreateProcessInfo.hProcess; lpAddress = pDebugEvent->u.CreateProcessInfo.lpStartAddress;printf("断点位置:0x%p\n",lpAddress);DWORD64 oldAddressData;ReadProcessMemory(hProcess, lpAddress, &oldAddressData, sizeof(DWORD64), NULL);printf("保存前断点地址对应的硬编码:%llx\n" , oldAddressData);// 1. 保存原始字节ReadProcessMemory(hProcess, lpAddress, &originalByte, sizeof(BYTE), NULL);printf("保存的originalByte:%llx\n", originalByte);// 2. 写入INT3指令WriteProcessMemory(hProcess, lpAddress, &int3, sizeof(BYTE), NULL);ReadProcessMemory(hProcess, lpAddress, &oldAddressData, sizeof(DWORD64), NULL);printf("保存后断点地址对应的硬编码:%llx\n\n", oldAddressData);printf("------------设置软件断点后的汇编指令------------\n");// 从断点位置解释反汇编代码DisassembleHex(hProcess, lpAddress, 16);// 3. 刷新指令缓存FlushInstructionCache(hProcess, lpAddress, sizeof(BYTE));
}// 异常过滤器
BOOL ExceptionHandler(DEBUG_EVENT* pDebugEvent) {BOOL bRet = TRUE;// 得到异常信息EXCEPTION_DEBUG_INFO exceptionInfo = pDebugEvent->u.Exception;// 得到线程句柄g_hDebugThread = OpenThread(THREAD_ALL_ACCESS, FALSE, pDebugEvent->dwThreadId);// 判断 异常类型switch (exceptionInfo.ExceptionRecord.ExceptionCode) {// int 3 异常case EXCEPTION_BREAKPOINT: {printf("断点异常\n");bRet = Int3ExcptionProc(&exceptionInfo);break;}// 还有很多其他的异常类型可以处理。。。}return bRet;}int main() {BOOL nIsContinue = TRUE;DEBUG_EVENT debugEvent = { 0 };BOOL bRet = TRUE;// 1.创建调试进程STARTUPINFO startUpInfo = { 0 };PROCESS_INFORMATION pInfo = { 0 };GetStartupInfo(&startUpInfo);bRet = CreateProcess(DEBUGGR_PROCESS, NULL, NULL, NULL, TRUE, DEBUG_PROCESS || DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &startUpInfo, &pInfo);if (bRet == FALSE) {printf("创建调试进程失败,错误码:%d\n",GetLastError());return 0;}// 调试循环(主框架)while (nIsContinue) {// 2.等待调试事件bRet = WaitForDebugEvent(&debugEvent, INFINITE);if (bRet == FALSE) {printf("等待调试事件失败,错误码:%d\n", GetLastError());return 0;}switch (debugEvent.dwDebugEventCode) {case EXCEPTION_DEBUG_EVENT: {// 处理异常bRet = ExceptionHandler(&debugEvent);if (!bRet)dwContinue = DBG_EXCEPTION_NOT_HANDLED;break;}case CREATE_PROCESS_DEBUG_EVENT: {// 在OPE入口设置断点setInt3BreakPoint(&debugEvent);break;}case EXIT_PROCESS_DEBUG_EVENT: {nIsContinue = FALSE;break;}case CREATE_THREAD_DEBUG_EVENT: {break;}case EXIT_THREAD_DEBUG_EVENT: {break;}case LOAD_DLL_DEBUG_EVENT: {break;}case UNLOAD_DLL_DEBUG_EVENT: {break;}default:break;}// 让被调试程序继续运行bRet = ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, dwContinue);}return 0;
}

效果展示

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/92126.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/92126.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/92126.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS】鸿蒙应用开发中常用的三方库介绍和使用示例

&#x1f31f; 鸿蒙应用开发常用三方库指南&#xff08;2025 最新版&#xff09;适用版本&#xff1a;HarmonyOS NEXT / API 12 参考来源&#xff1a;HarmonyOS 三方库中心 截止至 2025 年 8 月 1 日&#xff0c;本文整理了当前社区中下载量高、稳定性强、生态完善的热门三方库…

【通识】C Sharp

1. 使用 \p{名称}构造匹配Unicode常规类别&#xff08;该示例为Pd或“标点、短划线”类别&#xff09;和命名块&#xff08;IsGreek和IsBsicLatin命名块&#xff09; using System; using system.Text.RegularExpressions; public class Example {public static void main() {s…

国内首个开源SCA社区——OpenSCA开源社区

OpenSCA开源社区成果说明项目背景智能时代&#xff0c;软件定义一切。随着开发模式的敏捷化转型&#xff0c;开源代码在软件制品中的占比越来越大&#xff0c;开源软件已然成为软件供应链的重要组成部分。由于其特殊性&#xff0c;开源代码的引入增加了软件应用的风险面&#x…

超聚变:智能体时代,AI原生重构城企数智化基因

2025 世界人工智能大会&#xff08;WAIC&#xff09;世博展览馆内&#xff0c;超聚变展台前人头攒动&#xff0c;其展示的AI落地全栈解决方案及上百个AI应用场景吸引了众多参观者驻足观看。这是今年WAIC大会火爆的一角&#xff0c;更是当下AI应用爆发的一个缩影。当人工智能发展…

Traccar:开源GPS追踪系统的核心价值与技术全景

Traccar&#xff1a;开源GPS追踪系统的核心价值与技术全景 —— 从设备兼容到企业级定位管理的开源实践 一、项目定位&#xff1a;多场景定位管理的开源基石 Traccar是一个高扩展性的开源GPS追踪平台&#xff0c;支持全球超过200种通信协议与2000款GPS设备&#xff08;包括车…

编程与数学 03-002 计算机网络 20_计算机网络课程实验与实践

编程与数学 03-002 计算机网络 20_计算机网络课程实验与实践一、实验环境搭建&#xff08;一&#xff09;使用模拟器&#xff08;如Cisco Packet Tracer&#xff09;搭建网络实验环境&#xff08;二&#xff09;实验设备的配置与连接二、基础网络实验&#xff08;一&#xff09…

15个命令上手Linux!

1、id&#xff0c;显示当前登录系统的用户信息2、pwd&#xff0c;显示当前工作目录的绝对路径3、ls&#xff0c;显示当前目录下的内容&#xff08;ls -r&#xff1a;按反向顺序列出内容&#xff0c;ls -l&#xff1a;以详细列表形式显示&#xff09;4、cd&#xff0c;切换工作目…

MongoDB分片技术实现

MongoDB分片技术实现概述MongoDB分片&#xff08;Sharding&#xff09;是MongoDB的水平扩展解决方案&#xff0c;通过将数据分布到多个分片&#xff08;shard&#xff09;上来处理大数据量和高吞吐量的需求。MongoDB分片架构1. 分片集群组件# MongoDB分片集群架构 version: 3.8…

Python开发环境PyCharm下载与安装

python下载 python下载地址&#xff1a; Download Python | Python.org 上面的下载速度慢的话&#xff0c;用下面的地址下载&#xff08;window&#xff09;&#xff1a; https://download.csdn.net/download/liangmengbk/91580033 PyCharm下载 PyCharm下载地址&#xff1a…

汽车供应链PPAP自动化审核指南:如何用AI实现规则精准匹配与文件智能校验

在汽车行业质量管理的核心环节&#xff0c;PPAP&#xff08;生产件批准程序&#xff09;审核长期困扰着供应商与主机厂。 随着IATF 16949等标准持续升级、新能源零件复杂度激增&#xff0c;传统人工审核模式正面临系统性挑战。 行业数据显示&#xff0c;超过70%的SQE&#xf…

正则表达式在js中的应用

正则表达式在 JavaScript 中的应用非常广泛&#xff0c;尤其是在字符串处理和验证方面。以下是一些常见的正则表达式方法及其应用示例&#xff0c;包括 .test() 方法。 1. .test() 方法 .test() 方法用于测试一个字符串是否匹配正则表达式。如果匹配&#xff0c;返回 true&…

Rust视频处理开源项目精选

Rust视频处理开源项目精选 基于Rust实现的视频处理示例 以下是一些基于Rust实现的视频处理或多媒体相关的开源项目或示例,涵盖编解码、流媒体、分析工具等方向,可作为实际开发参考: 视频编解码与处理 rav1e:Rust编写的AV1视频编码器,高性能且内存安全,适合研究视频压缩…

Python爬虫实战:研究pycrumbs库,构建豆瓣读书数据采集系统

1. 引言 1.1 研究背景 在大数据与人工智能技术快速发展的背景下,互联网作为全球最大的信息载体,蕴含着海量结构化与非结构化数据。高效、合规地获取这些数据成为数据分析、业务决策的前提。网络爬虫作为自动化数据采集工具,通过模拟人类浏览行为遍历网页并提取信息,已成为…

linux的用户操作(详细介绍)

在 Linux 系统中&#xff0c;用户管理是系统管理员的核心工作之一&#xff0c;涉及用户账号的创建、修改、删除、权限分配等操作。Linux 采用多用户多任务机制&#xff0c;通过严格的用户和组管理确保系统安全性和资源分配合理性。以下是 Linux 用户操作的详细介绍&#xff1a;…

k8s常见问题

以下是 Kubernetes 常见问题&#xff08;FAQ&#xff09;的整理&#xff0c;涵盖了初学者和运维人员常遇到的痛点&#xff1a; ​一、部署与安装问题​ ​安装太复杂&#xff1f;​​ 解决方案&#xff1a;使用 ​kubeadm​&#xff08;官方工具&#xff09;、Minikube​&#…

RK Android14 新建分区恢复出厂设置分区数据不擦除及开机动画自定义(一)

文章目录 前言 一、分区创建与参数配置 二、分区挂载配置 三、SELinux 安全策略 四、系统初始化配置 五、开机动画路径重定向 总结 前言 本方案通过在 RK3568 Android 14 系统中创建一个独立的 rk_partition 分区(128MB),实现以下核心功能: 出厂设置保护:该分区在恢复出厂…

如何快速给PDF加书签--保姆级教程

买的电子书没有目录书签看着不舒服&#xff0c;手动加书签加到想吐。想有没有办法快速加书签。这要分为PDF目录部分可以被复制和不可被复制两种情况。不可复制时&#xff0c;要用到工具把目录提取出来&#xff0c;变成文字。 工具&#xff1a;Foxit Phantom福昕阅读器&#xff…

Redis面试精讲 Day 9:Redis模块开发与扩展

【Redis面试精讲 Day 9】Redis模块开发与扩展 文章标签 Redis,模块开发,扩展机制,面试技巧,Redis模块,Redis插件 文章简述 本文是"Redis面试精讲"系列第9天&#xff0c;聚焦Redis模块开发与扩展机制。文章详细解析Redis模块系统的架构设计&#xff0c;包括模块加…

八股训练--Spring

目录 一、引言 二、Spring 1.Spring框架的特性 2.介绍一下IOC和AOP 3.IOC和AOP都是如何实现的 4.怎么实现依赖注入 5.为什么AOP不用静态代理 6.介绍一下反射 7.Spring如何解决循环依赖问题 8.Spring常用注解 9.Spring事务什么情况会失效 10.Bean的生命周期 11.Bean…

无公网环境下在centos7.9上使用kk工具部署k8s平台(amd64架构)

文章目录前言一、环境列表二、思路三、环境准备四、有网环境下准备文件1.下载所需的rpm包2.准备harbor需要用到的镜像3. k8s的镜像文件4、 生成离线安装包5、harbor创建项目脚本五、无公网环境部署单点集群1、基础环境安装2、安装harbor3 、 准备k8s镜像4、安装k8s六、无公网环…