• 调试器第二讲,单步步入/步过功能实现,以及基本的断点功能实现


               调试器第二讲,单步步入/步过功能实现,以及基本的断点功能实现

    昨天,我们实现了调试器的基本框架,那么今天我们实现单步功能,还有断点功能,以及使用反汇编引擎

    作者:IBinary
    出处:http://www.cnblogs.com/iBinary/
    版权所有,欢迎保留原文链接进行转载:)

    一丶反汇编引擎的编译,生成LIB

    首先,我们有一个反汇编引擎的代码,现在我们编译连接一下(注意,可以使用GitHub下载,或者百度Google下载)

    关于反汇编引擎的介绍: 请参考转载博客 http://blog.csdn.net/earbao/article/details/72857805

    先编译成OBJ文件,(不连接),上面两个函数就是我们需要的使用的,准确的来说,是下面的这个,因为上面那个不会给你二进制数据.

    比如我们反汇编的结果是

    00401000    CC         int 3  那么这样就是用下面这个,有二进制代码显示

    如果使用上面那个则是

    00401000  int3      具体爱好看你使用那个,这里具体讲解第二个

    先编译成OBJ

    需要的就这有3个,  除了stdafx.obj 还有MyDisasm.obj 其余的都是我们用的

    现在我们使用lib工具,讲编译好的obj打包成一个lib(当然你也可以写)

    关于lib工具的使用,请参考我写的博客,32位汇编第七讲,混合编程 连接: http://www.cnblogs.com/iBinary/p/7555503.html

    现在回车,生成我们的lib

     

     

    然后我们还需要这两个函数的头文件.

    现在准备齐全了,准备开始我们的代码编写.

    注意: 这里我们是生成的静态lib,你也可以生成动态链接库 (也就是俗称的 DLL)

    二丶使用反汇编引擎API

    直接看代码吧

    新建一个工程,控制台的(随你便,啥都行,能写代码,调用API的就可以)

    把我们的lib,和.h文件,拷贝到我们的程序目录下(静态使用)

    #include "stdafx.h"
    #include <WINDOWS.H>
    #include <STDLIB.H>
    #include "Decode2Asm.h"
    
    #pragma comment(lib,"MyDisAsm.lib")
    int main(int argc, char* argv[])
    {
        BYTE OpCode[] = {0xcc,0x90};      //解析的地址,地址里面有机器码,我们不知道是什么(这里举例子我们知道)
        char szAsm[256] = {NULL};        //通过地址,得出反汇编字符串,放到这个缓冲区中
        char szBin[256] = {NULL};        //通过地址,得出二进制机器码,放到这个缓冲区中
        UINT binSize = NULL;           //每次只解析一个指令长度,所以我们要遍历数组,加上这个长度,接着输出出来.
        BYTE *pCurCode = OpCode;         //遍历的时候需要给个指针
        do 
        {
            Decode2AsmOpcode(pCurCode,szAsm,szBin,&binSize,(UINT)pCurCode);//调用API,解析,
            printf("%-16p%-20s%-20s
    ",pCurCode,szBin,szAsm);        //输出
            pCurCode = pCurCode + binSize;                    //地址 + 指令长度 = 下一次需要解析的指令的地址
        } while (pCurCode < (OpCode + sizeof(OpCode)));            //判断是否数组越界
        system("pause");
        return 0;
    }
    Decode2AsmOpcode的各个参数意思:
    第一个参数: 地址,你要给我一个地址,我去解析
    第二个参数: 反汇编代码的缓冲区,通过地址,解析的反汇编会放到这个缓冲区当中
    第三个参数: 二进制代码缓冲区,通过地址,解析二进制,放到这个缓冲区当中
    第四个参数: 是否计算偏移
    关于这个参数,其实是给EIP的值,(也就是地址),例如我们上面的给的.
    这个参数的作用是
    比如你有一个 JMP 指令
    00401000 JMP 000010 这个是正常的汇编代码,我们知道JMP是JMP的偏移
    而后面给了这个参数,它则会给我们计算出来
    00401000 JMP 00401010

    看下输出结果

    配合我们昨天写的,则可以反汇编出来调试进程的代码了.

    三丶汇编调用反汇编引擎API,显示调试进程的汇编代码.

    在上面,我们对API有了一个认识.

    下面我们就结合我们昨天写的汇编代码,接着写,显示出来断点位置的反汇编代码.

    首先在处理异常的事件中,我们要调用

    先加载我们的LIB,以及INC文件(INC文件中,是那个两个API的函数声明,你可以自己通过LIB生成,

    具体请参考上面的混合编程的博客链接)

    1.加载LIB,以及INC文件

    2.使用ReadProcessMemory,和我们的API配合使用

    首先使用Read..读取.然后放到我们的数组中,

    然后使用API,获取反汇编的各种信息

    invoke ReadProcessMemory,g_hProcess,
                                 [ebx].u.Exception.pExceptionRecord.ExceptionAddress,
                                 @OpCode,sizeof @OpCode,
                                  NULL
    invoke ShowAsm,addr @OpCode,[ebx].u.Exception.pExceptionRecord.ExceptionAddress

    当然,Read的时候,需要注意要保存g_hProcess句柄.这样才可以.

    下面的ShowAsm是封装的函数,内部还是调用的Decode2AsmOpco

    ShowAsm proc pCode :ptr byte, pAddr:ptr Byte
        LOCAL  @szAsmCode[256]:BYTE
        LOCAL  @szOpCode[256]:BYTE
        LOCAL  @CodeSize1:DWORD
        
        invoke Decode2AsmOpcode, pCode, addr @szAsmCode, addr @szOpCode,
                                 addr @CodeSize1, pAddr
        invoke crt_printf, offset g_szDcode, pAddr, addr @szOpCode, addr @szAsmCode
    
        ret
    
    ShowAsm endp

    这里提一下简单思路,因为真正的都写出来,汇编代码很多,影响观看,所以都是简单思路,没有完整代码,完整代码,在每天的课件资料中,可以去看,这里这说一下核心代码的思路

    四丶汇编设置F2断点,以及单步(步入,步过)

    简单思路

    1.断点的设置:

      1.首先,系统断点第一次来,然后在创建进程的时候会有一个地址,我们使用Read...读取地址内容,然后反汇编出来显示

      2.读取出来之前,使用VirtualProtectEx将保护属性去除,(注意保存旧的)

      3.使用WriteProcessMemory往地址写入CC(注意保存以前的值)

      4.重新修改保护属性,改回去(使用旧的)

    然后一个断点即完成了,具体代码,请看课件.

    2.单步的设置(步入,进函数)

    如果是单步,我们要判断断点是我们设置的还是系统设置的.

    1.判断是否使我们设置的断点

    2.修改内存保护属性(注意保存旧的)

    3.写入CC,(int 3断点)

    4.读取内存数据

    5.显示反汇编

    设置单步(步入)异常

    1.打开线程获得线程句柄

    2.使用GetThreadContext获取寄存器的值

    3.设置单步标志,单步表示是要我们设置的,他是第9个标志

    or [esi].regflag,0100h 这样设置即可.设置第九位为1

    4.设置寄存器环境 SetThreadContext

    设置单步步过异常

    但步步过和单步步入一样

    只不过遇到Call的时候我们要把他的下一条指令设置一个int3断点才可以.

    课堂资料: 链接:http://pan.baidu.com/s/1geBOgQR 密码:5dw9


    作者:IBinary
    出处:http://www.cnblogs.com/iBinary/
    版权所有,欢迎保留原文链接进行转载:)

  • 相关阅读:
    springMVC的自定义类型的转换器
    pl/sql
    oracle中的函数
    Oracle基础
    跳台阶算法题
    红黑树
    优先队列
    堆排序
    H5页面,输入框的光标,如果页面上下滑动光标停留在页面上,除了输入框外,松手过了一段时间才跑回输入框里面
    正则:判断为数字,输入的金额整数位不得超过9位,小数位不得超过2位!
  • 原文地址:https://www.cnblogs.com/iBinary/p/7609213.html
Copyright © 2020-2023  润新知