写个自己的调试器

编写一个简易调试器 菜鸡的日常,复习一下调试器,简单CV点代码,调试器调试程序有两种方式,一种是创建进程,另一种便是附加: while (TRUE) { printf("1.创建新的调试进程\n"); printf("2.附加待调试的进程\n"); int input = 0; scanf_s("%d", &input); if (input == 1) { printf("请输入调试进程的路径:\n"); char Path[MAX_PATH] = { 0 }; scanf 阅读详情
对于写了一段时间的程序员来说,了解一些debugger的实质无疑对于技术的提高是有很大帮助的。而debugging自身也是一门非常细节化,比较复杂的技术。好的Debug工具如SoftICE,也是技术稍深一些的程序员必备的技术之一。这篇随笔并不会去讨论Debug技术的实质,而只是利用Platform SDK和最新的DbgHelp.dll提供的API作为引擎写一个自己的debugger,也即是写一个实用的debugger的Host端。呵呵,本人不擅于写文章,所以下面就指一个例子来说,即如何给一个进程设下断点并捕获。其实看过IA32的人都知道,CPU为Debug提供了强力的支持,比如设单步跟踪的标志;再比如BIOS代码的调试,对于ROM的BIOS代码是无法进行插CC(int 3)指令进行断点设置的,这时CPU提供了地址中断,执行至指定地址时,CPU自行中断。在这里并不会提及这些内容,当然也许有时间,或大家感兴趣,我可以写点或讨论一二。下面单就如何给进行设断点来说说,即然是随笔,所以可能会有错别字,欢迎大家来找别字 ^_^,

       调试目标程序时,你得有相应的权限。用下面这个函数得到它:

//--------------------------------------------------------------------------

// EnableDebugAccessCtl

// Description: Enable or disable debug access control

// Return value: 0 means succeed

DWORD EnableDebugAccessCtl(BOOL bEnable)

{

    HANDLE hTokenHandle = NULL;

    if( !OpenProcessToken(GetCurrentProcess(),

                            TOKEN_ADJUST_PRIVILEGES,

                            &hTokenHandle ) )

    {

        return GetLastError();

    }

    // Lookup the privilege value

    TOKEN_PRIVILEGES tp;

    tp.PrivilegeCount = 1;

    if( !LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid ) )

    {

        CloseHandle(hTokenHandle);

        return -1;

    }

    // Enable/disable the privilege

    tp.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;

    if( !AdjustTokenPrivileges( hTokenHandle, FALSE, &tp, sizeof(tp), NULL, NULL ) )

    {

        CloseHandle(hTokenHandle);

        return -1;

    }

 

    CloseHandle(hTokenHandle);

    return 0;

}

       我们可以attach一个正在运行的进行或重新启动一个进程进行调试。DebugActiveProcess可以实现第一种情况;第二种情况可以用CreateProcess,下面是代码,注意创建标志。

// Create Process

    STARTUPINFO si;

    PROCESS_INFORMATION pi;

    ZeroMemory( &si, sizeof(si) );

    si.cb = sizeof(si);

    ZeroMemory( &pi, sizeof(pi) );

    if( !CreateProcess(NULL, csCmdParms.GetBuffer(),

                        NULL, NULL, FALSE,

                           CREATE_NEW_CONSOLE | DEBUG_ONLY_THIS_PROCESS,

                        NULL, NULL,

                        &si, &pi ) )

    {

        return GetLastError();     

    }

 

这下初调试的程序就跑起来了,接下来一般来用一个循环来获取目标进行的Debug事件。主循环看起来应该是这样的,嘿,MSDN给了你一个模板,那就用吧:

DEBUG_EVENT DebugEv;                   // debugging event information 
DWORD dwContinueStatus = DBG_CONTINUE; // exception continuation 

for(;;) 

{  

// Wait for a debugging event to occur. The second parameter indicates 

// that the function does not return until a debugging event occurs.  

    WaitForDebugEvent(&DebugEv, INFINITE);  

// Process the debugging event code.  

    switch (DebugEv.dwDebugEventCode) 

{ 

        case EXCEPTION_DEBUG_EVENT: 

        // Process the exception code. When handling 

        // exceptions, remember to set the continuation 

        // status parameter (dwContinueStatus). This value 

        // is used by the ContinueDebugEvent function.  

            switch (DebugEv.u.Exception.ExceptionRecord.ExceptionCode) 

            { 

                case EXCEPTION_ACCESS_VIOLATION: 

                // First chance: Pass this on to the system. 

                // Last chance: Display an appropriate error. 

                    break; 

                case EXCEPTION_BREAKPOINT: 

                // First chance: Display the current 

                // instruction and register values. 

                    break; 

                case EXCEPTION_DATATYPE_MISALIGNMENT: 

                // First chance: Pass this on to the system. 

                // Last chance: Display an appropriate error. 

                    break; 

                case EXCEPTION_SINGLE_STEP: 

                // First chance: Update the display of the 

                // current instruction and register values. 

                    break; 

                case DBG_CONTROL_C: 

                // First chance: Pass this on to the system. 

                // Last chance: Display an appropriate error. 

                    break; 

                default;

                // Handle other exceptions. 

                    break;

            }  

        case CREATE_THREAD_DEBUG_EVENT: 

        // As needed, examine or change the thread's registers 

        // with the GetThreadContext and SetThreadContext functions; 

        // and suspend and resume thread execution with the 

        // SuspendThread and ResumeThread functions. 

            break;

        case CREATE_PROCESS_DEBUG_EVENT: 

        // As needed, examine or change the registers of the 

        // process's initial thread with the GetThreadContext and 

        // SetThreadContext functions; read from and write to the 

        // process's virtual memory with the ReadProcessMemory and 

        // WriteProcessMemory functions; and suspend and resume 

        // thread execution with the SuspendThread and ResumeThread 

        // functions. Be sure to close the handle to the process image 

        // file with CloseHandle.

            break; 

        case EXIT_THREAD_DEBUG_EVENT: 

        // Display the thread's exit code. 

            break; 

        case EXIT_PROCESS_DEBUG_EVENT: 

        // Display the process's exit code. 

            break; 

        case LOAD_DLL_DEBUG_EVENT: 

        // Read the debugging information included in the newly 

        // loaded DLL. Be sure to close the handle to the loaded DLL 

        // with CloseHandle.

            break; 

        case UNLOAD_DLL_DEBUG_EVENT: 

        // Display a message that the DLL has been unloaded. 

            break; 

        case OUTPUT_DEBUG_STRING_EVENT: 

        // Display the output debugging string. 

            break; 

    } 

 

// Resume executing the thread that reported the debugging event.  

ContinueDebugEvent(DebugEv.dwProcessId, DebugEv.dwThreadId, dwContinueStatus); 

 }

可以从CASE语句中看到可以获取什么样的事件。注意CREATE_PROCESS_DEBUG_EVENT事件,我们设置断点是在这里,也就是进行被创建的时候。

说到这里就要讲讲断点是怎么设置的了。通常我们设置的断点称为软件断点。通俗点说这个断点其实并不是在原代码中写的,它的基本工作是:调试器跟据用户的设置对代码进行了修改,也即是在指地址处更换一个字节的值为CC,当程序运行到用户指定地址时,CC被处理器装入执行,因为CC对应用int 3指令,这是处理器的一个断点异常,于是处理暂停当前程序,并发出相应异常,通过异常处理程序和debug驱动程序,调试器Host端得到这个事件,此时用户就可以对被debugging的程序进行一些访问了,比如寄存器,局部变量等各种信息,可以对目标程序的指定代码块进行反汇编或进行源码级的查看。

注意:这里指出的是当程序被断点所中断时,调试器获得此断点事件后第一件是要将有被改写为CC的内存单元重新改会为原来程序的代码,以保证程序的完整性。另一点提示,被捕获的第一个断点异常应该被丢掉,呵呵,那不关你的事,它是规定的一个步骤,当然,你是可以用它做点什么事的。

当然继续调试的时候,目标程序会根据EIP来执行下一条指令,而这时EIP实际指向的是CC后的位置,因此必须令EIP指针值减1,这样程序就对用户实现了透明,用户是不知道调试器作了什么手脚的,当然别忘,程序继续跑时,其实的断点还要改成CC的。

写目标进程可以用WriteProcessMemory进行,写完后别忘了用FlushInstructionCache指令flush一下目标进行的指令的cache。如果页为只读时,可以使用VirtualProtectEx改其为读写属性然后再写。

修改目标线程EIP的值可以用SetThreadContext,当然EIP的值请先用GetThreadContext来获得。啊,这样就可以了。好热,写了40多分钟......要吃冰棒去了。

自己写调试器 软断点 [Linux] 之前结果Windows上面的如何是实现,下面写Linux如何实现     在linux中,我们需要用到ptrace 这个系统调用来实现对进程的控制。同时为了获取系统库中的函数地址,我们需要dlsym等在libdl中的相关函数帮助。 ptrace 的原型如下: long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data); 我们可以看到 ptrac 阅读详情

相关推荐

瑞萨RX23T与E1调试器烧写失败排查指南:从硬件连接到软件配置

在嵌入式开发中,微控制器(MCU)的程序烧写是基础且关键的环节,其核心原理是通过调试接口建立主机与目标芯片之间的可靠通信。通信协议的正确实现直接关系到烧写的成功率与效率,是评估开发工具链稳定性的重要指标。对于采用瑞萨RX23T系列MCU进行电机控制或数字电源开发的工程师而言,掌握其与E1/E2 Lite调试器的协同工作机理具有极高的技术价值,能有效提升开发调试效率,缩短项目周期。在实际应用场景中,烧写失败往往源于硬件连接、电源设计、复位电路或软件配置等环节的细微疏漏。本文聚焦于解决RX23T与E1调试器配合

weixin_34072458的博客 400

STM32开发常见问题解决方法汇总(不断更新)

STM32开发常见问题解决方法汇总

MeeFly的博客 7280

编写简单的 Windows调试器

你经常调试程序,但你知道调试器的工作原理吗?

python灰帽子--自己动手写调试器

一、为了对一个进程进行调试,你必须手写用一些方法把调试器和进程链接起来。所以我们的调试器可以有两种:      (1)装载一个可执行程序然后运行它      (2)动态的附加到一个运行的进程。       优点:       (1)在于他能在程序运行任何代码之前完全的控制程序,这对分析病毒或恶意代码很有用。       (2)附加到一个进程,它允许你跳过启动部分的代码,分析你感兴趣的代码

I have a dream 2848

自己写的软件调试器

我用c语言写的调试器,新手请大家指教 来来来

npu-smi info 华为昇腾NPU 状态监控工具解读

用于查询所有设备的基本信息。

Lixora's DB Home 2486

description和debugDescription在调试程序时使用总结

description,debugDescription,调试程序时使用总结

抽筋的小乌龟 3952

VINS-Mono 时延估计论文翻译

Online Temporal Calibration for Monocular Visual-Inertial Systems 摘要 精确的状态估计是机器人导航、自主驾驶、虚拟现实和增强现实等各种智能应用的基础模块。视觉惯性融合是近年来流行的六自由度状态估计技术。记录不同传感器测量值的时刻对系统的鲁棒性和准确性至关重要。在实践中,每个传感器的时间戳通常会受到触发和传输延迟的影响,从而导致不同传感器之间的时间偏差(时间偏移)。这种时间偏移严重影响传感器融合的性能。为此,我们提出了一种标定视觉和

weixin_39061796的博客 1255

自己动手写编译器、解释器、调试器和集成开发环境---使用 Java和现代软件工程方法(序言)

本书介绍编写编译器和解释器。重点在于编写,因此本书编写了大量代码。如果你想学习如何编写解释器、编译器、交互式源代码级调试器以及带有图形用户界面(GUI)的集成开发环境(IDE),本书就是你的首选。所有代码都使用 Java,我将对此进行详细讲解。本书不涉及编译器编写背后的理论。我把这个问题留给了教科书。如果你现在就想学习理论,那么这本书就不适合你。不过,我希望你在学习完本书的程序后,能受到激励,去了解这些程序的理论基础。

langfengyl的专栏 2122

MIPI DPHY接口(基于Xilinx FPGA实现)案例分析

在Xilinx FPGA实现MIPI DPHY接口的案例(包括CIS协议层)。截止目前为止,Xilinx仅在Ultrascale+及其以上版本的FPGA IO可直接支持MIPI 电平输入,其他的,都需要转换成LVDS来接收。

ONEFPGA的博客 5625

PCB板质量测试和PCB板

PCB板质量测试和板厂

weixin_51370842的博客 515

STM32 JLINK SWD调试器手动复位才能烧写的问题

如果我们使用的代码对SWD口进行了一些配置,导致reset指令无法通过SWD口接收的话,调试器就无法reset MCU。解决办法就是不要复用SWDIO 口,否则使用reset pin。手动写代码的时候,SWDIO我们可以自己把握,不去配置就可以用,所以一般来说都在掌控中。MDK中关于reset的设置比较复杂一般使用normal,如果有兴趣可以通过下链接了解。STM32CubeMX的程序就有问题?只有手动复位的情况下,才能进行烧写。为什么烧录程序一次后就无法连接调试器烧录,一定要手动复位?

宁静致远的博客 2451

高精度磁力计RM3100 传感器LR振荡电路偏置电路分析

LR振荡器电路通过正向和反向偏置实现磁场测量。Sen-XY-f/Z-f传感器线圈作为电感元件构成LR弛张振荡电路,其振荡频率随磁场变化而改变。测量时,线圈一端接地,另一端交替通入正反向电流,通过两次偏置测量消除电路自身磁场干扰,仅保留外部磁场影响。MagI2C芯片通过高速时钟测量振荡次数和时间差,计算磁场强度。该设计具有抗干扰强、数字化输出和高分辨率等优势,是RM3100传感器高精度磁测量的核心原理。

bother3000的博客 1133

自己写调试器 进阶

实现了调试器的控制进程后,我们需要访问进程的内存空间,和进程内部各个线程的上下文。   我们用OpenThread来获得一个线程的handle。 HANDLE WINAPI OpenThread( _In_ DWORD dwDesiredAccess, _In_ BOOL bInheritHandle, _In_ DWORD dwThreadId ); def open_

氺在飛天 1564

Python 爬虫实战:爬取电商平台商品信息(价格 / 销量 / 评价)

摘要:本文详细介绍基于Python的电商商品信息爬取技术方案,以京东商品详情页为例,对比分析静态(BeautifulSoup)和动态(Selenium)两种爬取方式的实现逻辑。静态爬取适合获取基础信息,而动态爬取可解决JS渲染数据的获取问题。文章包含完整的代码实现、反爬规避策略及数据存储方案,涵盖商品名称、价格、销量、评价等核心数据提取。同时强调爬虫的合规使用,提供扩展方向建议,为电商数据采集提供实用技术参考。

2503_91057718的博客 2021

linux系统中实现智能家居的基本方法

使用QT开发智能家居中的一个物联应用,通过云服务器远程控制设备与设备进行通信。在生活中,可以使用WIFI智能插座控制电器开关,比如远程开启热水器,远程打开空调,窗帘等等。包括:WIFI联网,注册到云服务器上,编写QT UI通过网络来与云服务器通信,然后再下发指令到这个连网的设备。硬件说明:需要有一个串口转WIFI模块,另外需要加上一个USB-TTL模块,外加一根T口USB连接线,可接入PC电脑调试。

嵌入式技术开发 2608

自己写调试器 初探

调试器有两种,一种是黑盒调试器,另外一种是白盒调试器。而黑盒调试又分两种:用户态和系统态。一般来说,像GDB这样的既可以用作黑盒,又可以用作白盒。但只能用作用户态来调试程序。   我看了一些大牛们的博客和一些书之后,也有自己写调试器的想法。准备在Windows和Linux上各实现简单的调试功能,顺便对Intel X86的架构有更加深入的了解。     调试器要实现的功能: Con

氺在飛天 2605

CDD数据库文件制作(二)——服务配置(0x27)

主要根据诊断调查表,针对0x27服务在CDD中的每一步配置给出详细介绍 1.会话切换配置 1.1.根据诊断调查表进行信息提取 1.2.子功能添加 1.2.1.Level1安全等级1创建 1.2.2.Level3安全等级3创建 1.2.3.安全等级名字查看与修改 1.3.会话切换信息提取(应用程序下) 1.4.会话转换配置(应用程序下) 1.5.会话切换信息提取(引导程序下) 1.6.会话转换配置(引导程序下) 2.安全等级配置信息提取 2.1.安全访问配置(level1) 2.2.安全访问配置(level2

LOVE135149的博客 2929

自己写调试器 软断点

调试器的核心便是断点,根据断点的类型不同,可以分为:软断点,硬断点,内存断点。   软断点实际上是一个单字节的指令,改指令可以引发软中断,将当前进程的控制权交给OS。在X86的架构上,是INT3。要想引发软中断,首先得了解在CPU上出发软中断的机器码。在X86上便是0xCC。然后,调试器的工作便是替换原来指令的机器码中的操作码为引发软中断的操作码,让OS捕获中断,挂起进程,同时让OS把中断的处理

氺在飛天 1588

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

Keil MDK下STM32G4系列烧写报错?可能是你的CMSIS-DAP调试器在‘打架’

本文深入解析Keil MDK下STM32G4系列烧写报错问题,特别是CMSIS-DAP调试器冲突导致的'content mismatch'错误。通过硬件优化、软件配置和高级调试技巧,提供系统化解决方案,帮助开发者快速定位并解决烧写冲突问题,提升开发效率。

weixin_30352645的博客 523

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

python写的调试器

生成调试文件的源代码#!/usr/bin/python#_*_coding:utf8_*_import osimport sysimport re"""行匹配(必须是对应的符号),例{},(),[]等,head表示前半部分,tail表示后半部分"""def match(head, tail,fileName): try: f = open(fileName) ...

weixin_30359021的博客 133

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

上一篇: 3721驻留机制简单研究
下一篇: 演示如何在物理内存中如何获得所须的BIOS信息
pll621
博客等级 码龄25年 27粉丝 87原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值