windbg 腳本命令實例
debugger commands部分,痛苦死了。也找不到WINDBG的插件,還是WINDBG沒插件功能?爲了簡化調試過程,只有學習使用SCRIPT了,現在把這幾天的經驗跟大家分享。附件中所有代碼經NOTEPAD,REGEDIT等調試,花了幾小時,基本通過。
廢話多了,現在是正文。WINDBG的指令比較多,還是英文的,所以我只挑了一部分經常會用到的,並通過實例去告訴大家那些指令的作用和格式。正如大多數高級語言教程一樣,我們先來看看如何寫一個HELLO WORLD的程序。
如果使用.echo "HELLO WORLD"作爲例程就太簡單了,我希望介紹更多的指令。所以我在OD直接用匯編寫了個程序:
PUSH 0
PUSH 12345678 ;TITLE跟顯示內容都在這個跟下一個PUSH
PUSH 12345678 ;我比較懶。。。就用一樣的字符了
PUSH 0
MOV EAX,OFFSET MESSAGEBOXW
CALL EAX
先用EAX保存MESSAGEBOXW的指針,然後再CALL。這是爲了你在任何一個程序下都能用使用這個SCRIPT。如果直接CALL MESSAGBOXW的指針,翻譯成機器碼是相對於當前位置的偏移,這樣寫出來的SCRIPT文件在這個程序能用,別的程序就不能用了。
機器碼 6A 00 68 78 56 34 12 68 78 56 34 12 6A 00 b8 68 3d e2 77 ff d0
我虛擬機使用的是WIN 2000 連SP1都不是。。所以我不保證你的機器仍然能正常運行這個程序。爲了能正常使用,你可以隨便找一個程序,然後BP MESSAGEBOXW,中斷之後當前的EIP就是了,把ff d0前面的68 3d e2 77換掉了就可以了。我的目的並不是介紹如何寫一個兼容性差的程序,重點是學會如何寫SCRIPT。
準備工作做好了,在看代碼之前,先解釋一些指令:
$exentry僞寄存器,數值上等於EP
$t0-$t19,WINDBG爲我們提供了20個自定義的僞寄存器
R指令能改變幾乎所有寄存器的值,包括EAX等
.dvalloc [/b] size 申請內存空間,帶/b 地址,可在指定地址申請空間,不帶則自動分配,指定地址時不一定成功,暫時的經驗指定地址越大越容易成功。
e* 地址 在指定內存中寫入數據,EW 寫入WORD,EB寫入BYTE,ED寫入DWORD
注意: EW 00400000 12345會產生溢出錯誤,同理EB 00400000 123也是錯的,正確的例子可見後面的代碼
f 地址 L長度 BYTE 在長度的地址寫入數據,你可以在示例中看到效果。同樣BYTE的位置只能是BYTE,多於8位的數據都會造成溢出錯誤。
m 源地址 L源地址長度 目的地址 複製內存區域
d* 地址 顯示地址中的數據,其中db的效果可在示例中看到。
.dvfree /d 地址 size 釋放指定地址的內存,這裏指定地址用的是/d要與 .dvalloc的/b相區別。
附件中helloworld.txt的代碼:
---------------------------------------helloworld.txt--------------------------------
g $exentry
r $t0=00ff0000; $$ $t0:源內存基址
r $t2=@$exentry; $$ $t2:目的內存基址
r $t1=@$t0; $$ $t1:當前指針
.dvalloc /b $t0 1000; $$在00b90000申請1000BYTE的內存空間
ew $t1 006A 0068
db $t0
.echo "ew指令的效果"
r $t3 = @$t1 + 3; $$PUSH DWORD的機器碼=68 DWORD
$$這裏應該輸入字符串的首址
r $t1 = @$t1 + 7; $$懶得計算,所以用$t3存起DWORD的指針
$$輸入字符串的時候一起搞定
eb $t1 68 12 34
db $t0
.echo "eb指令的效果"
r $t4 = @$t1 + 1; $$同上
r $t1 = @$t1 + 5
f $t1 l20 6A 00 b8 68 3d e2 77 ff d0
db $t0
.echo "f指令的效果"
r $t1 = @$t1 + 9
r $t5 =$t1 - $t0 + $t2
ed $t3 $t5; $$ 添加字符串的指針回去
ed $t4 $t5
f $t1 l20 'h' 'e' 'l' 'l' 'o' ' ' 'w' 'o' 'r' 'l' 'd' '!' 00 00
$$ 把字符串寫進內存中
m $t0 l30 $t2
r $ip=$t2; $$ 修改EIP
.dvfree /d $t0 1000; $$ 釋放內存
g
---------------------------------------helloworld.txt完結的分割線--------------------------------
爲了你的速度,請保證symbol path爲空,只有在你有源代碼或者系統核心的時候它的存在纔有意義,否則你會發現它會非常費時且毫無意義,尤其是你得連上網絡下載symbol資源的時候。
使用SCRIPT文件的命令有4個"$<","$$<","$><","$$><",他們的區別就是有沒有空格或者換行符的限制。使用$$><沒有任何限制,這樣可使代碼更具可讀性。要使用附件中的SCRIPT請使用$$><指令。
例如你可以用下面指令訪問在D盤下的helloworld.txt。
$$><d:\helloworld.txt
如果你把helloworld.txt放在WINDBG的安裝目錄,那麼你可以使用下面指令:
$$><helloworld.txt
運行完helloworld.txt後你會發現報錯了,因爲我的代碼覆蓋了EP。通過上面的例子,我們能用SCRIPT做什麼呢?在合適的時機,把沒加密的IAT或者其他什麼的,暫存到內存中,在脫殼完畢的時候再自動用正確的部分把加密部分覆蓋掉。
也許在未來,也會遇到這樣的需要,程序運行到某部分的時候,中斷,然後運行我們自己的代碼,運行完畢之後,我們需要返回到程序原來的流程。爲此我把上面的SCRIPT修改了一下,寫成BACKTOCODE.TXT。
--------------------------------------------backtocode.txt--------------------------------------
r $t0=00ff0000
r $t1=@$t0
r $t18=$ip ;$$ 用$t18暫存當前EIP,顯然$ip=EIP
.dvalloc /b $t0 1000
ew $t1 006A 0068
r $t3 = @$t1 + 3
r $t1 = @$t1 + 7
eb $t1 68 12 34
r $t4 = @$t1 + 1
r $t1 = @$t1 + 5
f $t1 l20 6A 00 b8 68 3d e2 77 ff d0
r $t1 = @$t1 + 9
ed $t3 $t1
ed $t4 $t1
ba e1 $t1 ;$$ 內存運行斷點,E代表運行1是長度,在E後面通常是1,斷在最後一個指令後的第一個地址
f $t1 l20 'h' 'e' 'l' 'l' 'o' ' ' 'w' 'o' 'r' 'l' 'd' '!' 00 00
r $ip=$t0 ;$$ 在分配的內存中直接運行我們自己的代碼
g
.dvfree /d $t0 1000
r $ip=$t18 ;$$ 把EIP設置爲原來的
.cls ;$$ 當前命令行窗口清屏
p ;$$ 單步步過
-------------------------------------------backtocode.txt結束-----------------------------------
爲了anti anti debug我們需要隱藏標題,雖然WINDBG本身有.wtitle指令,可是那個指令會把它後面的所有內容當作字符串輸入,而且windbg+版本號是無論怎麼改都會被默認添加到最後的。這樣上面那個SCRIPT就有用了,就差CODE了。
爲了anti anti debug,每次DEBUG的時候,我們都要做一些準備工作,用SCRIPT文件,我們可以自動完成這些操作,下面是我DEBUG之前都會用到的SCRIPT文件
-----------------------------------------------start.txt----------------------------------------
r $t0 = 00
eb 7FFDF002 $t0 ;$$去除DEBUG標誌
.pcmd -s ".if(eax<70000000 and eax>00120000){da eax;du eax}; .if(edx<70000000 and edx>00120000){da edx;du edx}"
g $exentry ;$$入口點
-------------------------------------------start.txt結束----------------------------------------
如你所見的,這有點少。沒辦法水平有限,而且寫這篇文章的時候我才勉強說是學會用,還是那句重點是教會大家用WINDBG。WINDBG的初始斷點並不是入口點所以得自己用指令讓它自動停在入口點,有的程序是有TLS表的,對着PE格式的介紹文章,寫一個SCRIPT在有TLSCALLBACK的情況下自動停在TLSCALLBACK入口是有可能的,你會在文章的最後部分得到相關指令的介紹。現在來說說START.TXT中沒有註釋的指令。
; 分號,多條命令的分隔符。從左到右運行。
下面例子中,對MESSAGEBOXW下斷後運行,中斷之後便會運行r $t0=esp+8指令
bp messageboxw;g;r $t0=esp+8
注意:如果你使用CRTL+BREAK快捷鍵在中斷之前暫停調試也會導致r $t0=esp+8的運行。
.if(條件表達式){命令} 跟C語言中的用法一樣。
.pcmd 不帶參數則顯示每條指令之後自動使用的指令。-s "命令" 設置命令。-c 清除命令。
da 以ASCII顯示內存地址,du以UNICODE顯示內存地址
在示例中,整條指令的效果表現爲,每單步一個指令,便會當EAX,EDX指向的是一個合法地址的時候,便以ASCII和UNICODE的方式分別顯示它的值,就象OD那樣。如果熟悉ASCII和UNICODE字符集的範圍還能設置僅當有效字符時才顯示結果。
標 題: 答覆
作 者: 笨笨雄
時 間: 2006-10-22 17:04
詳細信息:
在調試的過程中,有時我們希望自動化解決一些問題。例如調試使用了UnhandledExceptionFilter的SEH,我們需要自動修改ZwQueryInformationProcess的返回值。或者對於某些API的ANTI DEBUG,如果我們修改了輸入參數,同樣不能返回應該返回的值。學破解不久,一下子要找用了UnhandledExceptionFilter的軟件還真不容易,用別的API代替了。我用OD把NOTEPAD修改一下,改名爲TEST放在附件中。
流程MESSAGEBOXW,GETCOMMANDLINEW,MESSAGEBOXW輸出COMMANDLINE,最後EXITPROCESS。
現在我要做的是改變GETCOMMANDLINEW的輸出,和第二個MESSAGEBOXW的輸入。現在讓我們看看test2.txt
-------------------------------------------test2.txt-----------------------------------------------
g $exentry
r $t0=0
bp messageboxw "r $t0=$t0+1;j($t0=2)'r $t1=poi(esp+8);f $t1 l4 45;g';g"
bp getcommandlinew "g poi(esp);r $t1=eax+5;f $t1 l4 55;g"
g
------------------------------------------test2.txt完結---------------------------------------------
首先對相關指令作一些介紹
BP 地址或者函數名 "命令" 命令參數是可選的,存在的情況下,中斷的同時會先運行那些命令。
J(條件表達式)'命令1';命令2 相當於.if但是又有點不同命令2只能是1個,後面所有命令會被忽略。
POI() 返回指針的指向位置的內容。
!= 不等於
這裏用了條件中斷的方法實現,第一個條件中斷指令用$t0作爲計數器,第二次中斷的時候變修改堆棧中指針指向位置的內存區域。注意到調用API的返回地址在ESP中,直接跳出去,然後修改EAX就可以達到修改函數輸出參數的效果了。
這裏提供第二種可行的方法,並且更有可擴展性,現在看看test.txt中的代碼。
-------------------------------------------test.txt------------------------------------------------
g $exentry
r $t0=0
bp messageboxw
bp getcommandlinew
bp exitprocess
.while (eip!=77e7b0bb){
g
.if($ip=77e116cc){
r $t0=$t0+1
.if($t0=2){
r $t1=poi(esp+8)
f $t1 l4 45
}
}
.if($ip=77e7c693){
g poi(esp)
r $t1=eax+5
f $t1 l4 55
}
.elsif($ip=77e7b0bb){
.break
}
}
g
------------------------------------------test.txt完結----------------------------------------------
仍然先介紹一些指令:
.while(條件表達式){} 跟C語言中的一樣,循環結構,直到條件表示式爲真
.elsif(){} 跟前面的.if用法一樣,它的作用如字面上意思,只是小心別拼錯爲ELSEIF
.break 跟C語言中的一樣,跳出循環。
如果在條件爲真的時候不用.break跳出循環就會出錯,這點要注意。
這裏構造了一個循環結構,並且通過對比EIP的方法來識別函數,同樣地因爲我的虛擬機是WIN 2000 連SP1都不是,所以我不肯定該地址在你的機器中仍然可用。不過這裏提供了一個思路,你可以用這個方法構造一個SCRIPT來加強WINDBG的功能,例如象OD一樣中斷的時候自動顯示所有參數,並且帶上英文提示那是什麼參數。同樣地,我們可以做一個自動化分析SCRIPT,分析每個CALL中包含了什麼API,並且列出輸入和輸出參數,CALL的深度還指令數,並且自動生成報告文件,假如有人開發出這樣一個SCRIPT,調試分析將會變得容易。WINDBG裏面有個相似功能的指令。
WT 自動跟蹤並生成報告,幾乎跟我上面說的一樣。帶/l參數的時候可以設置深度,不過很多時候,我們看到一個CALL並不知道里面究竟有多深,但是我們希望得到一些關於那個CALL的詳細信息來判斷是否值得跟進。這裏有兩個問題:
1 遞歸,那這個指令不知道運行多久。
2 大量NATIVE API調用,顯然大多數情況下,我們並不關心。
比起1,2更加常見,/i參數是用來避開指定模塊的,不會用,幫助文件裏也沒提。。。。希望有大大能答我這個問題
WINDBG提供了下面3個指令用於保存分析過程進文件,通過適當的開關可以過濾一些無意義的信息,使分析過程易於觀看。
.logopen 文件路徑 帶/U參數則以UNICODE方式輸入文本。重寫整個文件,並記錄當前命令窗口在使用該指令之後的所有內容。
.logclose 文件路徑 停止記錄並關閉文件。
.logappend 文件路徑 帶/U參數則以UNICODE方式寫文件。記錄當前命令窗口在使用該指令之後的所有內容,並添加進文件。
提到了功能強化,大家都知道OD裏面有個命令是運行到RET處吧,在WINDBG中似乎沒有這樣的指令,類似的有PC,即運行到CALL。我寫了一個SCRIPT來模擬OD中的那個指令。現在我們來看看goret.txt
-------------------------------------------goret.txt------------------------------------------------
r $t0=0
.while(@$t0!=c3){
p
r $t0=by(eip)
.if(@$t0=c3){
.break
}
}
-----------------------------------------goret.txt完結----------------------------------------------
這裏是最後一個示例分析,所以除了解釋上面的指令之外也給出一些有價值的指令
not 非 and或者& 與
hi() 取高16位 or或者^ 或
low() 取低16位 xor或者| 異或
by() 取低8位 gu 步出,不知道具體原理,有時會出錯
wo() 取低16位 t 步入
mod或者% 模運算
這個SCRIPT使用了一個循環,通過EIP取得當前指令的機器碼,低8位既爲指令,然後把指令存進$t0作比較。C3是RET的機器碼,等於則跳出循環,否則一直步過。
這個示例表明,我們可以在SCRIPT裏分析每一條指令。我們可以在WINDBG中進行2次開發,動態將那些簡單使用JMP+內存指針或者寄存器作爲跳轉的亂序的程序重新排序,使花指令失效,並且實現自動清除垃圾指令,最後生成優化後的彙編代碼文件。本論壇翻譯區裏的變形多態中的關於收縮器的理論已經爲我們奠定了理論基礎。
你可能會需要用到反彙編指令
u 起始地址 l長度 L代表的不是地址長度而是指令的個數
---------------------------------後續討論,用SCRIPT把WINDBG變成脫殼機------------------------------
在準備寫這篇文章的時候,我又把DEBUGGER COMMANDS看了一次,發現了這個指令
.writemen filename range 將目標內存區域寫進文件。RANGE的格式爲 地址 l長度
我沒試過L後面是否接受寄存器作爲參數。也沒實際測試過這個指令的具體操作是怎麼樣的,無論如何,有這個可能存在。當然我們也可以申請內存區域以程序的方式來完成這個工作,不過我希望它僅用SCRIPT完成。
假如這的確可行,可以通過下面指令組合來自動尋找文件頭,當然也能確定文件大小。
$p 僞寄存器,它將返回前一次用d*指令所顯示的內存的內容。
假設00100000 01 02 03 04 05 06 07 08
我使用dd 00100000,那麼$p = 04030201
顯然我們可以通過這個方法來訪問內存。
dw 取一個WORD; dd取DWORD; dw取qword
能訪問內存也代表說我們在調試程序中插入的代碼也能跟SCRIPT通信,並且把一些SCRIPT無法完成的工作交給程序執行,然後把結果返回給SCRIPT。
假如l的參數無法通過寄存器來傳遞,只能依靠用戶按照提示進行操作,那麼我們有更簡單的方法
.imgscan 它將返回所有模塊MZ的地址和它的SIZE
----------------------------------這裏給出一些可能的疑問和解答--------------------------------------
Q:在調試SCRIPT文件的時候,我該如何知道寄存器跟內存的變化?
A:我們可以用下面的指令來觀察寄存器跟內存的變化
d* 用於顯示內存,之前已經提到就不詳細說明了
? 寄存器 顯示寄存器的值,例如
? poi(esp); ? $t0
這將先顯示ESP指向的值,然後顯示$t0的值
除了可以使用.echo命令對顯示參數作說明之前,也可以使用.printf作格式化輸出,它的用法跟C語言中的printf是一樣的
Q:我寫的SCRIPT文件出錯了,語法跟參數都沒錯,爲什麼我找不到出錯原因?
A:有的指令要注意的,BA只能在進入程序區域之後才能用。.dvalloc申請過的內存,即使用.dvfree釋放了,也無法在同樣的位置再申請,可能是BUG。
*是一個註釋命令,它後面所有的內容都會被當作字符
$$則是以分號爲結束
.restart指令跟.wtitle指令,不知道爲什麼不能放在SCRIPT中使用。
還有就是@這個標記,這個標記是告訴WINDBG後面的是一個僞寄存器而不是程序裏的某一個變量的符號。有的指令在沒有@標記的時候會報錯,例如.while括號裏的條件表達式,如果你用了僞寄存器,一定要在前面加上@否則一定報錯。此外用幫助文件裏的話來說,使用@,可以讓SCRIPT文件運行得更快,因爲在解讀這個代碼的時候不需要先搜索一次SYMBOL記錄。
Q:我能把功能模塊化然後在其他SCRIPT文件中使用嗎?
A:我已經測試過$$><指令也能在SCRIPT裏面使用
Q:我寫的SCRIPT FILE能在64位系統中用嗎?
A:如果你僅使用SCRIPT來實現功能,那麼很可能與64位兼容。儘量使用僞寄存器。
$ip,$retreg,$csp在32位系統中分別表示EIP,EAX,ESP,而在64位系統中則表示RIP,RAX,RSP也分別對應Itanuim處理器中的相關寄存器。
通過函數名獲取不同版本下的地址,可以通過下面代碼:
bp messageboxw ; $$第一個斷點,斷點ID爲0
bp getcommandlinew; $$第二個斷點,斷點ID爲1
r $t10 = $bp0; $$將第一個斷點的地址轉存$t10
r $t11 = $bp1; $$將第二個斷點的地址轉存$t11
bc *; $$清除所有斷點。
這段代碼運行之後MESSAGEBOXW的地址便存於$t10中,而$t11裏面的則是getcommandlinew的地址。這裏要說明,斷點用完要釋放,否則不好估計斷點的ID,此外在內核模式中,最多隻允許32個斷點。
$peb和$teb返回當前進程的PEB和TEB地址,這裏的翻譯區有介紹如何僅通過PEB或者TEB判斷當前操作系統類型
爲不同系統準備不同代碼
總算寫完了。。。。再廢話幾句
先來了解簡單的,得到當前訪問的文件名
先寫段C代碼,創建C:\a.txt並往文件中寫任意幾個字符,代碼如下:
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);
把以上代碼放到對話框的按鈕點擊響應事件中去。編譯鏈接得到test.Exe.
文件名爲CreateFile API的第一個參數,因而在執行到該API的入口時,esp+4即表示第一個參數的地址。故可這樣下斷:
bp kernel32!CreateFileW "r $t1=poi(esp+4);.echo;.printf\"FileName:%mu\",$t1;.echo;g"
$t0~$t19爲僞寄存器,可用來存儲臨時值,poi表示取地址的值,
也可將腳本保存爲文件,然後在windbg中輸入: $$><腳本文件路徑 來運行。
我把以上腳本保存爲 ”C:\script.txt”
用windbg打開以上代碼編譯得到的test.exe,
Ctrl+Break中斷windbg,然後下斷,即輸入:$$><C:\script.txt,再輸入g,讓進程運行起來,
點擊按鈕,果其然,得到文件名了,見下圖,
23985
訪問的文件獲取了,那如何在訪問指定文件時中斷下來呢?字符串比較的腳本如何寫呀?
上網查資料吧,不大一會,發現了$scmp/$sicmp/$spat是用來字符串操作的。$spat正合我意呀。
$spat("string1”, "pattern”):判斷參數1指定的字符串是否符合參數2指定的模式。模式字符串中可以包含?、*、#等特殊符號,WinDBG幫助文件中String Wildcard Syntax一節包含了詳細的說明;
這樣摸索了一番,寫了如下腳本:
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
}
}"
以上腳本,不復雜,實現當訪問文件名類似“a.txt”時,windbg中斷執行。
對腳本解析幾個要點:
1. 使用僞寄存器,更快速的方法是在$前加上一個@符號。這樣,WinDBG就知道@後面是一個僞寄存器,不需要搜索其他符號;
2. r $t1=poi(esp+4),poi(esp+4)取地址的值,並賦給僞寄存器$t1 ;
3. as /mu $FileName $t1 ,定義$t1 所指地址一個別名$FileName,用來在下面的$spat中使用。別名會在腳本加載時被解析程序替換一次。爲何要用別名?你不用試試就知道了,直接用$t1不行,windbg提示你語法錯誤;
4. .block是啥東西,看windbg幫助就知道了。代碼塊,如果需要每次運行進入替換,請用.block括起來;我這裏有個別名,需要每次替換,所以用了個.block括起來;
5. $spat爲模式匹配函數,其他類似函數$scmp/$sicmp。
6. ${$FileName}、${/v:$FileName}這呢?聽我說來,${ aliase} 明確的指出了, 大括號 {} 內的變量名是可以被替換的,即使 aliase 和其它文本相連。如果要求 ${} 這個別名不被替換, 即不被解析程序替換成其他值, 只保留它當前的字面值.如下面的ad ${/v:$FileName},刪除別名,此時用/v 選項來了阻止對該別名的替換, 保留它原來的字面值;
7. 別名用完記得要刪除;刪除方法用ad命令。
試試看看結果,在訪問a.txt時斷下來了。
23986
如果我要在往該文件寫數據時斷下來,如何設斷?直接在writeFile下斷?但不知道當前訪問的是哪個文件呀?在腳本里,通過文件句柄能得到相應的文件名嗎?我反正還不知道,如果你知道請一定不要忘了告我呀?以下爲我的腳本:
$$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)
{
$$往該文件寫數據時下斷
.printf \"File Handle:%08x\",$t1
.echo
bp kernel32!WriteFile \"
r @$t2=poi(esp+4)
.if(@$t2!=@$t1) {gc}
\"
}
ad ${/v:$FileName}
gc
}
.else
{
.echo No Match...
ad ${/v:$FileName}
gc
}
}
"
運行結果截圖:
23987
WINDBG看起來很難用,是因爲用的人不多。
即使沒有插件功能,WINDBG SCRIPT的功能也已經很強大了。
如果大家都來做SCRIPT,調試分析難度會降低很多,新手也可以通過閱讀SCRIPT FILE來學習。搜索引擎使用得好的確可以學到很多,可惜這跟作者的表達和使用引擎者的表達有關,很可能相同的內容,因爲表達方式不同就查不到了。就象我學校的圖書館,在電腦搜索逆向工程是什麼都找不到的,但是搜索加密解密,卻看到好幾本書。
OD雖然好,始終是RING3的,SOFTICE似乎也已經停止開發了。希望大家都能加入WINDBG的行列
廢話多了,現在是正文。WINDBG的指令比較多,還是英文的,所以我只挑了一部分經常會用到的,並通過實例去告訴大家那些指令的作用和格式。正如大多數高級語言教程一樣,我們先來看看如何寫一個HELLO WORLD的程序。
如果使用.echo "HELLO WORLD"作爲例程就太簡單了,我希望介紹更多的指令。所以我在OD直接用匯編寫了個程序:
PUSH 0
PUSH 12345678 ;TITLE跟顯示內容都在這個跟下一個PUSH
PUSH 12345678 ;我比較懶。。。就用一樣的字符了
PUSH 0
MOV EAX,OFFSET MESSAGEBOXW
CALL EAX
先用EAX保存MESSAGEBOXW的指針,然後再CALL。這是爲了你在任何一個程序下都能用使用這個SCRIPT。如果直接CALL MESSAGBOXW的指針,翻譯成機器碼是相對於當前位置的偏移,這樣寫出來的SCRIPT文件在這個程序能用,別的程序就不能用了。
機器碼 6A 00 68 78 56 34 12 68 78 56 34 12 6A 00 b8 68 3d e2 77 ff d0
我虛擬機使用的是WIN 2000 連SP1都不是。。所以我不保證你的機器仍然能正常運行這個程序。爲了能正常使用,你可以隨便找一個程序,然後BP MESSAGEBOXW,中斷之後當前的EIP就是了,把ff d0前面的68 3d e2 77換掉了就可以了。我的目的並不是介紹如何寫一個兼容性差的程序,重點是學會如何寫SCRIPT。
準備工作做好了,在看代碼之前,先解釋一些指令:
$exentry僞寄存器,數值上等於EP
$t0-$t19,WINDBG爲我們提供了20個自定義的僞寄存器
R指令能改變幾乎所有寄存器的值,包括EAX等
.dvalloc [/b] size 申請內存空間,帶/b 地址,可在指定地址申請空間,不帶則自動分配,指定地址時不一定成功,暫時的經驗指定地址越大越容易成功。
e* 地址 在指定內存中寫入數據,EW 寫入WORD,EB寫入BYTE,ED寫入DWORD
注意: EW 00400000 12345會產生溢出錯誤,同理EB 00400000 123也是錯的,正確的例子可見後面的代碼
f 地址 L長度 BYTE 在長度的地址寫入數據,你可以在示例中看到效果。同樣BYTE的位置只能是BYTE,多於8位的數據都會造成溢出錯誤。
m 源地址 L源地址長度 目的地址 複製內存區域
d* 地址 顯示地址中的數據,其中db的效果可在示例中看到。
.dvfree /d 地址 size 釋放指定地址的內存,這裏指定地址用的是/d要與 .dvalloc的/b相區別。
附件中helloworld.txt的代碼:
---------------------------------------helloworld.txt--------------------------------
g $exentry
r $t0=00ff0000; $$ $t0:源內存基址
r $t2=@$exentry; $$ $t2:目的內存基址
r $t1=@$t0; $$ $t1:當前指針
.dvalloc /b $t0 1000; $$在00b90000申請1000BYTE的內存空間
ew $t1 006A 0068
db $t0
.echo "ew指令的效果"
r $t3 = @$t1 + 3; $$PUSH DWORD的機器碼=68 DWORD
$$這裏應該輸入字符串的首址
r $t1 = @$t1 + 7; $$懶得計算,所以用$t3存起DWORD的指針
$$輸入字符串的時候一起搞定
eb $t1 68 12 34
db $t0
.echo "eb指令的效果"
r $t4 = @$t1 + 1; $$同上
r $t1 = @$t1 + 5
f $t1 l20 6A 00 b8 68 3d e2 77 ff d0
db $t0
.echo "f指令的效果"
r $t1 = @$t1 + 9
r $t5 =$t1 - $t0 + $t2
ed $t3 $t5; $$ 添加字符串的指針回去
ed $t4 $t5
f $t1 l20 'h' 'e' 'l' 'l' 'o' ' ' 'w' 'o' 'r' 'l' 'd' '!' 00 00
$$ 把字符串寫進內存中
m $t0 l30 $t2
r $ip=$t2; $$ 修改EIP
.dvfree /d $t0 1000; $$ 釋放內存
g
---------------------------------------helloworld.txt完結的分割線--------------------------------
爲了你的速度,請保證symbol path爲空,只有在你有源代碼或者系統核心的時候它的存在纔有意義,否則你會發現它會非常費時且毫無意義,尤其是你得連上網絡下載symbol資源的時候。
使用SCRIPT文件的命令有4個"$<","$$<","$><","$$><",他們的區別就是有沒有空格或者換行符的限制。使用$$><沒有任何限制,這樣可使代碼更具可讀性。要使用附件中的SCRIPT請使用$$><指令。
例如你可以用下面指令訪問在D盤下的helloworld.txt。
$$><d:\helloworld.txt
如果你把helloworld.txt放在WINDBG的安裝目錄,那麼你可以使用下面指令:
$$><helloworld.txt
運行完helloworld.txt後你會發現報錯了,因爲我的代碼覆蓋了EP。通過上面的例子,我們能用SCRIPT做什麼呢?在合適的時機,把沒加密的IAT或者其他什麼的,暫存到內存中,在脫殼完畢的時候再自動用正確的部分把加密部分覆蓋掉。
也許在未來,也會遇到這樣的需要,程序運行到某部分的時候,中斷,然後運行我們自己的代碼,運行完畢之後,我們需要返回到程序原來的流程。爲此我把上面的SCRIPT修改了一下,寫成BACKTOCODE.TXT。
--------------------------------------------backtocode.txt--------------------------------------
r $t0=00ff0000
r $t1=@$t0
r $t18=$ip ;$$ 用$t18暫存當前EIP,顯然$ip=EIP
.dvalloc /b $t0 1000
ew $t1 006A 0068
r $t3 = @$t1 + 3
r $t1 = @$t1 + 7
eb $t1 68 12 34
r $t4 = @$t1 + 1
r $t1 = @$t1 + 5
f $t1 l20 6A 00 b8 68 3d e2 77 ff d0
r $t1 = @$t1 + 9
ed $t3 $t1
ed $t4 $t1
ba e1 $t1 ;$$ 內存運行斷點,E代表運行1是長度,在E後面通常是1,斷在最後一個指令後的第一個地址
f $t1 l20 'h' 'e' 'l' 'l' 'o' ' ' 'w' 'o' 'r' 'l' 'd' '!' 00 00
r $ip=$t0 ;$$ 在分配的內存中直接運行我們自己的代碼
g
.dvfree /d $t0 1000
r $ip=$t18 ;$$ 把EIP設置爲原來的
.cls ;$$ 當前命令行窗口清屏
p ;$$ 單步步過
-------------------------------------------backtocode.txt結束-----------------------------------
爲了anti anti debug我們需要隱藏標題,雖然WINDBG本身有.wtitle指令,可是那個指令會把它後面的所有內容當作字符串輸入,而且windbg+版本號是無論怎麼改都會被默認添加到最後的。這樣上面那個SCRIPT就有用了,就差CODE了。
爲了anti anti debug,每次DEBUG的時候,我們都要做一些準備工作,用SCRIPT文件,我們可以自動完成這些操作,下面是我DEBUG之前都會用到的SCRIPT文件
-----------------------------------------------start.txt----------------------------------------
r $t0 = 00
eb 7FFDF002 $t0 ;$$去除DEBUG標誌
.pcmd -s ".if(eax<70000000 and eax>00120000){da eax;du eax}; .if(edx<70000000 and edx>00120000){da edx;du edx}"
g $exentry ;$$入口點
-------------------------------------------start.txt結束----------------------------------------
如你所見的,這有點少。沒辦法水平有限,而且寫這篇文章的時候我才勉強說是學會用,還是那句重點是教會大家用WINDBG。WINDBG的初始斷點並不是入口點所以得自己用指令讓它自動停在入口點,有的程序是有TLS表的,對着PE格式的介紹文章,寫一個SCRIPT在有TLSCALLBACK的情況下自動停在TLSCALLBACK入口是有可能的,你會在文章的最後部分得到相關指令的介紹。現在來說說START.TXT中沒有註釋的指令。
; 分號,多條命令的分隔符。從左到右運行。
下面例子中,對MESSAGEBOXW下斷後運行,中斷之後便會運行r $t0=esp+8指令
bp messageboxw;g;r $t0=esp+8
注意:如果你使用CRTL+BREAK快捷鍵在中斷之前暫停調試也會導致r $t0=esp+8的運行。
.if(條件表達式){命令} 跟C語言中的用法一樣。
.pcmd 不帶參數則顯示每條指令之後自動使用的指令。-s "命令" 設置命令。-c 清除命令。
da 以ASCII顯示內存地址,du以UNICODE顯示內存地址
在示例中,整條指令的效果表現爲,每單步一個指令,便會當EAX,EDX指向的是一個合法地址的時候,便以ASCII和UNICODE的方式分別顯示它的值,就象OD那樣。如果熟悉ASCII和UNICODE字符集的範圍還能設置僅當有效字符時才顯示結果。
標 題: 答覆
作 者: 笨笨雄
時 間: 2006-10-22 17:04
詳細信息:
在調試的過程中,有時我們希望自動化解決一些問題。例如調試使用了UnhandledExceptionFilter的SEH,我們需要自動修改ZwQueryInformationProcess的返回值。或者對於某些API的ANTI DEBUG,如果我們修改了輸入參數,同樣不能返回應該返回的值。學破解不久,一下子要找用了UnhandledExceptionFilter的軟件還真不容易,用別的API代替了。我用OD把NOTEPAD修改一下,改名爲TEST放在附件中。
流程MESSAGEBOXW,GETCOMMANDLINEW,MESSAGEBOXW輸出COMMANDLINE,最後EXITPROCESS。
現在我要做的是改變GETCOMMANDLINEW的輸出,和第二個MESSAGEBOXW的輸入。現在讓我們看看test2.txt
-------------------------------------------test2.txt-----------------------------------------------
g $exentry
r $t0=0
bp messageboxw "r $t0=$t0+1;j($t0=2)'r $t1=poi(esp+8);f $t1 l4 45;g';g"
bp getcommandlinew "g poi(esp);r $t1=eax+5;f $t1 l4 55;g"
g
------------------------------------------test2.txt完結---------------------------------------------
首先對相關指令作一些介紹
BP 地址或者函數名 "命令" 命令參數是可選的,存在的情況下,中斷的同時會先運行那些命令。
J(條件表達式)'命令1';命令2 相當於.if但是又有點不同命令2只能是1個,後面所有命令會被忽略。
POI() 返回指針的指向位置的內容。
!= 不等於
這裏用了條件中斷的方法實現,第一個條件中斷指令用$t0作爲計數器,第二次中斷的時候變修改堆棧中指針指向位置的內存區域。注意到調用API的返回地址在ESP中,直接跳出去,然後修改EAX就可以達到修改函數輸出參數的效果了。
這裏提供第二種可行的方法,並且更有可擴展性,現在看看test.txt中的代碼。
-------------------------------------------test.txt------------------------------------------------
g $exentry
r $t0=0
bp messageboxw
bp getcommandlinew
bp exitprocess
.while (eip!=77e7b0bb){
g
.if($ip=77e116cc){
r $t0=$t0+1
.if($t0=2){
r $t1=poi(esp+8)
f $t1 l4 45
}
}
.if($ip=77e7c693){
g poi(esp)
r $t1=eax+5
f $t1 l4 55
}
.elsif($ip=77e7b0bb){
.break
}
}
g
------------------------------------------test.txt完結----------------------------------------------
仍然先介紹一些指令:
.while(條件表達式){} 跟C語言中的一樣,循環結構,直到條件表示式爲真
.elsif(){} 跟前面的.if用法一樣,它的作用如字面上意思,只是小心別拼錯爲ELSEIF
.break 跟C語言中的一樣,跳出循環。
如果在條件爲真的時候不用.break跳出循環就會出錯,這點要注意。
這裏構造了一個循環結構,並且通過對比EIP的方法來識別函數,同樣地因爲我的虛擬機是WIN 2000 連SP1都不是,所以我不肯定該地址在你的機器中仍然可用。不過這裏提供了一個思路,你可以用這個方法構造一個SCRIPT來加強WINDBG的功能,例如象OD一樣中斷的時候自動顯示所有參數,並且帶上英文提示那是什麼參數。同樣地,我們可以做一個自動化分析SCRIPT,分析每個CALL中包含了什麼API,並且列出輸入和輸出參數,CALL的深度還指令數,並且自動生成報告文件,假如有人開發出這樣一個SCRIPT,調試分析將會變得容易。WINDBG裏面有個相似功能的指令。
WT 自動跟蹤並生成報告,幾乎跟我上面說的一樣。帶/l參數的時候可以設置深度,不過很多時候,我們看到一個CALL並不知道里面究竟有多深,但是我們希望得到一些關於那個CALL的詳細信息來判斷是否值得跟進。這裏有兩個問題:
1 遞歸,那這個指令不知道運行多久。
2 大量NATIVE API調用,顯然大多數情況下,我們並不關心。
比起1,2更加常見,/i參數是用來避開指定模塊的,不會用,幫助文件裏也沒提。。。。希望有大大能答我這個問題
WINDBG提供了下面3個指令用於保存分析過程進文件,通過適當的開關可以過濾一些無意義的信息,使分析過程易於觀看。
.logopen 文件路徑 帶/U參數則以UNICODE方式輸入文本。重寫整個文件,並記錄當前命令窗口在使用該指令之後的所有內容。
.logclose 文件路徑 停止記錄並關閉文件。
.logappend 文件路徑 帶/U參數則以UNICODE方式寫文件。記錄當前命令窗口在使用該指令之後的所有內容,並添加進文件。
提到了功能強化,大家都知道OD裏面有個命令是運行到RET處吧,在WINDBG中似乎沒有這樣的指令,類似的有PC,即運行到CALL。我寫了一個SCRIPT來模擬OD中的那個指令。現在我們來看看goret.txt
-------------------------------------------goret.txt------------------------------------------------
r $t0=0
.while(@$t0!=c3){
p
r $t0=by(eip)
.if(@$t0=c3){
.break
}
}
-----------------------------------------goret.txt完結----------------------------------------------
這裏是最後一個示例分析,所以除了解釋上面的指令之外也給出一些有價值的指令
not 非 and或者& 與
hi() 取高16位 or或者^ 或
low() 取低16位 xor或者| 異或
by() 取低8位 gu 步出,不知道具體原理,有時會出錯
wo() 取低16位 t 步入
mod或者% 模運算
這個SCRIPT使用了一個循環,通過EIP取得當前指令的機器碼,低8位既爲指令,然後把指令存進$t0作比較。C3是RET的機器碼,等於則跳出循環,否則一直步過。
這個示例表明,我們可以在SCRIPT裏分析每一條指令。我們可以在WINDBG中進行2次開發,動態將那些簡單使用JMP+內存指針或者寄存器作爲跳轉的亂序的程序重新排序,使花指令失效,並且實現自動清除垃圾指令,最後生成優化後的彙編代碼文件。本論壇翻譯區裏的變形多態中的關於收縮器的理論已經爲我們奠定了理論基礎。
你可能會需要用到反彙編指令
u 起始地址 l長度 L代表的不是地址長度而是指令的個數
---------------------------------後續討論,用SCRIPT把WINDBG變成脫殼機------------------------------
在準備寫這篇文章的時候,我又把DEBUGGER COMMANDS看了一次,發現了這個指令
.writemen filename range 將目標內存區域寫進文件。RANGE的格式爲 地址 l長度
我沒試過L後面是否接受寄存器作爲參數。也沒實際測試過這個指令的具體操作是怎麼樣的,無論如何,有這個可能存在。當然我們也可以申請內存區域以程序的方式來完成這個工作,不過我希望它僅用SCRIPT完成。
假如這的確可行,可以通過下面指令組合來自動尋找文件頭,當然也能確定文件大小。
$p 僞寄存器,它將返回前一次用d*指令所顯示的內存的內容。
假設00100000 01 02 03 04 05 06 07 08
我使用dd 00100000,那麼$p = 04030201
顯然我們可以通過這個方法來訪問內存。
dw 取一個WORD; dd取DWORD; dw取qword
能訪問內存也代表說我們在調試程序中插入的代碼也能跟SCRIPT通信,並且把一些SCRIPT無法完成的工作交給程序執行,然後把結果返回給SCRIPT。
假如l的參數無法通過寄存器來傳遞,只能依靠用戶按照提示進行操作,那麼我們有更簡單的方法
.imgscan 它將返回所有模塊MZ的地址和它的SIZE
----------------------------------這裏給出一些可能的疑問和解答--------------------------------------
Q:在調試SCRIPT文件的時候,我該如何知道寄存器跟內存的變化?
A:我們可以用下面的指令來觀察寄存器跟內存的變化
d* 用於顯示內存,之前已經提到就不詳細說明了
? 寄存器 顯示寄存器的值,例如
? poi(esp); ? $t0
這將先顯示ESP指向的值,然後顯示$t0的值
除了可以使用.echo命令對顯示參數作說明之前,也可以使用.printf作格式化輸出,它的用法跟C語言中的printf是一樣的
Q:我寫的SCRIPT文件出錯了,語法跟參數都沒錯,爲什麼我找不到出錯原因?
A:有的指令要注意的,BA只能在進入程序區域之後才能用。.dvalloc申請過的內存,即使用.dvfree釋放了,也無法在同樣的位置再申請,可能是BUG。
*是一個註釋命令,它後面所有的內容都會被當作字符
$$則是以分號爲結束
.restart指令跟.wtitle指令,不知道爲什麼不能放在SCRIPT中使用。
還有就是@這個標記,這個標記是告訴WINDBG後面的是一個僞寄存器而不是程序裏的某一個變量的符號。有的指令在沒有@標記的時候會報錯,例如.while括號裏的條件表達式,如果你用了僞寄存器,一定要在前面加上@否則一定報錯。此外用幫助文件裏的話來說,使用@,可以讓SCRIPT文件運行得更快,因爲在解讀這個代碼的時候不需要先搜索一次SYMBOL記錄。
Q:我能把功能模塊化然後在其他SCRIPT文件中使用嗎?
A:我已經測試過$$><指令也能在SCRIPT裏面使用
Q:我寫的SCRIPT FILE能在64位系統中用嗎?
A:如果你僅使用SCRIPT來實現功能,那麼很可能與64位兼容。儘量使用僞寄存器。
$ip,$retreg,$csp在32位系統中分別表示EIP,EAX,ESP,而在64位系統中則表示RIP,RAX,RSP也分別對應Itanuim處理器中的相關寄存器。
通過函數名獲取不同版本下的地址,可以通過下面代碼:
bp messageboxw ; $$第一個斷點,斷點ID爲0
bp getcommandlinew; $$第二個斷點,斷點ID爲1
r $t10 = $bp0; $$將第一個斷點的地址轉存$t10
r $t11 = $bp1; $$將第二個斷點的地址轉存$t11
bc *; $$清除所有斷點。
這段代碼運行之後MESSAGEBOXW的地址便存於$t10中,而$t11裏面的則是getcommandlinew的地址。這裏要說明,斷點用完要釋放,否則不好估計斷點的ID,此外在內核模式中,最多隻允許32個斷點。
$peb和$teb返回當前進程的PEB和TEB地址,這裏的翻譯區有介紹如何僅通過PEB或者TEB判斷當前操作系統類型
爲不同系統準備不同代碼
總算寫完了。。。。再廢話幾句
先來了解簡單的,得到當前訪問的文件名
先寫段C代碼,創建C:\a.txt並往文件中寫任意幾個字符,代碼如下:
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);
把以上代碼放到對話框的按鈕點擊響應事件中去。編譯鏈接得到test.Exe.
文件名爲CreateFile API的第一個參數,因而在執行到該API的入口時,esp+4即表示第一個參數的地址。故可這樣下斷:
bp kernel32!CreateFileW "r $t1=poi(esp+4);.echo;.printf\"FileName:%mu\",$t1;.echo;g"
$t0~$t19爲僞寄存器,可用來存儲臨時值,poi表示取地址的值,
也可將腳本保存爲文件,然後在windbg中輸入: $$><腳本文件路徑 來運行。
我把以上腳本保存爲 ”C:\script.txt”
用windbg打開以上代碼編譯得到的test.exe,
Ctrl+Break中斷windbg,然後下斷,即輸入:$$><C:\script.txt,再輸入g,讓進程運行起來,
點擊按鈕,果其然,得到文件名了,見下圖,
23985
訪問的文件獲取了,那如何在訪問指定文件時中斷下來呢?字符串比較的腳本如何寫呀?
上網查資料吧,不大一會,發現了$scmp/$sicmp/$spat是用來字符串操作的。$spat正合我意呀。
$spat("string1”, "pattern”):判斷參數1指定的字符串是否符合參數2指定的模式。模式字符串中可以包含?、*、#等特殊符號,WinDBG幫助文件中String Wildcard Syntax一節包含了詳細的說明;
這樣摸索了一番,寫了如下腳本:
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
}
}"
以上腳本,不復雜,實現當訪問文件名類似“a.txt”時,windbg中斷執行。
對腳本解析幾個要點:
1. 使用僞寄存器,更快速的方法是在$前加上一個@符號。這樣,WinDBG就知道@後面是一個僞寄存器,不需要搜索其他符號;
2. r $t1=poi(esp+4),poi(esp+4)取地址的值,並賦給僞寄存器$t1 ;
3. as /mu $FileName $t1 ,定義$t1 所指地址一個別名$FileName,用來在下面的$spat中使用。別名會在腳本加載時被解析程序替換一次。爲何要用別名?你不用試試就知道了,直接用$t1不行,windbg提示你語法錯誤;
4. .block是啥東西,看windbg幫助就知道了。代碼塊,如果需要每次運行進入替換,請用.block括起來;我這裏有個別名,需要每次替換,所以用了個.block括起來;
5. $spat爲模式匹配函數,其他類似函數$scmp/$sicmp。
6. ${$FileName}、${/v:$FileName}這呢?聽我說來,${ aliase} 明確的指出了, 大括號 {} 內的變量名是可以被替換的,即使 aliase 和其它文本相連。如果要求 ${} 這個別名不被替換, 即不被解析程序替換成其他值, 只保留它當前的字面值.如下面的ad ${/v:$FileName},刪除別名,此時用/v 選項來了阻止對該別名的替換, 保留它原來的字面值;
7. 別名用完記得要刪除;刪除方法用ad命令。
試試看看結果,在訪問a.txt時斷下來了。
23986
如果我要在往該文件寫數據時斷下來,如何設斷?直接在writeFile下斷?但不知道當前訪問的是哪個文件呀?在腳本里,通過文件句柄能得到相應的文件名嗎?我反正還不知道,如果你知道請一定不要忘了告我呀?以下爲我的腳本:
$$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)
{
$$往該文件寫數據時下斷
.printf \"File Handle:%08x\",$t1
.echo
bp kernel32!WriteFile \"
r @$t2=poi(esp+4)
.if(@$t2!=@$t1) {gc}
\"
}
ad ${/v:$FileName}
gc
}
.else
{
.echo No Match...
ad ${/v:$FileName}
gc
}
}
"
運行結果截圖:
23987
WINDBG看起來很難用,是因爲用的人不多。
即使沒有插件功能,WINDBG SCRIPT的功能也已經很強大了。
如果大家都來做SCRIPT,調試分析難度會降低很多,新手也可以通過閱讀SCRIPT FILE來學習。搜索引擎使用得好的確可以學到很多,可惜這跟作者的表達和使用引擎者的表達有關,很可能相同的內容,因爲表達方式不同就查不到了。就象我學校的圖書館,在電腦搜索逆向工程是什麼都找不到的,但是搜索加密解密,卻看到好幾本書。
OD雖然好,始終是RING3的,SOFTICE似乎也已經停止開發了。希望大家都能加入WINDBG的行列
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.