zoukankan      html  css  js  c++  java
  • windbg内存查看(d*)

    d*命令

    d{a|b|c|d|D|f|p|q|u|w|W} Address [/c ColumuWidth] [l Length]

    Address:查看address地址处的内存。

    ColumnWidth:Windbg每行显示的多少个数据单位。默认为16进制数字,十进制需加前缀0n

    Length:总共显示Address地址后的多少个数据单位

    如:
    db /c 0n32 06beee78 l 0n128 表示 显示06beee78之后的128个byte,每行显示32个byte,
    dw /c 0n32 06beee78 l 0n128 表示 显示06beee78之后的128个word,每行显示32个word。

    db: 按照Byte(单字节)来显示。如果为ASCII字符就显示ASCII字符。会在第八个和第九个16进制间插入分隔符-;右边显示每个16进制数据对应的ASCII字符,ASCII不支持的、或者不能显示的字符用. 点号代替。

    如:
    地址002afa48指向一个char s[51] 的字符串:

    红框中的-表示第八个和第九个16进制数据之前的分隔符。
    蓝框中的表示ASCII字符。

    地址002afa84指向长整型变量 long a = 0x12345678;

    为什么没有按照12345678的顺序显示,而是显示的78563412了? 这个涉及到了数据存储的大小端问题,不清楚的话可以先看1.2节。

    dw:按照Word(双字节)来显示。

    现在显示的是5678 1234

    dd: 按照Double-Word(4个字节)来显示。

    dq :按照8个字节来显示。

    du: 按照Unicode字符格式来显示。

    df :按照单浮点(float,4字节)来显示。

    dD :按照双浮点(double,8字节)来显示。

    dt:不仅可以显示内存的值,还能显示变量的值、类型、结构等信息。

    dv:显示局部变量、全局变量等。

    大小端

    什么是大小端?

    Big-Endian和Little-Endian的定义如下:
    Little-Endian 数据的低位字节位存放在内存的低地址端,高位字节存放在内存的高地址端。
    Big-Endian 数据的高位字节位存放在内存的低地址端,低位字节存放在内存的高地址端。

    比如1.1节中提到的数字0x12345678,它总共占4个字节(1个字节8位,2个16进制占8位,所以1个字节最大表示0xFF)。这个数据在大小端模式下,在内存中的存储布局为:
    大端模式:

    低地址 -----------------> 高地址
    0x12  |  0x34  |  0x56  |  0x78
    

    小端模式:

    低地址 ------------------> 高地址
    0x78  |  0x56  |  0x34  |  0x12
    

    因为windows是小端模式,所以,db 002afa84 以字节为单位显示002afa84地址处的数据(0x12345678)会显示为:

    更详细的介绍可以参考:http://blog.csdn.net/ce123_zhouwei/article/details/6971544

    程序判断大小端

    bool IsLittleEndian() {
        int a = 0x1234;
        char c = *(char *)&a;
        if (c == 0x34) {
            return true;
        }
        return false;
    }
    

    STL(std::string)显示

    文件stl_show.cpp:

    void test1(long l, char* pMsg, std::string str, std::vector<int> vInts) {
    	printf("%ld, %s, %s, %d", l, pMsg, str.c_str(), vInts.size()); // 第10行
    }
    
    int main()
    {
    	long l = 0x12345678;
    	
    	char szMsg[100] = { "I'm ok" };
    
    	std::string strInfo = "hello 123";
    
    	std::vector<int> vInts;
    	vInts.push_back(1);
    	vInts.push_back(2);
    	vInts.push_back(3);
    
    	test1(l, szMsg, strInfo, vInts);
    
        return 0;
    }
    

    test1函数第3个参数为std::string,在第10行printf函数下断点bp stl_show.cpp:10g执行到断点,kvn查看堆栈信息:

    0:000> kbn
     # ChildEBP RetAddr  Args to Child              
    00 002af970 0018899e 12345678 002afb10 0033e1d8 stl_show!test1+0x1e [c:usersjefferydesktopstl_showstl_showstl_show.cpp @ 10]
    01 002afb94 00189b4e 00000001 0033db98 0033cbd0 stl_show!main+0x14e [c:usersjefferydesktopstl_showstl_showstl_show.cpp @ 26]
    02 002afba8 001899b0 9bea5bac 00000000 00000000 stl_show!invoke_main+0x1e [f:ddvctoolscrtvcstartupsrcstartupexe_common.inl @ 64]
    03 002afc00 0018984d 002afc10 00189b68 002afc1c stl_show!__scrt_common_main_seh+0x150 [f:ddvctoolscrtvcstartupsrcstartupexe_common.inl @ 253]
    04 002afc08 00189b68 002afc1c 76de336a 7efde000 stl_show!__scrt_common_main+0xd [f:ddvctoolscrtvcstartupsrcstartupexe_common.inl @ 296]
    05 002afc10 76de336a 7efde000 002afc5c 77659902 stl_show!mainCRTStartup+0x8 [f:ddvctoolscrtvcstartupsrcstartupexe_main.cpp @ 17]
    06 002afc1c 77659902 7efde000 776bd5e0 00000000 kernel32!BaseThreadInitThunk+0xe
    07 002afc5c 776598d5 001810f5 7efde000 00000000 ntdll!__RtlUserThreadStart+0x70
    08 002afc74 00000000 001810f5 7efde000 00000000 ntdll!_RtlUserThreadStart+0x1b
    

    栈帧#0显示第三个参数值为0033e1d8,因为现在加载了pdb,我直接使用dt -b 0033e1d8 是可以显示std::string的结构和值的,但windbg却提示我:
    Symbol not found at address 0033e1d8.
    无论0033e1d8地址存储的是什么数据,但windbg识别不了这是std::string结构,我猜想这个值可能是string结构中某个成员的值,下面我来证明我的猜想。

    因为函数test1前2个参数各占4个字节,所以第三个参数地址应该是EBP+0x8+0x4+0x4=EBP+0x10=002af970+0x10=002af980
    查看该地址的内容 dd 002af980

    刚好和栈帧#0显示第三个参数值为0033e1d8一样。
    所以windbg针对std::string类型的参数提示多做了一步,这一步刚好也是多余的。

    现在需要分析std::string结构,在pdb文件的情况直接使用dt -b str 来查看str变量的结构,如图:

    可以看到,字符串缓冲区的地址等于参数地址+0x004偏移即0x002af980+0x004,使用db 0x002af980+0x004 查看字符串内容:

    综上所述,对于std::string变量,输出其存储的字符串的方法为:
    db 变量地址+0x4,这种方法无论是否有pdb符号文件都适用。

    在有pdb的情况,使用 !stl 变量名 无疑是最快捷的方式。

  • 相关阅读:
    假期进度报告2
    假期进度报告1
    JavaScript下判断元素是否存在
    浪潮之巅阅读笔记06
    浪潮之巅阅读笔记05
    浪潮之巅阅读笔记04
    【C语言】C语言简介
    iOS网络监测方法
    iOS常用手势识别器
    【CoreData】 简单地使用
  • 原文地址:https://www.cnblogs.com/jiangxueqiao/p/7418195.html
Copyright © 2011-2022 走看看