用户操作
[即时聊天] [发私信] [加为好友]
鸟六ID:firingme
4723次访问,排名18677(1)好友0人,关注者0
firingme的文章
原创 7 篇
翻译 0 篇
转载 0 篇
评论 6 篇
最近评论
psnccs:WoW Gold
EAsport:firingme老师翻译的很漂亮
yjh1982:呵呵
to 自然::^_^ 过奖!
自然:周星星时间可是充足啊,到处都有你的足迹。
文章分类
收藏
    相册
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 DrX调试寄存器使用 一收藏

    新一篇: Beman Dawes-Boost-20031104-C++标准委员会 | 旧一篇: DrX调试寄存器使用 二

    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 


    程序运行结果截图如下:

    发表于 @ 2003年09月16日 12:11:00|评论(loading...)|编辑

    新一篇: Beman Dawes-Boost-20031104-C++标准委员会 | 旧一篇: DrX调试寄存器使用 二

    评论:没有评论。

    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © firingme