软件工程

本类阅读TOP10

·PHP4 + MYSQL + APACHE 在 WIN 系统下的安装、配置
·Linux 入门常用命令(1)
·Linux 入门常用命令(2)
·使用 DCPROMO/FORCEREMOVAL 命令强制将 Active Directory 域控制器降级
·DirectShow学习(八): CBaseRender类及相应Pin类的源代码分析
·基于ICE方式SIP信令穿透Symmetric NAT技术研究
·Windows 2003网络负载均衡的实现
·一网打尽Win十四种系统故障解决方法
·数百种 Windows 软件的免费替代品列表
·收藏---行百里半九十

分类导航
VC语言Delphi
VB语言ASP
PerlJava
Script数据库
其他语言游戏开发
文件格式网站制作
软件工程.NET开发
DrX调试寄存器使用 一

作者:未知 来源:月光软件站 加入时间:2005-2-28 月光软件站

DrX调试寄存器使用

 

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

 

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

http://www7.informatik.uni-erlangen.de/~msdoerfe/embedded/386html/toc.htm

http://www.anticracking.sk/EliCZ/

 

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

下面进入正题:

 

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   <CONTEXT_FULL 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 


程序运行结果截图如下:




相关文章

相关软件