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:\users\jeffery\desktop\stl_show\stl_show\stl_show.cpp @ 10]
01 002afb94 00189b4e 00000001 0033db98 0033cbd0 stl_show!main+0x14e [c:\users\jeffery\desktop\stl_show\stl_show\stl_show.cpp @ 26]
02 002afba8 001899b0 9bea5bac 00000000 00000000 stl_show!invoke_main+0x1e [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 64]
03 002afc00 0018984d 002afc10 00189b68 002afc1c stl_show!__scrt_common_main_seh+0x150 [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 253]
04 002afc08 00189b68 002afc1c 76de336a 7efde000 stl_show!__scrt_common_main+0xd [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 296]
05 002afc10 76de336a 7efde000 002afc5c 77659902 stl_show!mainCRTStartup+0x8 [f:\dd\vctools\crt\vcstartup\src\startup\exe_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 變量名 無疑是最快捷的方式。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM