您好,登錄后才能下訂單哦!
驅動文件*.sys一般在目錄:
C:\Windows\System32\drivers
pc機上每個東西都有驅動,鍵盤、鼠標、顯示器、cpu等等。
沒有驅動,這些東西都不能運作,就是一堆廢品。
談一談windows驅動調試。
使用windbg調試。
一般安裝ddk后,就安裝了windbg,在目錄
C:\Program Files (x86)\Windows Kits\8.1\Debuggers\x64里就有了windbg調試工具。
windbg命令分為標準命令,元命令和擴展命令。
準命令提供最基本的調試功能,不區分大小寫。如:bp g dt dv k等
元命令提供標準命令沒有提供的功能,也內建在調試引擎中,以.開頭。如.sympath .reload等;
擴展命令用于擴展某一方面的調試功能,實現在動態加載的擴展模塊中,以!開頭。如!analyze等;
進入調試狀態時,直接回車可重復執行上一條命令;按上下方向鍵可以瀏覽和選擇以前輸入過的命令;
神奇的Tab鍵,進行命令補全;ESC清除當前命令輸入框中的文本;
使用;作為分隔符,可以在同一行輸入多條命令;
當命令提示符顯示*BUSY*時,即使命令輸入框可以輸入命令,但輸入的命令不會立即被執行,要等windbg空閑時才能執行;
可使用Ctrl + Break來終止一個長時間未完成的命令;
一次可以執行多條命令,命令間用分號;分隔 【如:bp main;bp `test.cpp:120`】,一次打2個斷點;
為了保證windbg流暢運行,在調試時,盡量不要開啟Watch、Locals、Registers、Call Stack、Processes and Threads窗口,直接用command來獲取信息;
幫助:
? // 打印出所有標準命令
.help // 打印出所有元命令
.hh // 打開windbg的chm幫助文件
.hh bp // 打開windbg的chm幫助文件bp命令介紹頁
command /? // 打印命令command具體參數用法
* // 注釋整行
$$ // 注釋(遇到分號結束)
.sympath // 查看當前符號查找路徑
.sympath c:\symbols // 將符號查找路徑設為:c:\symbols
.sympath+ c:\symbols // 將c:\symbols添加到符號查找路徑集合中
.symfix // 將符號查找路徑設為:SRV*WinDbg安裝目錄\Sym*http://msdl.microsoft.com/download/symbols
.symfix f:\symbols // 將符號查找路徑設為:SRV*f:\symbols*http://msdl.microsoft.com/download/symbols
.symfix+ f:\symbols // 將SRV*f:\symbols*http://msdl.microsoft.com/download/symbols添加到符號查找路徑集合中
.srcpath // 查看當前源文件查找路徑
.srcpath f:\src // 將源文件查找路徑設為:f:\src
.srcpath+ f:\src // 將f:\src添加到源文件查找路徑集合中
.exepath // 查看可執行文件查找路徑
.exepath f:\bin // 將可執行文件查找路徑設為:f:\bin
.exepath+ f:\bin // 將f:\bin添加到可執行文件查找路徑集合中
.effmach // 查看當前調試mode:x86、x64等
.load wow64exts // [!load wow64exts] 加載wow64exts.dll模塊 注:!sw就是wow64exts中的命令
.unload wow64exts // [!unload wow64exts] 卸載wow64exts.dll模塊
!sw // [!wow64exts.sw] 在多個mode:x86、x64上進行循環切換 注:如果win32程序在x64的mode下,會看到地址是64位的
!k // [!wow64exts.k] 打印32位、64位堆棧
!k 5 // [!wow64exts.k 5] 打印32位、64位堆棧,棧幀個數為5
!info // [!wow64exts.info] 輸出wow64相關的PEB、TEB和TLS基本信息
!r // [!wow64exts.r] 輸出處理器當前上下文信息
!r dumpTest!main // [!wow64exts.r dumpTest!main] 輸出main函數地址的上下文信息
符號加載與查看
除了使用ld和.reload命令直接加載符號文件,某些使用符號的命令也可以觸發調試器來加載符號,如:棧回溯命令(k*)和反匯編命令(u)等。
值得說明的是,windbg缺省使用的是懶惰式符號加載策略,當它收到模塊加載事件時,它通常是不會加載符號的,符號狀態顯示為deferred(延遲加載)。
.symopt // 顯示當前所有符號選項
.symopt+ flags // 添加符號選項
.symopt- flags // 刪除符號選項
!sym noisy // 激活詳細符號加載(noisy symbol loading)顯示
!sym quiet // 禁止詳細符號加載顯示
ld * // 為所有模塊加載符號
ld kernel32 // 加載kernel32.dll的符號
.reload // 為所有已加載模塊載入符號信息
.reload /i // 重新加載不匹配符號的模塊【dmp文件沒有對應的pdb時使用】
.reload /i TGame.exe // 重新加載不匹配符號的TGame.exe
.reload /f /v // f:強制立即模式(不允許延遲載入) v:詳細模式
.reload /f @"c:\windows\System32\verifier.dll" // 為指定模塊加載符號信息
.reload /f TGame.exe // 為TGame.exe加載符號信息
.chain // 顯示已經加載進來的模塊
x *! // 列出所有模塊對應的符號信息
lm // 列出所有模塊(加載和未加載)對應的符號信息
lmv // 列出所有模塊(加載和未加載)對應的符號信息
lmvm ntdll // 查看ntdll.dll的詳細信息(注意exe、dll等都不要帶后綴名)
x ConsoleTest!* // 列出ConsoleTest模塊中的所有符號
x ConsoleTest!add* // 列出ConsoleTest模塊中的所有add開頭的符號
x /t /v ConsoleTest!* // 帶數據類型、符號類型和大小信息,列出ConsoleTest模塊中的所有符號
x kernel32!*LoadLib* // 列出kernel32模塊中所有含LoadLib字樣的符號
#進程
| // 列出調試進程
|* // 列出調試進程
|N // 參看序數為N的調試進程
|Ns // 切換序數為N的進程為當前調試進程
#線程
~ // 列出線程
~* // 所有線程
~* k // 所有線程堆棧信息
~* r // 所有線程寄存器信息
~. // 查看當前線程
~0s // 查看主線程
~# // 查看導致當前事件或異常的線程
~N // 查看序數為N的線程
~~[n] // 查看線程ID為n的線程
~Ns // 切換序數為N的線程為當前調試線程
~N f // 凍結序數為N的線程
~N u // 解凍序數為N的線程
~N n // Suspend序數為N的線程
~N m // Resume序數為N的線程
!runaway // 顯示所有線程的CPU消耗
#斷點
bl // 列出所有斷點
bc * // 清除所有斷點
bc 1 // 清除1號斷點
bc 1 2 5 // 清除1號、2號、5號斷點
be * // 啟用所有斷點
be 1 // 啟用1號斷點
be 1 2 5 // 啟用1號、2號、5號斷點
bd * // 禁用所有斷點
bd 1 // 禁用1號斷點
bd 1 2 5 // 禁用1號、2號、5號斷點
bp 7c801b00 // 在7c801b00地址處放置一個斷點
bp `ConsoleTest.cpp:36` // 在ConsoleTest.cpp的36行處放置一個斷點
bp main // 在main函數的起始處放置一個斷點
bp CSecondLoader::CSecondLoader // 在CSecondLoader的構造函數處放置一個斷點
bp TestCommon! CTest::add // 在TestCommon.dll的Test.cpp文件的CTest::add()函數起始處放置一個斷點
bp `ConsoleTest.cpp:40` "j (poi(pVar)>5) ''; 'g'" // j為條件表示式:條件斷點 pVar指針指向的值>5,執行空語句(;),斷住 否則繼續執行
---------------------------------
---------------------------------
x表示的一個地址
hi(x) 高16 bits
low(x) 低16 bits
by(x) 返回第一個byte
wo(x) 返回第一個word
dwo(x) 返回第一個dword
qwo(x) 返回第一個4 word(Quad-word)
poi(x) 返回第一個指針所指向的值
---------------------------------
bp advapi32!RegOpenKeyExA ".echo;.printf\"RegOpenKeyExW(%p,\\\"%ma\\\",%N,%N,%p) returned: \", dwo(esp+4), poi(esp+8), dwo(esp+c), dwo(esp+10), dwo(esp+14);gu;.printf\"%N\",eax;.echo;g" // 不斷住進程情況下,打印所有的RegOpenKeyExA調用(打開注冊表鍵值)
bu // 保存斷點,其用法和bp一樣
bm add_* // 匹配add_開頭的函數,并在這些函數起始處都打上斷點
ba w4 0483dfe0 // 當對0483dfe0地址寫操作時停下
// ba [r|w|e] [Size] Addr [r=read/write, w=write, e=execute], Size=[1|2|4 bytes]
#調試執行控制
g // Go(F5)
gH // 執行gH命令強制讓調試器返回已經處理了這個異常。【Go with Exception Handled】
// 系統收到這個回復后會停止分發異常(因為調試器聲稱已經處理了異常),恢復調試目標繼續執行,
// 但由于異常條件仍在,所以還會產生異常,于是再次分發,WinDBG再次中斷到命令模式。
gN // 【Go with Exception Not Handled】
// 執行gN命令強制讓調試器返回沒有處理了這個異常,那么系統會進一步分發該異常,
// 如果沒有其他調試器也不處理,最后系統會彈出程序終止對話框。
gu // 執行到當前函數完成時停下 【Go Up】
Ctrl+Break // 暫停正在運行的程序
p // 單步執行(F10) 【Step】
p 2 // 2為步進數目
pc // 執行到下一個函數調用處停下 【Step to Next Call】
pa 7c801b0b // 執行到7c801b0b地址處停下 【Step to Adress】
t // Step into(F11) 【Trace】
tc // 執行到下一個進入點處停下 【Trace to Next Call】
ta 7c801b12 // 執行到7c801b12地址處停下 【Trace to Adress】
bp advapi32!RegOpenKeyExA ".echo;.printf\"RegOpenKeyExW(%p,\\\"%ma\\\",%N,%N,%p) returned: \", dwo(esp+4), poi(esp+8), dwo(esp+c), dwo(esp+10), dwo(esp+14);gu;.printf\"%N\",eax;.echo;g" // 不斷住進程情況下,打印所有的RegOpenKeyExA調用(打開注冊表鍵值)
bu // 保存斷點,其用法和bp一樣
bm add_* // 匹配add_開頭的函數,并在這些函數起始處都打上斷點
ba w4 0483dfe0 // 當對0483dfe0地址寫操作時停下
// ba [r|w|e] [Size] Addr [r=read/write, w=write, e=execute], Size=[1|2|4 bytes]
#調試執行控制
g // Go(F5)
gH // 執行gH命令強制讓調試器返回已經處理了這個異常。【Go with Exception Handled】
// 系統收到這個回復后會停止分發異常(因為調試器聲稱已經處理了異常),恢復調試目標繼續執行,
// 但由于異常條件仍在,所以還會產生異常,于是再次分發,WinDBG再次中斷到命令模式。
gN // 【Go with Exception Not Handled】
// 執行gN命令強制讓調試器返回沒有處理了這個異常,那么系統會進一步分發該異常,
// 如果沒有其他調試器也不處理,最后系統會彈出程序終止對話框。
gu // 執行到當前函數完成時停下 【Go Up】
Ctrl+Break // 暫停正在運行的程序
p // 單步執行(F10) 【Step】
p 2 // 2為步進數目
pc // 執行到下一個函數調用處停下 【Step to Next Call】
pa 7c801b0b // 執行到7c801b0b地址處停下 【Step to Adress】
t // Step into(F11) 【Trace】
tc // 執行到下一個進入點處停下 【Trace to Next Call】
ta 7c801b12 // 執行到7c801b12地址處停下 【Trace to Adress】
# 查看句柄
!handle // 查看所有句柄的ID
!handle 000007f8 1 // 查看ID為000007f8的句柄的類型
!handle 000007f8 4 // 查看ID為000007f8的句柄的名稱
!handle 0 5 // 查看所有句柄的類型和名稱
查看變量
=== 0n(十進制) 0x(十六進制) 0t(8進制) 0y(2進制) 可以使用n [8|10|16]命令來修改數值進制表示方式(輸入n可查看當前進制,默認為16進制)===
-- VC6.0的Link選項需要將/pdbtype:sept改為/pdbtype:con, 否則生成的pdb文件中將不包含如自定義結構體,類等信息
dt nRet // 查看局部變量nRet的類型與值(函數參數變量請用dv命令)
dt myApp!g_app // 表示顯示myApp進程里全局變量g_app的內存布局(注:vc6見上述說明)
dt WindbgTest!CTest // 查看模塊WindbgTest的CTest的內存布局(注:vc6見上述說明)
dt WindbgTest!CTest 0x0041f8d4 // 將0x0041f8d4地址處內容按照模塊WindbgTest的CTest的內存布局來解析
dt this // 查看this指針的類型及成員變量(注:vc6見上述說明)
dt -b this // 查看this指針的類型及成員變量,如果某一成員變量為結構體,則把其結構成員也一一打印出來
dt _PEB @$PEB // 查看PEB(process's environment block)內存結構
?? this->m_nPen // 查看成員變量的值(注:vc6見上述說明)
?? this // 查看this指針中的成員變量(注:vc6見上述說明)
? nCount // 顯示局部變量nCount的地址(前面4198608為10進制表示地址,004010d0為16進制表示地址) 形如:Evaluate expression: 4198608 = 004010d0
? HeapTest!CTest::Add // 顯示HeapTest模塊中CTest類中的Add函數地址
dv // 顯示當前函數內所有局部變量,函數參數的值
dv n* // 顯示當前函數內n開頭的所有局部變量,函數參數的值
dv nCount // 查看局部變量nCount的值
dv a // 查看函數參數變量a的值
dv /t /i /V /a|/n|/z
/*****************************************
更加詳細地顯示當前函數內所有局部變量,函數參數信息
i = type (local, global, parameter)
t = data type
V = memory address or register location
-----------------------
a = sort by Addr, n = sort by name, z = sort by size
*****************************************/
x // 用法和dv命令一致,顯示當前函數內所有局部變量,函數參數的地址與值
調用堆棧
k // 顯示當前調用堆棧
kn // 帶棧編號顯示當前調用堆棧
kb // 打印出前3個函數參數的當前調用堆棧
02a9ffec 00000000 01e511f9 0174c570 00000000 kernel32!BaseThreadStart+0x37
----------------------------------------------
kernel32!BaseThreadStart+0x37 這個是函數地址。
01e511f9 0174c570 00000000 這是前三個參數。注:如果是成員函數,this指針通過ecx來傳遞
02a9ffec 00000000是 ebp 和 返回地址。
kb 5 // 只顯示最上的5層調用堆棧
kv // 在kb的基礎上增加了函數調用約定等信息
kp // 顯示每一層函數調用的完整參數,包括參數類型、名字、取值(必須是完整符號的情況下,private symbols);注意:若程序被優化,這些值不一定對
kd // 打印堆棧的地址
.frame // 顯示當前棧幀
.frame n // 設置編號n的棧幀為當前棧幀
.frame /r n // 設置編號n的棧幀為當前棧幀 并顯示寄存器變量
!uniqstack // 顯示所有線程的調用堆棧
調用堆棧
k // 顯示當前調用堆棧
kn // 帶棧編號顯示當前調用堆棧
kb // 打印出前3個函數參數的當前調用堆棧
02a9ffec 00000000 01e511f9 0174c570 00000000 kernel32!BaseThreadStart+0x37
----------------------------------------------
kernel32!BaseThreadStart+0x37 這個是函數地址。
01e511f9 0174c570 00000000 這是前三個參數。注:如果是成員函數,this指針通過ecx來傳遞
02a9ffec 00000000是 ebp 和 返回地址。
kb 5 // 只顯示最上的5層調用堆棧
kv // 在kb的基礎上增加了函數調用約定等信息
kp // 顯示每一層函數調用的完整參數,包括參數類型、名字、取值(必須是完整符號的情況下,private symbols);注意:若程序被優化,這些值不一定對
kd // 打印堆棧的地址
.frame // 顯示當前棧幀
.frame n // 設置編號n的棧幀為當前棧幀
.frame /r n // 設置編號n的棧幀為當前棧幀 并顯示寄存器變量
!uniqstack // 顯示所有線程的調用堆棧
寄存器
r // 顯示所有寄存器信息及發生core所在的指令
r eax, edx // 顯示eax,edx寄存器信息
r eax=5, edx=6 // 對寄存器eax賦值為5,edx賦值為6
!address 7ffd8000 // 查看7ffd8000地址處內存頁屬性
dd /c 5 7c801e02 // 從7c801e02內存處開始以dword為單位顯示內存(寬度為:5)【默認顯示128字節長度的內容】
dd /c 5 7c801e02 L8 // 從7c801e02內存處開始以dword為單位顯示內存(寬度為:5)【顯示8個dword】
da /c 100 7c80ff03 // 從7c80ff03內存處開始顯示Ascii字符串(寬度為:100)
du /c 100 7c8022f5 // 從7c8022f5內存處開始顯示Unicode字符串(寬度為:100)
/*****************************************
d[a| u| b| w| W| d| c| q| f| D] [/c 列數] [地址]
a = ascii chars
u = Unicode chars
b = byte + ascii
w = word (2b)
W = word (2b) + ascii
d = dword (4b)
c = dword (4b) + ascii
q = qword (8b)
f = floating point (single precision - 4b)
D = floating point (double precision - 8b)
*****************************************/
dyb /c 3 7c801e02 // 從7c801e02內存處開始,顯示byte及二進制(寬度為:3)
dyb /c 3 7c801e02 // 從7c801e02內存處開始,顯示byte及二進制(寬度為:3)
/*****************************************
dy[b | d] .. // b = binary+byte d = binary+dword
*****************************************/
s -w 522e0000 L0x100 0x1212 0x2212 0x1234 // 表示在起始地址522e0000之后的0x100個單位內搜索0x1212 0x2212 0x1234系列的起始地址
s -u 522e0000 527d1000 "web" //表示在522e0000 和527d1000之間搜索Unicode 字符串”web”
ea 0x445634 "abc" // 表示在0x445634地址寫入Ascii字符串abc, 不包含結束符0
eza 0x445634 "abc" // 表示在0x445634地址寫入Ascii字符串abc, 包含結束符0
eu 0x445634 "abc" // 表示在0x445634地址寫入Unicode字符串abc, 不包含結束符0
ezu 0x445634 "abc" // 表示在0x445634地址寫入Unicode字符串abc, 包含結束符0
ed nCounter 80 // 將變量nCounter的值修改為80(注:80為10進制還是16進制,還是其他,取決于當前進制)
!heap -s// 顯示進程堆的個數(每一項是一個堆,也就是_HEAP結構指針,對應的API是HeapCreate)
dt _HEAP 00140000 // 選取一個堆的地址,打印該堆的內存結構
!heap -a 00140000 // 選取一個堆的地址,打印該堆的信息,比上面打印內存命令更詳細直觀
設置事件發生時windbg行為
設置事件發生時windbg行為
sx // 顯示windbg遇到每個異常和事件時的行為
sxr // 將所有異常和事件過濾器的狀態重設為默認值
sxe ld // 當加載模塊時,立即中斷(Break)到調試器中(第一次處理機會)
sxe ud // 當卸載模塊時,windbg不會在第
一次處理機會時中斷(雖然會顯示信息)。如果其他錯誤處理器沒有處理掉該異常,執行會停止下來并中斷(Break)到windbg中(第二次處理機會)
sxn et // 當線程退出時,windbg會打印出一條消息
sxi ct // 當線程創建時,windbg不中斷也不打印消息
dump輸出
.dump /ma "d:\mydmpfile.dmp" // 將當前調試進程輸出Dump文件
其他元命令
.tlist // 顯示所有進程
.cls // 清除屏幕
.logopen c:\1.log // 將command內容輸出到c:\1.log文件中
其他擴展命令
!analyze -v // 詳細顯示當前異常信息
!peb // 格式化輸出PEB信息(process's environment block)
!gle // 打印當前線程最近的錯誤信息LastError
!gle -all // 打印所有線程的最近的錯誤信息
!error 897// 顯示錯誤碼為897的詳細描述信息
中文在線幫助:
點擊打開鏈接
windbg cmd:
WinDbg 命令手冊
http://www.cnblogs.com/gaochundong/p/windbg_cheat_sheet.html
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。