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:10
,g
執行到斷點,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 變量名
無疑是最快捷的方式。