日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

network怎么断点调试_Windows 网络编程:调试 API

發布時間:2023/12/10 windows 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 network怎么断点调试_Windows 网络编程:调试 API 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一次性進群,長期免費索取教程,沒有付費教程。

教程列表見微信公眾號底部菜單

進微信群回復公眾號:微信群;QQ群:460500587


微信公眾號:計算機與網絡安全

ID:Computer-network

在Windows中有這么一些API函數是專門用來進行調試的,這些函數被稱作為Debug API,或者是調試API。利用這些函數可以進行調試器的開發,調試器通過創建有調試關系的父子進程來進行調試,被調試進程的底層信息、即時的寄存器、指令等信息都可以被獲取,進而用來分析。

OllyDbg調試器的功能非常得強大,雖然有眾多的功能,但是其基礎的實現就是依賴于調試API。調試API函數的個數雖然不多,但是合理的使用會產生非常大的作用。調試器依賴于調試事件,調試事件有著非常復雜的結構體,調試器有著固定的流程,由于實時需要等待調試事件的發生,其過程是一個調試循環體,非常類似SDK開發程序中的消息循環。無論是調試事件,還是調試循環,對于調試或者說調試器來說,其最根本、最核心的部分是中斷,或者說其最核心的部分是可以捕獲中斷。

一、3種斷點方法

產生中斷的方法是設置斷點,常見的產生中斷的斷點方法有3種,一種是中斷斷點,一種是內存斷點,還有一種是硬件斷點。下面分別來介紹這3種斷點的不同。

中斷斷點,這里通常指的是匯編語言中的int3指令,CPU執行該指令時會產生一個斷點,因此也常稱之為INT3斷點。現在演示一下如何使用int 3來產生一個斷點。代碼如下:

在代碼中使用了__asm,在__asm后面可以使用匯編指令,如果想添加一段匯編指令,方法是__asm{}這樣的。通過__asm可以在C語言中進行內嵌匯編語言。在__asm后面直接使用的是int3指令,這樣會產生一個異常,稱為斷點中斷異常。對這段簡單的代碼進行編譯連接,并且運行。運行后出現了錯誤對話框,如圖1所示。

圖1? 異常對話框

這個對話框可能常常見到,而且見到以后多半很郁悶,通常情況是直接單擊“不發送”按鈕,然后關閉這個對話框。在這里,這個異常是通過int3導致的,不要忙著關掉它。通常在寫自己的軟件時如果出現這樣的錯誤,應該去尋找一些更多的幫助信息來修正錯誤。單擊“請單擊此處”鏈接,出現如圖2所示的對話框。

圖2“異常基本信息”對話框

彈出“異常基本信息”對話框,因為這個對話框給出的信息實在太少了,繼續單擊“要查看關于錯誤報告的技術信息”后面的“單擊此處”鏈接,打開如圖3所示的對話框。

圖3“錯誤報告內容”對話框

通常情況下,在這個報告中只關心兩個內容,一個內容是Code,另一個內容是Address。在圖3中,Code后面的值為0x80000003,在Address后面的值為0x0000000000401028。Code的值為產生異常的異常代碼,Address是產生異常的地址。在Winnt.h中定義了關于Code的值,在這里0x80000003的定義為STATUS_BREAKPOINT,也就是斷點中斷。在Winnt.h中的定義為:

這里給的Address可以看出是一個VA(虛擬地址),用OD打開這個程序,直接按F9鍵運行,如圖4、圖5所示。

圖4? 在OD中運行后被斷下

圖5? OD狀態欄提示

從圖4所示的地方看到,程序執行停在了00401029的位置處。從圖5所示的地方可以看到,INT3命令位于00401028的位置處。再看一下圖3中Address后面的值,值為00401028。這也就證明了在系統的錯誤報告中可以給出正確的出錯地址的。這樣在以后寫程序的過程中可以很容易地定位到自己程序中有錯誤的位置。

回到中斷斷點的話題上,中斷斷點是由int3產生的,那么要如何通過調試器(調試進程)在被調試進程中設置中斷斷點呢?看圖4中00401028地址處,在地址值的后面,在反匯編代碼的前面,中間那一列的內容是匯編指令對應的機器碼。可以看出,INT3對應的機器碼是0xCC。如果想通過調試器在被調試進程中設置INT3斷點的話,那么只需要把要中斷的位置的機器碼改為0xCC即可,當調試器捕獲到該斷點異常時,修改為原來的值即可。

內存斷點的方法同樣是通過異常來產生的。在Win32平臺下,內存是按頁進行劃分的,每頁的大小為4KB。每一頁內存都有其各自的內存屬性,常見的內存屬性有只讀、可讀寫、可執行等。內存斷點的原理就是通過對內存屬性的修改,而導致本該進行的操作無法進行,這樣便會引發異常。

在OD中關于內存斷點有兩種,一種是內存訪問,另外一種是內存寫入。用OD隨便打開一個應用程序,在其“轉存窗口”(或者叫“數據窗口”)中隨便選中一些數據點后單擊右鍵,在彈出的菜單中選擇“斷點”命令,在“斷點”子命令下會看到“內存訪問”和“內存寫入”兩種斷點,如圖6所示。

圖6? 內存斷點類型

下面通過簡單例子來看一下如何產生一個內存訪問異常,代碼如下:

在這個程序中,使用了VirtualProtect()函數,該函數與VirtualProtectEx()函數類似,不過VirtualProtect()是用來修改當前進程的內存屬性的。

對這個程序編譯連接,并運行起來。熟悉的出錯界面又出現在眼前,如圖7所示。

圖7“異常基本信息”對話框

按照前面介紹的步驟打開“錯誤報告內容”對話框,如圖8所示。

圖8“錯誤報告內容”對話框

按照上面的分析方法來看一下Code和Address這兩個值。Code后面的值為0xC0000005,這個值在Winnt.h中的定義如下:

這個值的意義表示訪問違例。在Address后面的值為0x0000000000402fa3,這個值是地址,但是這里的地址根據程序來考慮,值是用malloc()函數申請的,用于保存數據的堆地址,而不是用來保存代碼的地址。這個地址就不進行測試了,因為是動態申請,很可能每次不同,因此大家了解就可以了。

硬件斷點是有硬件進行支持的。在OD中使用硬件斷點的方法類似于內存斷點,同樣是在右鍵菜單中進行設置。由于是由硬件支持的,因此只能設置4個。

二、調試API函數及相關結構體

調試器的根本是依靠中斷,其核心也是中斷。前面也演示了兩個產生中斷異常的例子。下面的內容是介紹調試API函數,及其相關的調試結構體。調試API函數的數量非常少,但是其結構體是非常少有的較為復雜的,雖然說是復雜,其實只是嵌套的層級比較多,只要了解了較為常見的,剩下的可以自己對照MSDN進行學習。在介紹完調試API函數及其結構體后,再來簡單演示一下,如何通過調試API捕獲INT3斷點和內存斷點。

創建調試關系

既然是調試,那么必然存在調試和被調試。調試和被調試的這種調試關系是如何建立起來的,是我們首先要了解的內容。要使調試和被調試創建調試關系,那么就會用到兩個函數中的一個,這兩個函數分別是CreateProcess()和DebugActiveProcess()。如何使用CreateProcess()函數來建立一個需要被調試的進程呢?來回顧一下CreateProcess()函數。CreateProcess()函數的定義如下:

現在要做的是創建一個被調試進程。在CreateProcess()函數中,有一個dwCreationFlags的參數,該參數的取值中有兩個重要的常量,分別為DEBUG_PROCESS和DEBUG_ONLY_THIS_PROCESS。DEBUG_PROCESS的作用就是被創建的進程處于調試狀態,如果一同指定了DEBUG_ONLY_THIS_PROCESS的話,那么就只能調試被創建的進程,而不能調試被調試進程創建出來的進程。只要在使用CreateProcess()函數時指定這兩個常量即可。

除了CreateProcess()函數以外,還有一種創建調試關系的方法,該方法用的函數如下:

這個函數的功能是附加到一個進程上。該函數的參數就一個,該參數指定了被調試進程的進程ID號。從函數名與函數參數可以看出來,這個函數是和一個已經被創建的進程來建立調試關系的,跟CreateProcess()的方法是不一樣的。在OD中也同樣有這個功能,打開OD,選擇菜單中的“文件”->“掛接”命令,就出現“選擇要掛接的進程”窗口,如圖9所示。

圖9“選擇要掛接到的進程”的窗口

OD的這個功能就是通過DebugActiveProcess()函數來完成的。

調試器與被調試的目標進程可以通過前兩個函數建立調試關系,但是如何使調試器與被調試的目標進程斷開調試關系呢?有一個很簡單的方法,關閉調試器進程,這樣調試器進程與被調試的目標進程會同時結束。也可以關閉被調試的目標進程,這樣也可以達到斷開調試關系。那如何讓調試器與被調試的目標進程斷開調試關系,又保持被調試目標進程的運行呢?這里介紹一個函數,函數名為DebugActiveProcessStop(),其定義如下:

該函數只有一個參數,就是被調試進程的進程ID號。使用該函數可以在不影響調試器進程和被調試進程的正常運行而將兩者的關系進行解除。

三、判斷是否處于被調試狀態

很多程序都要檢測自己是否處于被調試狀態,比如游戲、病毒,或者加殼后的程序。游戲為了防止被做出外掛而進行反調試,病毒為了給反病毒工程師增加分析難度而反調試,加殼程序是專門用來保護軟件的,當然也會有反調試的功能(該功能僅限于加密殼,壓縮殼是沒有反調試功能的)。

下面不是要介紹反調試,而是要介紹一個簡單的函數,這個函數是判斷自身是否處于被調試狀態,函數名為IsDebuggerPresent(),函數的定義如下:

該函數沒有參數,根據返回值來判斷是否處于被調試狀態。這個函數也可以用來進行反調試。不過由于這個函數的實現過于簡單,很容易就能夠被分析者突破,因此現在也沒有軟件再使用該函數來用作反調試了。

下面通過一個簡單的例子來演示一下IsDebuggerPresent()函數的使用。代碼如下:

這個例子用來檢測是否被調試。在進入主函數后,直接調用IsDebuggerPresent()函數,用來判斷是否被調試器創建。在自定義線程函數中,一直循環檢測是否被附加。只要發現自身處于被調試狀態,那么就在控制臺中進行輸出提示。

現在用OD對這個程序進行測試。首先用OD直接打開這個程序并按F9鍵運行,如圖10所示。

圖10? 主函數檢測到調試器

按下F9鍵啟動以后,控制臺中輸出“mian func checked the debuggee”,也就是發現了調試器。

再測試一下檢測OD附加的效果。先運行這個程序,然后用OD去掛接它,看其提示,如圖11所示。

圖11? 線程函數檢測到調試器

控制臺中輸出“thread func checked the debuggee”。可以看出用OD進行附加也能夠檢測到自身處于被調試狀態。

進行該測試時請選用原版OD。由于該檢測是否處于被調試方法過于簡單,因此任何其他修改版的OD都可以將其突破,從而使測試失敗。

四、斷點異常函數

有時為了調試方便可能會在自己的代碼中插入__asm int 3,這樣當程序運行到這里時會產生一個斷點,就可以用調試器進行調試了。其實微軟提供了一個函數,使用該函數可以直接讓程序運行到某處的時候產生INT3斷點,該函數的定義如下:

修改一下前面的程序,把__asm int 3替換為DebugBreak(),編譯連接并運行看一下。同樣會因產生異常而出現“異常基本信息”對話框,查看它的“錯誤報告內容”,如圖12所示。

圖12“錯誤報告內容”對話框

看一下Code的后面的值,看到值為0x80000003就應該知道是EXCEPTION_BREAKPOINT。再看Address后面的值,值為0x000000007c92120e,從這個地址可以看出,該值在系統的DLL文件中,因為調用的是系統提供的函數。

五、調試事件

調試器在調試程序的過程中,是通過不斷地下斷點來完成的,而斷點的產生在前面的內容中提到過一部分。通過前面介紹的INT3斷點和內存斷點可以得知,調試器是在捕獲目標進程產生的異常從而作出響應。當然,對于介紹的斷點來說是這樣的,不過對于調試器來說,除了對異常作出響應以外,還會對其他的一些事件作出響應,異常只是所有調試能進行響應事件的一部分。

調試器的工作主要是依賴調試事件,調試事件在系統中被定義為一個結構體,也是到目前為止要接觸的最為復雜的一個結構體,因為這個結構體的嵌套關系很多。這個結構體的定義如下:

這個結構體非常重要,我們有必要詳細地介紹一下。

(1)dwDebugEventCode:該字段指定了調試事件的類型編碼。在調試的過程中可能產生的調試事件非常多,因此要根據不同的類型碼進行不同的響應處理。常見的調試事件如圖13所示。

圖13? dwDebugEventCode取值

(2)dwProcessId:該字段指明了引發調試事件的進程ID號。

(3)dwThreadId:該字段指明了引發調試事件的線程ID號。

(4)u:該字段是一個聯合體,該聯合體的取值由dwDebugEventCode指定。在該聯合體中包含了很多個結構體,包括EXCEPTION_DEBUG_INFO、CREATE_THREAD_DEBUG_INFO、CREATE_PROCESS_DEBUG_INFO、EXIT_THREAD_DEBUG_INFO、EXIT_PROCESS_DEBUG_INFO、LOAD_DLL_DEBUG_INFO、UNLOAD_DLL_DEBUG_INFO和OUTPUT_DEBUG_STRING_INFO。

在以上眾多的結構體中,特別要介紹一下EXCEPTION_DEBUG_INFO,因為這個結構體中包含了關于異常相關的信息,而對于其他的幾個結構體,使用比較簡單,大家可以參考MSDN。EXCEPTION_DEBUG_INFO的定義如下:

在EXCEPTION_DEBUG_INFO中包含的EXCEPTION_RECORD結構體中保存著真正的異常信息,對于dwFirstChance里面保存著ExceptionRecord的個數。看一下關于EXCEPTION_RECORD結構體的定義:

(1)ExceptionCode:異常碼。該值在MSDN中的定義非常多,不過我們需要使用的值只有3個,分別是EXCEPTION_ACCESS_VIOLATION (訪問違例)、EXCEPTION_BREAKPOINT(斷點異常)和EXCEPTION_SINGLE_STEP(單步異常)。這3個值中的前兩個值對于我們來說是非常熟悉的,因為在前面已經介紹過了,關于最后一個單步異常想必也是非常熟悉的了。我們在使用OD快捷鍵的F7鍵、F8鍵時就是在使用單步功能,而單步異常就是有EXCEPTION_SINGLE_STEP來表示的。

(2)ExceptionRecord:指向一個EXCEPTION_RECORD的指針,異常記錄是一個鏈表,其中可能保存著很多的異常信息。

(3)ExceptionAddress:異常產生的地址。

調試事件這個結構體DEBUG_EVENT看似非常復雜,其實也只是嵌套得比較深而已。只要大家去體會每個結構體,體會每層嵌套的含義,自然而然就覺得它沒有多么復雜了。

六、調試循環

調試器在不斷地對被調試目標進程進行捕獲調試信息,有點類似于Win32應用程序的消息循環,但是又有所不同。調試器在捕獲到調試信息后,進行相應地處理,然后恢復線程使之繼續運行。

用來等待捕獲被調試進程調試事件的函數是WaitForDebugEvent(),該函數的定義如下:

(1)lpDebugEvent:該參數用于接收保存調試事件;

(2)dwMillisenconds:該參數用于指定超時的時間,無限制等待使用INFINITE。

在調試器捕獲到調試事件后會對被調試的目標進程中產生調試事件的線程進行掛起,在調試器對被調試目標進程進行相應的處理后,需要使用ContinueDebugEvent()對先前被掛起的線程進行恢復。ContinueDebugEvent()函數的定義如下:

(1)dwProcessId:該參數表示被調試進程的進程標識符。

(2)dwThreadId:該參數表示準備恢復掛起線程的線程標識符。

(3) dwContinueStatus:該參數指定了該線程以何種方式繼續執行,該參數的取值為DBG_EXCEPTION_NOT_HANDLED和DBG_CONTINUE。對于這兩個值來說,在通常的情況下并沒有什么差別。但是當遇到調試事件中的調試碼為EXCEPTION_DEBUG_EVENT時這兩個常量就會有不同的動作,如果使用DBG_EXCEPTION_NOT_HANDLED,調試器進程將會忽略該異常,Windows會使用被調試進程的異常處理函數對異常進行處理;如果使用DBG_CONTINUE的話,那么需要調試器進程對異常進行處理,然后繼續運行。

由上面兩個函數配合調試事件結構體,就可以構成一個完整的調試循環,以下這段調試循環的代碼摘自MSDN,代碼如下:

以上就是一個完整的調試循環,不過有些調試事件對于我們來說可能是用不到的,那么就把不需要的調試事件所對應的case語句刪除掉就可以了。

七、內存的操作

調試器進程通常要對被調試的目標進程進行內存的讀取或寫入。對于跨進程的內存讀取和寫入的函數是ReadProcessMemory() 和WriteProcessMemory()。

要對被調試的目標進程設置INT3斷點時,就需要使用WriteProcessMemory()函數對指定的位置寫入0xCC。當INT3被執行后,要在原來的位置上把原來的機器碼寫回去,原來的機器碼需要使用ReadProcessMemory()函數來進行讀取。

關于內存操作除了以上兩個函數以外,還有一個就是修改內存的頁面屬性的函數,即VirtualProtectEx(),同樣這個函數前面也介紹過了。

八、線程環境相關API及結構體

進程是用來向系統申請各種資源的,而真正被分配到CPU并執行代碼的是線程。進程中的每個線程都共享著進程的資源,但是每個線程都有不同的線程上下文,或線程環境。Windows是一個多任務的操作系統,在Windows中為每一個線程分配一個時間片,當某個線程執行完其所屬的時間片后,Windows會切換到另外的線程去執行。在進行線程切換以前有一步保存線程環境的工作,那就是保存在切換時線程的所有寄存器值、棧信息及描述符等相關的所有信息。只有把線程的上下文保存起來,在下次該線程被CPU再次調度時才能正確地接著上次的工作繼續進行。

在Windows系統下,將線程環境定義為CONTEXT結構體,該結構體需要在Winnt.h頭文件中找到,在MSDN中并沒有給出定義。CONTEXT結構體的定義如下:

這個結構體看似很大,但是也并不大,只要了解匯編語言的話,結構體中的各個字段應該是非常熟悉的。這里介紹一下ContextFlags字段的功能,該字段用于控制GetThreadContext()和SetThreadContext()能夠獲取或寫入的環境信息。ContextFlags的取值也只能在Winnt.h頭文件中找到,其取值如下:

從這些宏定義的注釋來看,能很清楚地知道這些宏可以控制GetThreadContext()和SetThreadContext()進行何種操作。大家在真正使用時進行相應的賦值就可以了。

該結構體可能會在Winnt.h中找到多個定義,因為該結構體是與平臺相關的。因此,在各種不同的平臺上此結構體有所不同。

線程環境在Windows中定義了一個CONTEXT的結構體,我們要進行獲取或設置線程環境的話,需要使用GetThreadContext()和SetThreadContext()。這兩個函數的定義分別如下:

這兩個函數的參數都基本一樣,hThread表示線程句柄,而lpContext表示指向CONTEXT的指針。所不同的是,GetThreadContext()是用來獲取線程環境的,SetThreadContext()是用來進行設置線程環境的。

微信公眾號:計算機與網絡安全

ID:Computer-network

【推薦書籍】

總結

以上是生活随笔為你收集整理的network怎么断点调试_Windows 网络编程:调试 API的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。