Windows平台调试器原理与编写02.一般断点与反汇编引擎

news/2025/2/23 14:43:16/文章来源:https://www.cnblogs.com/weiyuanzhang/p/18732113

https://www.bpsend.net/thread-256-1-2.html

一般断点(软件断点)

断点的尊严

  1. 断的下来
  2. 走的过去
  3. 下次还来

所有合格的断点都应该满足这3个要求

OD下断点实际是把指令的第一个字节改成了CC,当程序执行到CC的时候其实是抛了一个异常(EXCEPTION_BREAKPOINT),这个异常就会进入调试器里面因为处于调试状态,调试器拿到这个异常之后就会知道程序要断到这里,写了CC之后,这条指令正常的功能就被破坏了,但是这条指令正常功能中他还是应该执行的,那怎么让他走过去呢,那就是把这条指令恢复,下次再来只需要走过去之后再把它写回CC,这条指令执行完可通过 TF 标志位 来实现, (TF置1就会抛出异常(EXCEPTION_SINGLE_STEP)),

img

断步配合: 断点和单步配合实现断点下次再来

调试的时候 如果 断点下次没来 就检查断步配合,如果崩了说明没有恢复,如果程序跑飞了,断点不再来,说明单步没处理好

调试器对被调试进程拥有所有的权限(除了写)

img

第二个成员就是调试器判断异常第一个次来还是第二次

第一个成员,异常信息结构体

img

获取寄存器环境 GetThreadContext

img

第一个参数: 线程句柄 ,第二个结构体指针(结构体类型要到 vs中去看, msdn没有)

代码实现

以扫雷为例

扫雷的过程函数:
地址                    机器码           助记符
01001BC9          55                  push    ebp
01001BCA         8BEC             mov     ebp, esp
01001BCC         83EC 40        sub     esp, 40
01001BCF         8B55 0C        mov     edx, dword ptr [ebp+C]        //在该行下断点
01001BD2         8B4D 14       mov     ecx, dword ptr [ebp+14]
01001BD5         53                  push    ebx
01001BD6         56                  push    esi
01001BD7         33DB             xor     ebx, ebx
.586
.model flat,stdcall
option casemap:noneinclude windows.incinclude user32.incinclude kernel32.incinclude msvcrt.incincludelib user32.libincludelib kernel32.libincludelib msvcrt.lib.datag_szExe db "winmine.exe", 0     ;被调试的程序g_hExe  dd 0                    ;被调试的程序句柄g_szEXCEPTION_DEBUG_EVENT         db "EXCEPTION_DEBUG_EVENT", 0dh, 0ah, 0g_szCREATE_THREAD_DEBUG_EVENT     db "CREATE_THREAD_DEBUG_EVENT", 0dh, 0ah, 0g_szCREATE_PROCESS_DEBUG_EVENT    db "CREATE_PROCESS_DEBUG_EVENT", 0dh, 0ah, 0g_szEXIT_THREAD_DEBUG_EVENT       db "EXIT_THREAD_DEBUG_EVENT", 0dh, 0ah, 0g_szEXIT_PROCESS_DEBUG_EVENT      db "EXIT_PROCESS_DEBUG_EVENT", 0dh, 0ah, 0g_szLOAD_DLL_DEBUG_EVENT          db "LOAD_DLL_DEBUG_EVENT", 0dh, 0ah, 0g_szUNLOAD_DLL_DEBUG_EVENT        db "UNLOAD_DLL_DEBUG_EVENT", 0dh, 0ah, 0g_szOUTPUT_DEBUG_STRING_EVENT     db "OUTPUT_DEBUG_STRING_EVENT", 0dh, 0ah, 0g_szLoadDllFmt    db "%08X %s", 0dh, 0ah, 0g_szwLoadDllFmt   dw '%', '0', '8', 'X', ' ', '%', 's', 0dh, 0ah, 0g_szBpFmt  db      "CC异常 %08X", 0dh, 0ah, 0g_szSsFmt  db      "单步异常 %08X", 0dh, 0ah, 0g_btOldCode db   0           ;记录没下断点之前的字符g_dwBpAddr  dd   01001BCFh   ;下断点的地址g_byteCC    db   0CCh        ; 短点符号 CC .code  ;处理异常信息
OnException proc uses esi pDE:ptr DEBUG_EVENT LOCAL @dwOldProc:DWORD   ;修改之前的内存属性LOCAL @dwBytesOut:DWORD   LOCAL @hThread:HANDLELOCAL @ctx:CONTEXTmov esi, pDEassume esi:ptr DEBUG_EVENT;判断是否断点异常.if [esi].u.Exception.pExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT;判断是否是自己的CC  通过地址判断mov eax, [esi].u.Exception.pExceptionRecord.ExceptionAddress.if eax != g_dwBpAddr     ;该处地址是不是我们下断点地址;不是自己的CC异常,不处理mov eax, DBG_EXCEPTION_NOT_HANDLED ret.endif;处理自己的CC异常invoke crt_printf, offset g_szBpFmt, [esi].u.Exception.pExceptionRecord.ExceptionAddress;修改内存属性invoke VirtualProtect, g_dwBpAddr, 1, PAGE_EXECUTE_READWRITE, addr @dwOldProc;恢复指令invoke WriteProcessMemory, g_hExe, g_dwBpAddr, offset g_btOldCode, size g_btOldCode, addr @dwBytesOut ;还原内存属性invoke VirtualProtect, g_dwBpAddr, 1, @dwOldProc, addr @dwOldProc;设置单步;获取线程句柄invoke OpenThread, THREAD_ALL_ACCESS, FALSE, [esi].dwThreadIdmov @hThread, eax;设置结构体标志位,用来判断获取那些寄存器环境; CONTEXT_FULL  表示获取控制,整数,段   CONTEXT_ALL 是所有的mov @ctx.ContextFlags, CONTEXT_FULL;获取寄存器环境invoke GetThreadContext, @hThread, addr @ctx;将TF标志位置1or @ctx.regFlag, 100h;返回当前代码地址  @ctx.regEip 执行完CC的地址 dec @ctx.regEip     ;减1,cc是一个字节.;设置寄存器环境invoke SetThreadContext, @hThread, addr @ctx;关闭线程句柄invoke CloseHandle, @hThreadmov eax, DBG_CONTINUEret.endif;单步来了  (如果是单步异常).if [esi].u.Exception.pExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP;处理自己的单步invoke crt_printf, offset g_szSsFmt, [esi].u.Exception.pExceptionRecord.ExceptionAddress;修改内存属性invoke VirtualProtect, g_dwBpAddr, 1, PAGE_EXECUTE_READWRITE, addr @dwOldProc;重设断点, 重新写入CCinvoke WriteProcessMemory, g_hExe,  g_dwBpAddr, offset g_byteCC, size g_byteCC, addr @dwBytesOut;还原内存属性invoke VirtualProtect, g_dwBpAddr, 1, @dwOldProc, addr @dwOldProc;异常已处理,继续执行代码mov eax, DBG_CONTINUEret.endifassume esi:nothingmov eax, DBG_EXCEPTION_NOT_HANDLED retOnException endpOnCreateProcess proc LOCAL @dwBytesOut:DWORD  LOCAL @dwOldProc:DWORD   ;修改之前的内存属性;修改内存属性invoke VirtualProtect, g_dwBpAddr, 1, PAGE_EXECUTE_READWRITE, addr @dwOldProc;保存原来的被下断点地址 指令到 g_btOldCode ,用于恢复invoke ReadProcessMemory, g_hExe, g_dwBpAddr, offset g_btOldCode, size g_btOldCode, addr @dwBytesOut;在 01001BCF(断点地址)写入CCinvoke WriteProcessMemory, g_hExe,  g_dwBpAddr, offset g_byteCC, size g_byteCC, addr @dwBytesOut;还原内存属性invoke VirtualProtect, g_dwBpAddr, 1, @dwOldProc, addr @dwOldProcretOnCreateProcess endpmain procLOCAL @si:STARTUPINFOLOCAL @pi:PROCESS_INFORMATIONLOCAL @de:DEBUG_EVENT LOCAL @dwStatus:DWORD   ;事件处理结果invoke RtlZeroMemory, addr @si, size @siinvoke RtlZeroMemory, addr @pi, size @piinvoke RtlZeroMemory, addr @de, size @demov @dwStatus, DBG_CONTINUE;建立调试会话invoke CreateProcess, NULL, offset g_szExe, NULL, NULL, FALSE, \DEBUG_ONLY_THIS_PROCESS,\NULL, NULL,\addr @si,\addr @pi.if !eaxret.endif mov eax, @pi.hProcessmov g_hExe, eax;循环接受调试事件.while TRUEinvoke WaitForDebugEvent, addr @de, INFINITE;处理调试事件.if @de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT;invoke crt_printf, offset g_szEXCEPTION_DEBUG_EVENTinvoke OnException, addr @demov @dwStatus, eax.elseif @de.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENTinvoke crt_printf, offset g_szCREATE_THREAD_DEBUG_EVENT.elseif @de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT;invoke crt_printf, offset g_szCREATE_PROCESS_DEBUG_EVENTinvoke OnCreateProcess.elseif @de.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENTinvoke crt_printf, offset g_szEXIT_THREAD_DEBUG_EVENT.elseif @de.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENTinvoke crt_printf, offset g_szEXIT_PROCESS_DEBUG_EVENT.elseif @de.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT;invoke OnLoadDll, addr @de.elseif @de.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENTinvoke crt_printf, offset g_szUNLOAD_DLL_DEBUG_EVENT.elseif @de.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENTinvoke crt_printf, offset g_szOUTPUT_DEBUG_STRING_EVENT.endif;提交事件处理结果invoke ContinueDebugEvent, @de.dwProcessId, @de.dwThreadId, @dwStatusinvoke RtlZeroMemory, addr @de, size @de.endwretmain endpstart:invoke main end start

反汇编引擎

https://bbs.pediy.com/thread-205590.htm

udis86官网 http://udis86.sourceforge.net/

📎udis86.zip

00513D41    8945 FC         mov     dword ptr [ebp-4], eax
00513D44    817D FC 4EE640B>cmp     dword ptr [ebp-4], BB40E64E
00513D4B    75 09           jnz     short 00513D56
00513D4D    C745 FC 4FE640B>mov     dword ptr [ebp-4], BB40E64F
00513D54    EB 1C           jmp     short 00513D72
00513D56    8B55 FC         mov     edx, dword ptr [ebp-4]
00513D59    81E2 0000FFFF   and     edx, FFFF0000
00513D5F    75 11           jnz     short 00513D72
00513D61    8B45 FC         mov     eax, dword ptr [ebp-4]
00513D64    0D 11470000     or      eax, 4711
00513D69    C1E0 10         shl     eax, 10
00513D6C    0B45 FC         or      eax, dword ptr [ebp-4]
00513D6F    8945 FC         mov     dword ptr [ebp-4], eax
00513D72    8B4D FC         mov     ecx, dword ptr [ebp-4]
00513D75    890D 04A05100   mov     dword ptr [__security_cookie], e>
00513D7B    8B55 FC         mov     edx, dword ptr [ebp-4]
00513D7E    F7D2            not     edx
00513D80    8915 00A05100   mov     dword ptr [__security_cookie_com>
00513D86    8BE5            mov     esp, ebp
00513D88    5D              pop     ebp
00513D89    C3              ret
#include "udis86.h"
#pragma comment(lib, "libudis86.lib")#include <iostream>
using namespace std;int  main()
{unsigned char data[73] = {0x89, 0x45, 0xFC, 0x81, 0x7D, 0xFC, 0x4E, 0xE6, 0x40, 0xBB, 0x75, 0x09, 0xC7, 0x45, 0xFC, 0x4F,0xE6, 0x40, 0xBB, 0xEB, 0x1C, 0x8B, 0x55, 0xFC, 0x81, 0xE2, 0x00, 0x00, 0xFF, 0xFF, 0x75, 0x11,0x8B, 0x45, 0xFC, 0x0D, 0x11, 0x47, 0x00, 0x00, 0xC1, 0xE0, 0x10, 0x0B, 0x45, 0xFC, 0x89, 0x45,0xFC, 0x8B, 0x4D, 0xFC, 0x89, 0x0D, 0x04, 0xA0, 0x51, 0x00, 0x8B, 0x55, 0xFC, 0xF7, 0xD2, 0x89,0x15, 0x00, 0xA0, 0x51, 0x00, 0x8B, 0xE5, 0x5D, 0xC3};ud_t ud_obj;                                        //定义ud_init(&ud_obj);                                   //初始化ud_set_input_buffer(&ud_obj, data, sizeof(data));   //缓冲区来源ud_set_mode(&ud_obj, 32);                           //32还是64位反汇编ud_set_syntax(&ud_obj, UD_SYN_INTEL);               //默认语法     ud_set_pc(&ud_obj, 0x00513D41);                     //指令开始地址while (ud_disassemble(&ud_obj))                     //开始反汇编{auto nLen = ud_insn_len(&ud_obj);   //当前指令长度auto nOff = ud_insn_off(&ud_obj);   //EIP  当前指令地址auto pHex = ud_insn_hex(&ud_obj);   //机器码auto ptr = ud_insn_ptr(&ud_obj);    //在本程序内存中的地址auto opr = ud_insn_opr(&ud_obj, 0);  auto mn = ud_insn_mnemonic(&ud_obj);auto mn0 = ud_lookup_mnemonic(mn);cout << hex << nOff << " "<< pHex << "\t\t"<< ud_insn_asm(&ud_obj) << endl;              //反汇编结果}return 0;
}

img

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

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

相关文章

输入搜索、分组展示选项、下拉选取,全局跳转页,el-select 实现 —— 后端数据处理代码,抛砖引玉展思路

详细前端代码写于上一篇:输入搜索、分组展示选项、下拉选取,el-select 实现:即输入关键字检索,返回分组选项,选取跳转到相应内容页 —— VUE项目-全局模糊检索 【效果图】:分组展示选项 =>【提供界面操作体验】 【mybatis】:多数据表抓取数据<select id="fin…

使用@SpringBootApplication注解

https://docs.spring.io/spring-boot/docs/2.0.x/reference/html/using-boot-using-springbootapplication-annotation.html许多Spring Boot开发人员希望他们的应用程序能够使用自动配置(auto-configuration)、组件扫描(component scan),并能够在其“应用程序类(applicat…

跨时钟域-单脉冲信号处理方法

逻辑设计中将所有同步元件(例如触发器和RAM等)使用相同时钟信号的部分称为时钟域。 退出亚稳态所需的时间被称为resolution Time(Tr)。 由于建立时间的违反,寄存器的输出电压可能是代表逻辑高、逻辑低,甚至更糟糕的是介于逻辑高和逻辑低之间的电压。 亚稳态是指触发器无法…

VMWare workstation pro 17 Windows11 中提示不能 支持Intel VT-x 虚拟化的问题终极解决方案

1. 在BIOS中开启虚拟化 2. 在系统功能里面取消hyper-v,虚拟机管理平台,沙盒功能, 虚拟机监控平台四个功能。 3. 在内核隔离里面取消内存隔离。 4. 运行下面的批处理。 5.重启后会有两次提示是否关闭vbs,两次按F3关闭,重启后一切正常。===================================…

PipeCAD Spooler 管道加工设计工具

PipeCAD Spooler是一款专门为管道预制厂商设计的管道深化加工设计和管理的工具。有以下一些功能:+ 直接导入PCF/IDF管道数据进行深化设计,大大提高设计效率; + 精确的材料统计,为材料采购提供准确数据; + 通过深化设计将管线拆分为易于车间加工的管段,提高加工质量,缩短…

『Python底层原理』--Python属性的工作原理

Python中的属性操作(如获取、设置和删除属性)是我们日常编程中非常常见的操作。 但你有没有想过,当我们写下obj.attr或obj.attr = value时,Python 内部究竟发生了什么? 本文将探讨Python属性的工作原理,并通过简单的代码示例来更好地理解这些概念。 1. 属性的基本操作 在…

deepseek最小模型安装部署

参考:DeepSeek本地部署详细指南访问ollama官网下载 这里我选择的是windows版本,因为本人设备能力有限,准备后续安装1.5B版本进行初步学习使用 安装好后,进入命令行执行ollama --version,检查是否安装成功,如出现下述信息,则说明安装成功下载并安装deepseek 1.5b模型部署…

SharePoint Online 使用 Power Automate 新建共享链接

前言似乎很久没关注SharePoint操作的更新了,这个新建共享链接的操作是一个蛮有用的,似乎挺新的。正文1.就是这样的一个操作,配置起来超级简单,如下图:2.链接类型有两个选项,如下图:3.链接的范围有两个属性,如下图:4.运行一下,看看效果,输出的结果就是那个链接,如下…

做销售,要有5不怕!

在销售领域,扎实的专业知识固然重要,但坚韧不拔的精神与积极心态更是不可或缺。以下 “五不怕” 精神,是销售从业者的致胜法宝,助你在销售道路上稳步前行。一、不怕见客户:勇敢开启销售之旅销售的核心在于与人沟通,而见客户是销售的起始点。不少销售人员对这第一步心怀恐…

Deepseek本地知识库(Ollama + Deepseek + Cherry)

Deepseek本地知识库(Ollama + Deepseek + Cherry)需要使用到的技术以及站点Ollama: https://ollama.com/download DeepSeek: https://ollama.com/library/deepseek-r1:7b bge-m3: https://ollama.com/library/bge-m3 Cherry Studio下载: https://cherry-ai.com/0x00 前言…

进程管理章节

调度器章节 Linux进程调度器概述--Linux进程的管理与调度(十五) Linux进程调度策略的发展和演变--Linux进程的管理与调度(十六) Linux进程调度器的设计--Linux进程的管理与调度(十七) Linux核心调度器之周期性调度器scheduler_tick--Linux进程的管理与调度(十八) Linux进程…

[计算机网络] Windows 网络管理

概述: Windows 网络管理 FAQ for Windows 网络 Q: 开放 Windows 的 ICMP v4,允许其他主机的ping问题描述vmware 中 桥接模式下的centos 虚拟机(172.10.31.104) 无法ping通在同一局域网的宿主机IP(172.10.31.21、,但该centos能访问baidu.com等互联网网络,且宿主机也能ping通…