博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
DrX调试寄存器使用 一 - firingme的专栏 - CSDNBlog
阅读量:2400 次
发布时间:2019-05-10

本文共 4464 字,大约阅读时间需要 14 分钟。

导读:

Intel公司自80386以来,在CPU内部引入了Dr0-Dr7八个调试寄存器专门用于程序的调试工作,可以说这8个调试寄存器已经存在了很长时间,可是国内的汇编教科书中鲜有涉及者,导致国内很多朋友对此都不甚了解。我作为一个计算机底层技术的爱好者,从国外的一些网站上阅读了一些此方面的资料,并且写了一些演示用的程序,如今把它们整理出来,希望对那些想了解这方面的技术,却苦于找不到中文资料的朋友提供一些帮助。

 

如果你的英文过关,你可以参考如下网址获得更详细的资料:

 

调试寄存器的作用就不再多说,相信知道调试是怎么回事情的朋友都能明白调试寄存器对于调试过程的重要性。

下面进入正题:

 

386体系的调试寄存器的示意图可以表示如下:

 

Dr0~Dr3用于存放欲设置断点的线性地址。

Dr4Dr5保留

Dr6保存了调试状态

Dr7是调试控制寄存器

 

调试寄存器的使用总体来说分为如下几步:

 

1、  把欲监视的地址放入Dr0~Dr3中的一个寄存器

2、  Dr7种设置相应的控制位,使得Dr0~Dr3存放的监视地址生效

3、  继续运行程序,接收EXCEPTION_SINGLE_STEP 调试消息,并在消息处理程序中作自己想做的事情。

 

以下的代码演示bpm最基础的用法,我假设你有Windows Debug API编程的基础知识以及利用32位汇编语言编程的能力。如果你这两方面都不太行,那网上关于这两方面的中文资料已经很多,可以自己参考。

 

我的编程环境是WinXP,凡是Nt架构的系统,在调试循环收到第一个EXCEPTION_BREAKPOINT调试消息的时候,程序都没有完全载入内存,所以不能对程序地址设断,此时的解决方案是先对Ntdll.dll的引出函数NtContinue设断,然后在第一个EXCEPTION_SINGLE_STEP产生时,再对需要设断的地址设断。

 

NoteDrX寄存器产生的断点是:EXCEPTION_SINGLE_STEP断点消息

整个程序的分支非常多,流程图如下:

如此多分支的流程图,用ASM实现的确容易出错,所以,一旦搭好一个调试的框架,日后如非必要,就务须修改。

 

另外,整个程序中使用的CONTEXT结构地址必须4字节对齐,否则得不到正确的结果。请大家记住一个规律:凡是需要和系统内核打交道的数据结构,一般都需要进行4字节对齐。C/C++中,编译器会自动帮你设置好对齐,而在ASM中,数据的内存布局都是由程序员决定的,所以,此处要特别小心。否则,最容易出现的结果就是:整个程序逻辑、编码都正确,可是就是出不来正确的结果。

 

理论到此为止,下面来看看DrX寄存器的第一个示例代码:

 

;filename: bpm1.asm

comment /*

演示bpm最基础的用法,在程序的首地址中断
1
CONTEXT结构的地址要4字节对齐
    yoda
的例子程序里面,CONTEXT结构是.DATA段第一个数据定义,连接器会自动对齐
;2
、调试循环结构很复杂
*/
.386
.model flat,stdcall 
option casemap:none 
include /masm32/include/windows.inc 
include /masm32/include/kernel32.inc 
include /masm32/include/comdlg32.inc 
include /masm32/include/user32.inc 
include ../bpm/bpm.inc
includelib /masm32/lib/kernel32.lib 
includelib /masm32/lib/comdlg32.lib 
includelib /masm32/lib/user32.lib 
.data 
szAppName         db        "firing's Bpm Example no.1",0 
szExitStr             db        "Debuggee exit...",0
szFormat             db        "Break at address: %08X",0Dh,0Ah,0
szExeName          db        "Msg.exe",0
szNtDllName       db        "ntdll.dll",0
szProcName         db        "NtContinue",0
DbgState             dd        0
TotalInstruction   dd        0
dwSSCnt              dd        0
dwAddrBuf          dd        0
dwBpCnt              dd        0
dwBreakAddr       dd        401000h
szBuffer              db        512 dup(?) 
align    dword
Regs   CONTEXT    OR /

CONTEXT_DEBUG_REGISTERS>                ;这个结构的地址要对齐的

sif              STARTUPINFO            < SIZEOF STARTUPINFO > 
pi                    PROCESS_INFORMATION < > 
DBEvent        DEBUG_EVENT            < > 
WipeContextBPdr0    PROTO
;
一些为了编码方便而设置的常量定义
DbgEvent             EQU            DBEvent.dwDebugEventCode 
excCode                EQU            DBEvent.u.Exception.pExceptionRecord.ExceptionCode 
excAddr                EQU            DBEvent.u.Exception.pExceptionRecord.ExceptionAddress 
;pDllName            EQU            Dev.u.LoadDll.lpImageName 
;lpBase                 EQU            Dev.u.LoadDll.lpBaseOfDll 
.code
start: 
xor        eaxeax
mov        dwSSCnt, eax
mov        dwBpCnt, eax
mov        dwBreakAddr, 401000h
invoke    GetStartupInfo,addr sif
invoke    CreateProcess, addr szExeName, NULL, NULL, NULL, FALSE, DEBUG_PROCESS+ DEBUG_ONLY_THIS_PROCESS, /
                NULL, NULL, addr sif, addr pi 
;
以下进入debug循环
.while TRUE
    invoke WaitForDebugEvent, addr DBEvent, INFINITE
    mov        DbgState, DBG_EXCEPTION_NOT_HANDLED
    .if DbgEvent == EXCEPTION_DEBUG_EVENT
        .if excCode==EXCEPTION_BREAKPOINT 
            mov        DbgState,DBG_CONTINUE
            inc        dwBpCnt
            .if        dwBpCnt == 1
                    invoke    GetThreadContext, pi.hThread, addr Regs
                    invoke    GetModuleHandle, addr szNtDllName
                    invoke    GetProcAddress, eax,  addr szProcName
                    mov        Regs.iDr7, M_INSTR0 + M_LDR0   ;执行指令中断+Dr0有效

                    mov        Regs.iDr0, eax                            ;NtContinue函数设断

                    invoke    SetThreadContext, pi.hThread, addr Regs
                    jmp        @f
                .endif
        .elseif excCode == EXCEPTION_SINGLE_STEP 
             inc    dwSSCnt
             .if    dwSSCnt == 1                                    ;
中断在NtContinue
                invoke  WipeContextBPdr0                            ;
清除断点
                mov        eax,Regs.regEsp
                add        eax,4                                        ;eax = "esp"+4
                invoke    ReadProcessMemory,pi.hProcess, eaxaddr dwAddrBuf, sizeof DWORD, /

NULL

      invoke    ReadProcessMemory,pi.hProcess, dwAddrBuf, addr Regs, sizeof CONTEXT, /

                   NULL

                push    dwBreakAddr
                pop        Regs.iDr0
                mov        Regs.iDr7, M_LDR0+ M_INSTR0
                invoke    WriteProcessMemory,pi.hProcess,dwAddrBuf,addr Regs,sizeof CONTEXT, /

NULL

      jmp        @f

            .elseif    dwSSCnt    == 2                                    ;中断在首地址
                invoke  WipeContextBPdr0
                invoke    wsprintf, addr szBuffer, addr szFormat, excAddr
                invoke    MessageBox, 0, addr szBuffer, addr szAppName, MB_OK+ /

MB_ICONINFORMATION 

       jmp        @f

                .endif
          .endif 
    .elseif DbgEvent == EXIT_PROCESS_DEBUG_EVENT                    ;
程序退出消息
        invoke MessageBox, 0, addr szExitStr, addr szAppName, MB_OK+     

MB_ICONINFORMATION 

        .break 
    .endif 
@@:
invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINUE
.endw 
    invoke CloseHandle,pi.hProcess 
    invoke CloseHandle,pi.hThread 
    invoke ExitProcess, 0 
;****************************************************************************** WipeContextBPdr0        Proc 
        invoke    GetThreadContext,pi.hThread,addr Regs 
        mov        Regs.iDr0,0 
        mov        Regs.iDr7,0 
        invoke    SetThreadContext,pi.hThread,addr Regs 
        ret 
WipeContextBPdr0        Endp 
;******************************************************************************
end start 

程序运行结果截图如下:

本文转自

转载地址:http://agnob.baihongyu.com/

你可能感兴趣的文章
apache学习笔记一(安装apache2+php+resin)(转)
查看>>
原创之apache指令大全(转)
查看>>
制作带SP2的win2k(转)
查看>>
JBoss的安装(转)
查看>>
安装配置篇--apache+resin(转)
查看>>
一个开放源码的高级NIDS系统(转)
查看>>
Tomcat5.x中的虚拟主机配置方法(转)
查看>>
AllowOverride以及Options相关指令(转)
查看>>
Tomcat 的过滤诀窍(转)
查看>>
Linux必学60个命令文件处理(转)
查看>>
在Linux下配置TCP/IP(转)
查看>>
深入理解硬盘的 Linux 分区(转)
查看>>
Linux 2.4中netfilter框架实现(转)
查看>>
第一次备份与紧急系统恢复(转)
查看>>
安装、完善slackware的全部过程(转)
查看>>
Windows+Apache+resin配置(转)
查看>>
proxy 相关问题集(转)
查看>>
Linux下NFS网络文件系统设定及管理(转)
查看>>
ORACLE常用傻瓜问题1000问(之十二)(转)
查看>>
已经装了最新的binutils,为什么grub还是不能用(转)
查看>>