windbg 脚本学习总结
生活随笔
收集整理的這篇文章主要介紹了
windbg 脚本学习总结
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
windbg 腳本簡(jiǎn)單入門
http://blog.csdn.net/superliuxing/article/details/19206985Windbg的功能自然不必說,集內(nèi)核調(diào)試,應(yīng)用程序調(diào)試,遠(yuǎn)程調(diào)試,dump分析等于一身,真是殺人滅口必備利器。但是也由于其太過強(qiáng)大,命令太多,導(dǎo)致很多新手對(duì)windbg望而生畏,覺得Windbg很高深。好在已經(jīng)有很多有識(shí)之士將Windbg的基礎(chǔ)用法分享了出來,入門應(yīng)該不是一件難事了。今天就不再重復(fù)談Windbg如何入門,來探討一下高級(jí)點(diǎn)的用法:腳本。其實(shí),腳本不應(yīng)該是一個(gè)很復(fù)雜的東西,但是,在Windbg的幫助里想過的內(nèi)容卻太過于分散了,導(dǎo)致學(xué)習(xí)起來頗有些海底撈針的感覺,所以我覺得有必要把我的心得跟大家分享一下。
先來解釋一下,Windbg的腳本是什么?你可以理解為腳本就是一種語言,就像c或者匯編,但是他不需要編譯器將其編譯為可執(zhí)行文件,而是由解釋器將其內(nèi)容翻譯為對(duì)應(yīng)的動(dòng)作。而Windbg的腳本就是利用Windbg作為解釋器,將腳本內(nèi)容翻譯為實(shí)際的動(dòng)作。也許這個(gè)解釋還是有些晦澀,那讓我們跳過這些晦澀的概念,來一個(gè)簡(jiǎn)單的例子:
代碼:
.echo “hello windbg”
這條命令會(huì)顯示“hello windbg”這個(gè)字符串,把它保存到c:\1.txt文件,然后在Windbg的命令窗口里輸入:
><c:\1.txt回車,看看屏幕上出現(xiàn)了什么?沒錯(cuò),Windbg將1.txt里的內(nèi)容當(dāng)做一條Windbg的命令執(zhí)行了。這就是一個(gè)簡(jiǎn)單的腳本。也許有人說,這確實(shí)是一個(gè)腳本,但是他太弱了,只能打印字符串而已。別急,飯要一口一口吃,腳本要一點(diǎn)一點(diǎn)擴(kuò)展。先來看看這個(gè)
><,根據(jù)前面的例子,很容易看出他的作用是將腳本文件交給Windbg解釋,由他完成了將一個(gè)txt變成Windbg命令的關(guān)鍵轉(zhuǎn)換。其實(shí)你知道了這個(gè),Windbg腳本就算入門了,因?yàn)槟憧梢园押芏嗝顚懺谶@個(gè)文件里,然后用
><裝載執(zhí)行。這應(yīng)該能完成一些功能,不過,這樣的用法充其量應(yīng)該叫做batch,而不是script,因?yàn)樗荒芘繄?zhí)行命令。那么怎么才能升級(jí)到script呢?接下來我們一步一步分解,不過在此之前,還是先把
><了解透徹。$$>< 其實(shí)有5個(gè)孿生兄弟,在windbg中給出的形式和用法如下:
代碼:
$<Filename?
$><Filename?
$$< Filename?
$$>< Filename?
$$>a< Filename [arg1 arg2 arg3 ... ]
媽呀,眼都花了,看上去長(zhǎng)得都很像。別急,他們是有規(guī)律的,歸納一下:
1.'$'的表示'<'和腳本名之間不可以有空格。
2.'
′的表示可以有空格(其實(shí)我有點(diǎn)不太理解這個(gè)操蛋設(shè)定,為什么不能自動(dòng)檢測(cè))。3.′<′表示不會(huì)自動(dòng)把腳本文件壓縮為一行。4.′><′表示會(huì)把他們壓縮為一行,并將原來的換行變成′;′。5.最后一個(gè)表示可以給腳本傳遞參數(shù)。為什么要壓縮成一行?問的好,Windbg執(zhí)行某些命令的時(shí)候需要他們是一行,比如bp后面可以添加其他命令,但是所有命令寫一行又太長(zhǎng)了,不容易閱讀,于是幫你壓縮一下。一般我們用
><就夠了。
好了,接下來是腳本的時(shí)刻了。要用好腳本,先要轉(zhuǎn)變自己的態(tài)度,要像學(xué)習(xí)一門編程語言一樣學(xué)習(xí)他,像寫代碼一樣寫他,總之,你的思路應(yīng)該和編程的思路一樣。寫Windows的應(yīng)用程序需要哪些知識(shí)?首先需要一門編程語言,比如c,另外需要了解Windows的API。好了,我們現(xiàn)在對(duì)應(yīng)到Windbg的腳本。Windbg提供了一些腳本的語法,相當(dāng)于一門編程語言,而腳本里用到的那些命令相當(dāng)于系統(tǒng)的API。要學(xué)好開發(fā),先要學(xué)好一門編程語言,而語言學(xué)好以后,API就是現(xiàn)用現(xiàn)查的,所以我們就主要從語法入手。
新學(xué)一門編程語言,入門的時(shí)候都會(huì)學(xué)以下幾個(gè)方面:數(shù)據(jù)類型,變量,表達(dá)式,語句,內(nèi)建函數(shù),我們也從這幾個(gè)方面來了解Windbg的腳本。
1. ?數(shù)據(jù)類型:
關(guān)于數(shù)據(jù)類型,Windbg的幫助里沒有明確列舉,但是,在使用時(shí)一般會(huì)遇到,數(shù)值和字符串這兩種。
數(shù)值
數(shù)值沒有太多需要解釋的,和所有編程語言里的整數(shù)含義一樣,在表示的時(shí)候有進(jìn)制之分。
代碼:
2進(jìn)制 ?0x
8進(jìn)制 ?0n
10進(jìn)制 ?0t
16進(jìn)制 ?0y
字符串
字符串用一對(duì) ” 括起來。比如上面的 ”hello windbg”。
2. ?變量:
在windbg中變量的定義很特別,實(shí)際上,他并沒有變量這個(gè)概念,所以,你學(xué)習(xí)的時(shí)候會(huì)覺得很別扭。不過,我們換個(gè)思路就容易了,變量實(shí)際上就是為了保存臨時(shí)結(jié)果, 如果你只想保存一些數(shù)值,那么偽寄存器應(yīng)該是比較好的選擇,windbg提供了20個(gè)偽寄存器$t0-$t19,供命令保存臨時(shí)數(shù)值變量。稱他們?yōu)閭渭拇嫫魇怯性虻?#xff0c;首先對(duì)他們的操作和寄存器一樣,都是使用r命令,在C++表達(dá)式里都前面需要加@符,但是他們又不是真正的寄存器,只是windbg定義的名字而已。使用這些偽寄存器也是很方便的:
代碼:
0:000> r $t0=0x123
0:000> r $t0
$t0=00000123
0:000> r eax
eax=004c1b89
0:000> r $t0=@eax
0:000> r $t0
$t0=004c1b89
? 從上面的例子也可以看出r命令后面的@是可以省略的。
3. ?別名
別名和變量還有些區(qū)別,變量是在執(zhí)行過程中取他的值,而別名更像是宏,在解釋時(shí)直接用內(nèi)容替換原始操作數(shù)。別名有兩種,一種是固定名字的,一種是自定義的。
固定名字別名
固定名字別名和偽寄存器很類似,Windbg提供了10個(gè),$u0-$u9。使用的時(shí)候依然是r命令,不過要在“u”前面加個(gè)“.”,像下面這樣:
代碼:
0:000> r $.u0 = "123"
0:000> .echo $u0
123
從上面的例子可以看出一旦別名被定義了,到使用他的時(shí)候,Windbg會(huì)把別名替換為內(nèi)容。
自定義別名
自定義別名會(huì)復(fù)雜一些,但是,有了它的存在,我們才可以為內(nèi)存中的一些字符串定義別名。操作自定義別名有3個(gè)命令:as,ad,al。
As 定義一個(gè)別名,其強(qiáng)大之處在于,可以指定一個(gè)內(nèi)存地址,然后將內(nèi)存中的內(nèi)容定義為別名。
代碼:
0:000> .dvalloc 10
Allocated 1000 bytes starting at 00010000
0:000> ea 00010000 "123456"
0:000> as /ma ${/v:test} 0x00010000
0:000> .echo test
123456
上面的命令將0x00010000地址的定義為一個(gè)別名,由于as使用了/ma選項(xiàng),所以將內(nèi)容當(dāng)做一個(gè)’\0’結(jié)尾的ASCII字符串來解析,${}是別名解釋器,后面再講。除了/ma選項(xiàng)以外as還有一些其他強(qiáng)大的選項(xiàng):
代碼:
/ma ?參數(shù)指定的內(nèi)存地址當(dāng)做ASCII字符串。
/mu ?參數(shù)指定的內(nèi)存地址當(dāng)做Unicode字符串。
/msa ?參數(shù)指定的內(nèi)存地址當(dāng)做ANSI_STRING字符串。
/msu ?參數(shù)指定的內(nèi)存地址當(dāng)做UNICODE_STRING字符串。
/f ?別名等于參數(shù)指定文件的內(nèi)容。
/e ?別名等于參數(shù)指定的環(huán)境變量。
al顯示已經(jīng)定義的別名,ad刪除已經(jīng)定義的別名,接著剛才的例子繼續(xù)輸入以下命令:
代碼:
0:000> al
? Alias ? ? ? ? ? ?Value ?
?------- ? ? ? ? ?-------?
?test ? ? ? ? ? ? 123456?
0:000> ad ${/v:test}
0:000> al
No aliases
可以看的很明顯吧。
現(xiàn)在我們來解釋一下例子里那個(gè)長(zhǎng)得很奇怪的${},這個(gè)東西叫別名解釋器,把別名放在后面的大括號(hào)里面,Windbg就知道里面是個(gè)別名,需要被翻譯。其實(shí)不用這個(gè)符號(hào)也可以,不過寫到復(fù)雜腳本的時(shí)候就可能出問題,誰用誰知道,我就不再發(fā)散了,建議是最好用。這個(gè)解釋器也有選項(xiàng),上面的/v:就是一個(gè)。
/v: ?保持別名原樣,不翻譯,在定義和刪除的時(shí)候用。
/n: ?如果別名定義就翻譯為內(nèi)容,否則不做任何翻譯。
/f: ?如果別名定義就翻譯為內(nèi)容,否則翻譯為空。
/d: ?如果別名被定義,翻譯為1,否則翻譯為0,相當(dāng)于#ifdef。
4. ?表達(dá)式
Windbg提供了兩種表達(dá)式:匯編表達(dá)式和C++表達(dá)式。兩種表達(dá)式的操作符和操作數(shù)都略有區(qū)別。
默認(rèn)是匯編表達(dá)式,求匯編表達(dá)式的值用?,求C++表達(dá)式的值用??。
匯編表達(dá)式里能用的操作符除了+、-、*、/這些算數(shù)運(yùn)算符以外還有一些類似轉(zhuǎn)型運(yùn)算符,比如poi,有時(shí)候大家斷到一個(gè)函數(shù),第一參數(shù)是個(gè)字符串指針,想打印這個(gè)字符串怎么辦?可以這樣 dd esp+4,然后再從結(jié)果中da一次,有了poi,一行命令就可以做到,dd poi(esp+4)。
C++表達(dá)式就更加豐富了,幾乎所有的C++表達(dá)式都可以用,包括.和->操作符,想讓W(xué)indbg將表達(dá)式按C++方式解釋,需要在表達(dá)式前面加@@c++()。
5. ?語句
都說了腳本要按照編程的思想來寫,既然是編程,怎么能少得了流程控制語句呢?Windbg支持以下流程控制語句。
代碼:
.if
.else
.elif
.for
.while
.break
.continue
.do
我覺得都可以不用解釋,看名字就應(yīng)該知道是什么,大家都是寫程序的嘛,對(duì)吧。
另外還有幾個(gè)比較有用的語句
代碼:
.printf ?格式化輸出,熟悉吧。
.block ?語句塊
$$ ?注釋,長(zhǎng)得好奇怪
這里面,.block要單獨(dú)說說,所謂語句塊,其實(shí)就是用{}括起開的一堆語句,包括.if、.else后面的語句其實(shí)都是語句塊,語句塊內(nèi)部的別名(還記得嗎)在進(jìn)入塊的時(shí)候會(huì)被翻譯,進(jìn)入塊以后,如果修改了別名的定義,那么在本塊內(nèi)的后續(xù)語句中是無效的(還記得別名是原樣替換嗎),所以,如果需要在后續(xù)語句中生效,需要把后面的語句放到一個(gè)單獨(dú)的語句塊里,也就是用{}把他們包含起來,但是Windbg又不能識(shí)別直接用{}包含起來的東西,于是就出現(xiàn)了.block,看到這里,請(qǐng)切記,如果需要?jiǎng)e名被翻譯,一定要把他放到語句塊里。
6. ?內(nèi)建函數(shù)
這里只講兩個(gè)內(nèi)建函數(shù)$scmp和$sicmp都是字符串比較,一個(gè)區(qū)分大小寫,一個(gè)不區(qū)分大小寫。這兩個(gè)函數(shù)有一個(gè)毛病,那就是參數(shù)只接受字符串字面量,就是說,你只能寫$scmp(“123”,”123”),不能寫$scmp(poi(esp+4),”123”),好了,有人急了,不能這樣寫,要這兩個(gè)函數(shù)有什么用?不急,我們可以利用別名(這就是別名最有用的地方),還是接著剛才那個(gè)例子:
代碼:
0:000> as /ma ${/v:test} 00010000
0:000> ? $scmp("${test}","123456")
Evaluate expression: 0 = 00000000
0:000> ? $scmp("${test}","123457")
Evaluate expression: -1 = ffffffff
這樣就可以比較變量字符串了。
好了,有了以上知識(shí),寫一個(gè)windbg腳本應(yīng)該就有基礎(chǔ)了,剩下的就是要看大家知道多少“API”了,更詳細(xì)的信息需要在Windbg的幫助里挖掘了。
最后貼一個(gè)完整的例子,利用腳Hook CreateFileW,這個(gè)例子雖然不長(zhǎng),但是都是精華啊,哈哈。
代碼:
.dvalloc /b 0x79990000 30 ew 0x79990000 0xc033 ed 0x79990002 0x00001cc2 bp kernel32!CreateFileW " as /mu ${/v:filename} poi(esp+4); .block{.if ($sicmp(\"${filename}\", \"c:\\1.txt\") == 0){.echo \"open 1.txt\";r eip=0x79990000} } ad ${/v:filename}; gc; "
稍微解釋一下,一開始分配了一段內(nèi)存,選了一個(gè)幾乎不會(huì)被用到的地址,然后填充為
代碼:
xor eax,eax
ret 0x1c
之后設(shè)置一個(gè)條件斷點(diǎn),斷到以后判斷參數(shù)中的文件名,如果文件是c:\1.txt就將執(zhí)行流程轉(zhuǎn)移到分配的指令處,相當(dāng)于直接返回,于是打開文件失敗。效果如下:
名稱: ?QQ圖片20131031221522.jpg查看次數(shù): 1文件大小: ?21.9 KB
碼了這么多字,還是挺累的,本文作者evil.eagle,轉(zhuǎn)載的時(shí)候煩請(qǐng)注明出處,如果大家希望繼續(xù)交流,歡迎加QQ群151843490,另外吐槽一下,看雪的排版真的好難用啊。
========
如何寫windbg高級(jí)腳本---以訪問文件的windbg腳本為例說明
http://www.pediy.com/kssd/pediy10/83946.html最近需要在訪問指定文件時(shí)中斷下來,但不知道如何下斷,在網(wǎng)上搜索了一番無果,只好自己摸索了。聽大俠說windbg的條件斷點(diǎn)功能異常強(qiáng)大,可以實(shí)現(xiàn),不禁心癢,特嘗試一番,順便熟悉一下windbg的腳本語法。
先來了解簡(jiǎn)單的,得到當(dāng)前訪問的文件名
先寫段C代碼,創(chuàng)建C:\a.txt并往文件中寫任意幾個(gè)字符,代碼如下:
? ? HANDLE hFile=CreateFile("C:\\a.txt",
? ? ? GENERIC_WRITE|GENERIC_READ,
? ? ? 0,
? ? ? NULL,
? ? ? OPEN_ALWAYS,
? ? ? FILE_ATTRIBUTE_NORMAL,
? ? ? NULL);
? ? if (hFile == INVALID_HANDLE_VALUE)?
? ? {
? ? ? return ;
? ? }
? ? char Buffer[]={"abcdefghijklemn"};
? ? DWORD dwReturn;
? ? WriteFile(hFile,Buffer,strlen(Buffer),&dwReturn,NULL);
? ? CloseHandle(hFile);
把以上代碼放到對(duì)話框的按鈕點(diǎn)擊響應(yīng)事件中去。編譯鏈接得到test.Exe.
文件名為CreateFile API的第一個(gè)參數(shù),因而在執(zhí)行到該API的入口時(shí),esp+4即表示第一個(gè)參數(shù)的地址。故可這樣下斷:
bp kernel32!CreateFileW "r $t1=poi(esp+4);.echo;.printf\"FileName:%mu\",$t1;.echo;g"
$t0~$t19為偽寄存器,可用來存儲(chǔ)臨時(shí)值,poi表示取地址的值,
也可將腳本保存為文件,然后在windbg中輸入: $$><腳本文件路徑 來運(yùn)行。
我把以上腳本保存為 ”C:\script.txt”
用windbg打開以上代碼編譯得到的test.exe,?
Ctrl+Break中斷windbg,然后下斷,即輸入:$$><C:\script.txt,再輸入g,讓進(jìn)程運(yùn)行起來,
點(diǎn)擊按鈕,果其然,得到文件名了,見下圖,
?
訪問的文件獲取了,那如何在訪問指定文件時(shí)中斷下來呢?字符串比較的腳本如何寫呀?
上網(wǎng)查資料吧,不大一會(huì),發(fā)現(xiàn)了$scmp/$sicmp/$spat是用來字符串操作的。$spat正合我意呀。
? $spat("string1”, "pattern”):判斷參數(shù)1指定的字符串是否符合參數(shù)2指定的模式。模式字符串中可以包含?、*、#等特殊符號(hào),WinDBG幫助文件中String Wildcard Syntax一節(jié)包含了詳細(xì)的說明;
? 這樣摸索了一番,寫了如下腳本:
bp kernel32!CreateFileW " r $t1=poi(esp+4)as /mu $FileName $t1.echo.printf\"File:%mu\",$t1.echo .block {.if($spat(\"${$FileName}\",\"*a.txt\")) {.echo 'find...';ad ${/v:$FileName}}.else {.echo no find...ad ${/v:$FileName}gc} }"
以上腳本,不復(fù)雜,實(shí)現(xiàn)當(dāng)訪問文件名類似“a.txt”時(shí),windbg中斷執(zhí)行。
對(duì)腳本解析幾個(gè)要點(diǎn):
1. ?使用偽寄存器,更快速的方法是在$前加上一個(gè)@符號(hào)。這樣,WinDBG就知道@后面是一個(gè)偽寄存器,不需要搜索其他符號(hào);
2. ?r $t1=poi(esp+4),poi(esp+4)取地址的值,并賦給偽寄存器$t1 ;
3. ?as /mu $FileName $t1 ,定義$t1 所指地址一個(gè)別名$FileName,用來在下面的$spat中使用。別名會(huì)在腳本加載時(shí)被解析程序替換一次。為何要用別名?你不用試試就知道了,直接用$t1不行,windbg提示你語法錯(cuò)誤;
4. ?.block是啥東西,看windbg幫助就知道了。代碼塊,如果需要每次運(yùn)行進(jìn)入替換,請(qǐng)用.block括起來;我這里有個(gè)別名,需要每次替換,所以用了個(gè).block括起來;
5. ?$spat為模式匹配函數(shù),其他類似函數(shù)$scmp/$sicmp。
6. ?${$FileName}、${/v:$FileName}這呢?聽我說來,${ aliase} 明確的指出了, 大括號(hào) {} 內(nèi)的變量名是可以被替換的,即使 aliase 和其它文本相連。如果要求 ${} 這個(gè)別名不被替換, 即不被解析程序替換成其他值, 只保留它當(dāng)前的字面值.如下面的ad ${/v:$FileName},刪除別名,此時(shí)用/v 選項(xiàng)來了阻止對(duì)該別名的替換, 保留它原來的字面值;
7. ?別名用完記得要?jiǎng)h除;刪除方法用ad命令。
試試看看結(jié)果,在訪問a.txt時(shí)斷下來了。
?
如果我要在往該文件寫數(shù)據(jù)時(shí)斷下來,如何設(shè)斷?直接在writeFile下斷?但不知道當(dāng)前訪問的是哪個(gè)文件呀?在腳本里,通過文件句柄能得到相應(yīng)的文件名嗎?我反正還不知道,如果你知道請(qǐng)一定不要忘了告我呀?以下為我的腳本:
$$Written by shakesky $$10:44 2009-2-12 $$訪問文件之windbg下斷腳本bp kernel32!CreateFileW " r $t0=poi(esp+4)as /mu $FileName $t0 .echo .printf \"Prepare to visit file:%mu\",$t0 .echo .block {$$ 判斷是否是訪問我所需觀察的文件.if($spat(\"${$FileName}\",\"*a.txt\")) {.echo 'Match...'~.gu$$ 得到文件句柄r @$t1=eax.if(@$t1!=0xFFFFFFFF){$$往該文件寫數(shù)據(jù)時(shí)下斷.printf \"File Handle:%08x\",$t1.echobp kernel32!WriteFile \"r @$t2=poi(esp+4).if(@$t2!=@$t1) {gc}\"}ad ${/v:$FileName}gc }.else {.echo No Match...ad ${/v:$FileName}gc} }"
運(yùn)行結(jié)果截圖:
?全文完,不當(dāng)處請(qǐng)不吝指教。
========
利用windbg腳本調(diào)試簡(jiǎn)單實(shí)例
http://blog.csdn.net/superliuxing/article/details/19505777之前想寫一篇用windbg腳本調(diào)試的東西,但是一直比較懶,懶得動(dòng)手,懶得想例子,把時(shí)間都放在了游戲上面,所以想法雖好一直沒有實(shí)施...
? ? 這次寫一個(gè)非常簡(jiǎn)單的利用windbg腳本進(jìn)行動(dòng)態(tài)調(diào)試的小文,博君一笑.
? ? // Windbgscript.cpp : Defines the entry point for the console application.
//
代碼:
#include "stdafx.h"
#include <iostream>
using namespace std;
int ret100()
{
? int x = 2; ?//2-3
? x*=33;
? ++x;
? return x;
}
int add(int x, int y)
{
? x = 0; //多余的
? return x+y;
}
int _tmain(int argc, _TCHAR* argv[])
{
? int x = 100;
? int y = add( x, ret100());
? cout << y;
? getchar();
? return 0;
}
? ? 上面代碼都非常簡(jiǎn)單,ret100里面做了一個(gè)非常簡(jiǎn)單的操作,我希望它的返回值是100,但現(xiàn)在的返回值是67, 當(dāng)然改法太多了,我這里假設(shè)是初始化時(shí) x 應(yīng)該初始化為3.?
? ? 同樣add里面也有問題,就是對(duì)于參數(shù)x賦值0,認(rèn)為它是一條多余的操作, 因?yàn)槲覀兊哪康氖欠祷豿+y的結(jié)果.
現(xiàn)在執(zhí)行結(jié)果是:
???
如何利用windbg去動(dòng)態(tài)的修改并且不需要我們始終去手動(dòng)交互是我們的主要目的, 首先肯定是要了解這兩個(gè)函數(shù)的內(nèi)部實(shí)現(xiàn).
uf伺候:
代碼:
0:001> uf windbgscript!ret100
? ?11 00401000 55 ? ? ? ? ? ? ?push ? ?ebp
? ?11 00401001 8bec ? ? ? ? ? ?mov ? ? ebp,esp
? ?11 00401003 51 ? ? ? ? ? ? ?push ? ?ecx
? ?12 00401004 c745fc02000000 ?mov ? ? dword ptr [ebp-4],2
? ?13 0040100b 8b45fc ? ? ? ? ?mov ? ? eax,dword ptr [ebp-4]
? ?13 0040100e 6bc021 ? ? ? ? ?imul ? ?eax,eax,21h
? ?13 00401011 8945fc ? ? ? ? ?mov ? ? dword ptr [ebp-4],eax
? ?14 00401014 8b4dfc ? ? ? ? ?mov ? ? ecx,dword ptr [ebp-4]
? ?14 00401017 83c101 ? ? ? ? ?add ? ? ecx,1
? ?14 0040101a 894dfc ? ? ? ? ?mov ? ? dword ptr [ebp-4],ecx
? ?16 0040101d 8b45fc ? ? ? ? ?mov ? ? eax,dword ptr [ebp-4]
? ?17 00401020 8be5 ? ? ? ? ? ?mov ? ? esp,ebp
? ?17 00401022 5d ? ? ? ? ? ? ?pop ? ? ebp
? ?17 00401023 c3 ? ? ? ? ? ? ?ret
?mov ? ? dword ptr [ebp-4],2
對(duì)應(yīng)的就是 x=2;的指令, 我們的目的是將x賦值3, 這里改法很多,比如將ebp-4處賦值3并跳過該指令...
這里選擇最簡(jiǎn)單的,讓該指令執(zhí)行,再執(zhí)行下一條指令前修改x的值.
代碼:
bp windbgscript!ret100 + 0xb " $$ 0xb代表從函數(shù)ret100開始處到當(dāng)前斷點(diǎn)位置的偏移
? ed (ebp-4) 3; $$當(dāng)代碼執(zhí)行到此處時(shí),ebp-4即代表x的內(nèi)存地址, ed命令為在制定地指處 賦值
?gc; ?$$gc命令表示腳本執(zhí)行后,程序會(huì)繼續(xù)執(zhí)行
"
代碼:
0:001> uf windbgscript!add
? ?20 00401030 55 ? ? ? ? ? ? ?push ? ?ebp
? ?20 00401031 8bec ? ? ? ? ? ?mov ? ? ebp,esp
? ?21 00401033 c7450800000000 ?mov ? ? dword ptr [ebp+8],0
? ?22 0040103a 8b4508 ? ? ? ? ?mov ? ? eax,dword ptr [ebp+8]
? ?22 0040103d 03450c ? ? ? ? ?add ? ? eax,dword ptr [ebp+0Ch]
? ?24 00401040 5d ? ? ? ? ? ? ?pop ? ? ebp
? ?24 00401041 c3 ? ? ? ? ? ? ?ret
mov ? ? dword ptr [ebp+8],0
即為那條多余的指令x=0; 我們的目的是讓cpu忽略這條指令, 做法是在這條指令被執(zhí)行前修改eip的值,始之跳轉(zhuǎn)到下一條指令處繼續(xù)執(zhí)行
代碼:
bp windbgscript!add + 0x03 "
?r @eip = @eip+0xa; $$ @符號(hào)會(huì)讓腳本解釋程序認(rèn)為后面跟隨的名稱代表為寄存器, 節(jié)省查找時(shí)間,提高效率
?gc;
"
加載windbg腳本后程序的執(zhí)行結(jié)果:
?
實(shí)在是找不出好的例子來,所以就想出了這么個(gè)下三濫的例子,莫笑。。。
? ?實(shí)際中這么簡(jiǎn)單的程序誰也不會(huì)用windbg調(diào)試的,編寫腳本的時(shí)間可能遠(yuǎn)遠(yuǎn)比重新編譯,部署,調(diào)試所消耗的時(shí)間更長(zhǎng)。
? ?個(gè)人認(rèn)為這種腳本還是比較適合用在重現(xiàn)問題比較困難, 尤其是一種場(chǎng)景, 一個(gè)進(jìn)程開始的時(shí)候沒有任何問題,但是跑一段時(shí)間(比如2-3個(gè)小時(shí))開始不斷重復(fù)出現(xiàn)一連串的錯(cuò)誤(非崩潰),這種場(chǎng)景用windbg腳本還是非常合適的。
? ?windbg腳本里的命令非常豐富,基本平時(shí)能用到的功能都有了,感興趣翻翻幫助文檔學(xué)學(xué)還是很不錯(cuò)的。
========
Windbg腳本和擴(kuò)展命令工具示例
http://www.cr173.com/html/18401_1.html類型:專業(yè)工具大小:216KB語言:中文 評(píng)分:6.6標(biāo)簽:立即下載
好長(zhǎng)一段時(shí)間沒寫文章了,最近一直忙于為項(xiàng)目的可調(diào)式性做一些腳本和擴(kuò)展工具,鑒于對(duì)windbg強(qiáng)大威力的震撼,以及相對(duì)較少的資料,筆者決定寫一系列關(guān)于如何開發(fā)Windbg腳本和擴(kuò)展命令的文章,您的支持是我最大的動(dòng)力,希望本系列文章對(duì)您有所幫助。
那么一個(gè)完整的windbg script是什么樣子的呢?首先讓我們看如下示例:
$$ 該腳本是列出用戶進(jìn)程和棧
r $t0 = nt!PSActiveProcessHead?
.for (r $t1 = poi(@$t0); (@$t1 != 0) & (@$t1 != @$t0); r $t1 = poi(@$t1))?
{?
? r? $t2 = #CONTAINING_RECORD(@$t1, nt!_EPROCESS, ActiveProcessLinks);?
? .process @$t2?
? .reload?
? !process @$t2
}
相對(duì)于Windbg腳本,windbg擴(kuò)展比較復(fù)雜,而且通常需要花費(fèi)更大的精力寫出同樣的功能,但是它帶來的一個(gè)好處就是你可以獲得更多的功能,你甚至可以通過這些擴(kuò)展寫一個(gè)調(diào)試器,那么一個(gè)完整的windbg擴(kuò)展又是什么樣子的呢?該擴(kuò)展dll打印出一個(gè)全局字符串的值。
以C++語言編寫的windbg擴(kuò)展示例:
HRESULT CALLBACK?
PrintPTR(PDEBUG_CLIENT pDebugClient, PCSTR args)
{
? ? UNREFERENCED_PARAMETER(args);
? ? IDebugSymbols* pDebugSymbols;
? ? if (SUCCEEDED(pDebugClient->QueryInterface(__uuidof(IDebugSymbols), (void **)&pDebugSymbols)))
? ? { ? ?// Resolve the symbol
? ? ? ? ULONG64 ulAddress = 0;
? ? ? ? if (SUCCEEDED(pDebugSymbols->GetOffsetByName("TestSTLMap!g_wString", &ulAddress)))
? ? ? ? {
? ? ? ? ? ? IDebugDataSpaces* pDebugDataSpaces;
? ? ? ? ? ? if (SUCCEEDED(pDebugClient->QueryInterface(__uuidof(IDebugDataSpaces), (void **)&pDebugDataSpaces)))
? ? ? ? ? ? { ? ?// Read the value of the pointer from the target address space
? ? ? ? ? ? ? ? ULONG64 ulPtr = 0;
? ? ? ? ? ? ? ? if (SUCCEEDED(pDebugDataSpaces->ReadPointersVirtual(1, ulAddress, &ulPtr)))
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? PDEBUG_CONTROL pDebugControl;
? ? ? ? ? ? ? ? ? ? if (SUCCEEDED(pDebugClient->QueryInterface(__uuidof(IDebugControl), (void **)&pDebugControl)))
? ? ? ? ? ? ? ? ? ? { ? ?// Output the values
? ? ? ? ? ? ? ? ? ? ? ? pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "%p TestSTLMap!g_wString= 0x%p\n", ulAddress, ulPtr);
? ? ? ? ? ? ? ? ? ? ? ? pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "%mu\n", ulPtr);
? ? ? ? ? ? ? ? ? ? ? ? pDebugControl->Release();
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? pDebugDataSpaces->Release();
? ? ? ? ? ? }
? ? ? ? ? ? pDebugSymbols->Release();
? ? ? ? }
? ? }
? ? return S_OK;
}
總結(jié)
基于筆者的研究發(fā)現(xiàn),國(guó)內(nèi)做相關(guān)研究的人并不多,其實(shí)國(guó)外也就幾個(gè)業(yè)內(nèi)比較牛的人做的相對(duì)比較好,但是這些工具的作用足以讓你震撼,今天開個(gè)頭,有興趣的朋友可以繼續(xù)關(guān)注后續(xù)文章。
========
Windbg腳本和擴(kuò)展工具之一STL容器擴(kuò)展命令
http://www.tuicool.com/articles/aqmmAz--by solidmango
想寫一篇關(guān)于windbg的STL容器擴(kuò)展命令的文章已經(jīng)有一段時(shí)間了,但是最近項(xiàng)目比較忙,再加上有幾本書特別想讀,所以就耽誤下來了,以至于整個(gè)三月都沒來得及寫,今天終于有時(shí)間可以把這篇文章寫完。至于windbg和STL都是什么在這里我就不細(xì)說了,能打開我這篇文章的想必都是行家,那么我為什么想寫著么一個(gè)主題的文章呢?
STL容器在調(diào)試的時(shí)候內(nèi)部實(shí)現(xiàn)相對(duì)來說還是比較復(fù)雜的,而在某些生產(chǎn)情況下和一些極端的問題分析的時(shí)候visual studio 是登不了大雅之堂的,當(dāng)然我不是說vs不好,在很多時(shí)候他是神器,但是它不是萬能的。
舉個(gè)例子:
如下類型的map
std::map<int,string>
實(shí)際的內(nèi)部節(jié)點(diǎn)類型可能是這樣的:
std::_Tree_nod<std::_Tmap_traits<int,std::basic_string<char,std::char_traits<char>,
std::allocator<char>>,
std::less<int>,
std::allocator<
std::pair<
int const , std::basic_string<char,std::char_traits<char>,std::allocator<char> > > >,0> >::_Node
STL內(nèi)部traits的應(yīng)用遍地都是,但是甚至好多謝了好久代碼的人可能都還是理解不了其巧妙之處。可能是由于其實(shí)現(xiàn)相對(duì)比較復(fù)雜,windbg內(nèi)部的和現(xiàn)有的擴(kuò)展對(duì)這塊的調(diào)試支持都相對(duì)較差,當(dāng)然如果你是高手,在某些簡(jiǎn)單的情況下,這塊是有方法繞過去的,但是問題如果想對(duì)復(fù)雜就恐怕不行了。
那么我都做了什呢?我實(shí)現(xiàn)了如下的幾個(gè)擴(kuò)展命令,只要給出地址和類型就可以將整個(gè)容器打出來。
0:000> !help
PRTSTLMap ? ? ? ? ?<Address> ? ? ?Type ? ? ?
PRTSTLMap2 ? ? ? ?<Address> ? ? ?Type ? ? ?
PRTSTLList ? ? ? ? ? <Address> ? ? ?Type ? ? ?
PRTSTLVector ? ? ? <Address> ? ? ?Type
詳細(xì)的每個(gè)命令的使用情況請(qǐng)參照如下的demo:
如下為!PRTSTLMap使用方法:
0:000>!PRTSTLMap (0x0012fd14+0x194) std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > >
Size of map is: 5
TestSTLMap!std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > >
? ?+0x000 first ? ? ? ? ? ?: 11
? ?+0x004 second ? ? ? ? ? : std::basic_string<char,std::char_traits<char>,std::allocator<char> >
? ? ? +0x000 _Alval ? ? ? ? ? : std::allocator<char>
? ? ? =00400000 npos ? ? ? ? ? ? : 0x905a4d
? ? ? +0x004 _Bx ? ? ? ? ? ? ?: std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Bxty
? ? ? ? ?+0x000 _Buf ? ? ? ? ? ? : [16] ?"aaa"
? ? ? ? ?+0x000 _Ptr ? ? ? ? ? ? : 0x00616161 ?""
? ? ? +0x014 _Mysize ? ? ? ? ?: 3
? ? ? +0x018 _Myres ? ? ? ? ? : 0xf
TestSTLMap!std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > >
? ?+0x000 first ? ? ? ? ? ?: 12
? ?+0x004 second ? ? ? ? ? : std::basic_string<char,std::char_traits<char>,std::allocator<char> >
? ? ? +0x000 _Alval ? ? ? ? ? : std::allocator<char>
? ? ? =00400000 npos ? ? ? ? ? ? : 0x905a4d
? ? ? +0x004 _Bx ? ? ? ? ? ? ?: std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Bxty
? ? ? ? ?+0x000 _Buf ? ? ? ? ? ? : [16] ?"bbb"
? ? ? ? ?+0x000 _Ptr ? ? ? ? ? ? : 0x00626262 ?""
? ? ? +0x014 _Mysize ? ? ? ? ?: 3
? ? ? +0x018 _Myres ? ? ? ? ? : 0xf
TestSTLMap!std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > >
? ?+0x000 first ? ? ? ? ? ?: 13
? ?+0x004 second ? ? ? ? ? : std::basic_string<char,std::char_traits<char>,std::allocator<char> >
? ? ? +0x000 _Alval ? ? ? ? ? : std::allocator<char>
? ? ? =00400000 npos ? ? ? ? ? ? : 0x905a4d
? ? ? +0x004 _Bx ? ? ? ? ? ? ?: std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Bxty
? ? ? ? ?+0x000 _Buf ? ? ? ? ? ? : [16] ?"ccc"
? ? ? ? ?+0x000 _Ptr ? ? ? ? ? ? : 0x00636363 ?"w"
? ? ? +0x014 _Mysize ? ? ? ? ?: 3
? ? ? +0x018 _Myres ? ? ? ? ? : 0xf
TestSTLMap!std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > >
? ?+0x000 first ? ? ? ? ? ?: 14
? ?+0x004 second ? ? ? ? ? : std::basic_string<char,std::char_traits<char>,std::allocator<char> >
? ? ? +0x000 _Alval ? ? ? ? ? : std::allocator<char>
? ? ? =00400000 npos ? ? ? ? ? ? : 0x905a4d
? ? ? +0x004 _Bx ? ? ? ? ? ? ?: std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Bxty
? ? ? ? ?+0x000 _Buf ? ? ? ? ? ? : [16] ?"dddd"
? ? ? ? ?+0x000 _Ptr ? ? ? ? ? ? : 0x64646464 ?"--- memory read error at address 0x64646464 ---"
? ? ? +0x014 _Mysize ? ? ? ? ?: 4
? ? ? +0x018 _Myres ? ? ? ? ? : 0xf
TestSTLMap!std::pair<int const ,std::basic_string<char,std::char_traits<char>,std::allocator<char> > >
? ?+0x000 first ? ? ? ? ? ?: 15
? ?+0x004 second ? ? ? ? ? : std::basic_string<char,std::char_traits<char>,std::allocator<char> >
? ? ? +0x000 _Alval ? ? ? ? ? : std::allocator<char>
? ? ? =00400000 npos ? ? ? ? ? ? : 0x905a4d
? ? ? +0x004 _Bx ? ? ? ? ? ? ?: std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Bxty
? ? ? ? ?+0x000 _Buf ? ? ? ? ? ? : [16] ?"eeeee"
? ? ? ? ?+0x000 _Ptr ? ? ? ? ? ? : 0x65656565 ?"--- memory read error at address 0x65656565 ---"
? ? ? +0x014 _Mysize ? ? ? ? ?: 5
? ? ? +0x018 _Myres ? ? ? ? ? : 0xf
?
如下為擴(kuò)展名伶!PRTSTLList的使用方法:
0:000> !PRTSTLList (0x0012fd14+0x178) CPoint
? ? Size of list is: 3
TestSTLMap!CPoint
? ?+0x000 x ? ? ? ? ? ? ? ?: 7
? ?+0x004 y ? ? ? ? ? ? ? ?: 8
TestSTLMap!CPoint
? ?+0x000 x ? ? ? ? ? ? ? ?: 4
? ?+0x004 y ? ? ? ? ? ? ? ?: 6
TestSTLMap!CPoint
? ?+0x000 x ? ? ? ? ? ? ? ?: 6
? ?+0x004 y ? ? ? ? ? ? ? ?: 9
?
如下為擴(kuò)展名伶! PRTSTLVector的使用方法:
0:000> !PRTSTLVector (0x0012fd14+0x1d4) CPoint
Size of Vector is: 6
TestSTLMap!CPoint
? ?+0x000 x ? ? ? ? ? ? ? ?: 17
? ?+0x004 y ? ? ? ? ? ? ? ?: 88
TestSTLMap!CPoint
? ?+0x000 x ? ? ? ? ? ? ? ?: 16
? ?+0x004 y ? ? ? ? ? ? ? ?: 87
TestSTLMap!CPoint
? ?+0x000 x ? ? ? ? ? ? ? ?: 15
? ?+0x004 y ? ? ? ? ? ? ? ?: 86
TestSTLMap!CPoint
? ?+0x000 x ? ? ? ? ? ? ? ?: 14
? ?+0x004 y ? ? ? ? ? ? ? ?: 85
TestSTLMap!CPoint
? ?+0x000 x ? ? ? ? ? ? ? ?: 13
? ?+0x004 y ? ? ? ? ? ? ? ?: 84
TestSTLMap!CPoint
? ?+0x000 x ? ? ? ? ? ? ? ?: 12
? ?+0x004 y ? ? ? ? ? ? ? ?: 83
總結(jié)
本文實(shí)現(xiàn)了幾種擴(kuò)展WINDBG STL調(diào)試支持的擴(kuò)展命令,旨在方便STL調(diào)試,算是拋磚引玉,希望打開大家的視野,其實(shí)好多時(shí)候在某些領(lǐng)域我們是可以做一些事情的,不要總跟在老外的后面走,由于需要使用這些擴(kuò)展命令的人不多,本文不會(huì)附上相關(guān)的擴(kuò)展文件,如果有人需要,請(qǐng)私信。
========
總結(jié)
以上是生活随笔為你收集整理的windbg 脚本学习总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MySQL优化学习总结
- 下一篇: VC++ .Net 实例学习