由於軟件斷點與硬件斷點不同,它確實會更改代碼,因此編寫一種對自身執行校驗和的程序作為反調試器技術相對容易。是否可以對硬件斷點執行類似的操作?
由於軟件斷點與硬件斷點不同,它確實會更改代碼,因此編寫一種對自身執行校驗和的程序作為反調試器技術相對容易。是否可以對硬件斷點執行類似的操作?
這是一個非常好的問題,因為該主題不如用於檢測軟件斷點的反調試技術那麼受歡迎。既然您沒有提到該體系結構,我們就必須牢記,正如其名稱所暗示的那樣,硬件斷點取決於您所運行的硬件,因此,這種斷點的實現在每個體系結構之間是不同的。由於我們無法涵蓋所有架構,因此在此假設我正在談論Windows上的英特爾x86架構。
簡而言之,答案是是。基本上有兩種檢測硬件斷點的常用方法:
為了理解每種方法,我們應該首先了解什麼是硬件斷點以及(簡而言之)它是如何工作的。
在 x86 體系結構中,調試器使用一組調試寄存器來應用硬件斷點。存在8個調試寄存器來控制調試過程,範圍從 DR0 到 DR7 。這些寄存器不能從 ring3 特權訪問,而只能從CPL0(當前特權級別,ring0)訪問。因此,在以任何其他特權級別執行時嘗試讀取或寫入調試寄存器都會導致一般性保護錯誤。調試寄存器允許調試器在訪問內存以進行讀寫時中斷程序的執行並將控制權轉移給它。
x86調試寄存器
DR3-線性斷點地址3
DR4-保留。未由Intel
DR5定義-保留。英特爾未定義
DR6-斷點狀態
DR0-DR3存儲斷點的線性地址。存儲的地址可以與物理地址相同,或者需要將其轉換為物理地址。 DR6 指示激活了哪個斷點。 DR7 通過以下訪問模式定義斷點激活模式: read , write 或 execute 。
方法一-ThreadContext Win API
下面的示例基於 this中的示例CodeProject上的文章。對示例進行註釋以描述每段代碼:
bool IsHWBreakpointExists(){//此結構是函數的關鍵,並且是CONTEXT ctx; ZeroMemory(&ctx,sizeof(CONTEXT)); // CONTEXT結構是一個in / out參數,因此我們必須//設置標誌,以便Get / SetThreadContext知道要設置或獲取的內容。 ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; //獲取線程的句柄HANDLE hThread = GetCurrentThread(); //獲取寄存器if(GetThreadContext(hThread,&ctx)== 0)返回false;如果((ctx.Dr0)||(ctx.Dr1)||(ctx.Dr2)||(ctx.Dr3)){返回true; } else {返回false; }}
方法2-SEH
操縱調試寄存器的SEH方法更為普遍,並且更容易在Assembly中實現,如圖所示在以下示例中,再次從CodeProject中獲取:
ClrHwBpHandler proto .safeseh ClrHwBpHandlerClearHardwareBreakpoints proc假定fs:nothing push offset ClrHwBpHandler push fs:[0] mov dword ptr fs:[0],esp;設置SEH xor eax,eax div eax;導致異常彈出字ptr fs:[0];在這裡繼續執行,添加esp,4 retClearHardwareBreakpoints endpClrHwBpHandler proc xor eax,eax
mov ecx,[esp + 0ch];這是堆棧mov dword ptr [ecx + 04h],eax上的CONTEXT結構; Dr0 mov dword ptr [ecx + 08h],eax; Dr1 mov dword ptr [ecx + 0ch],eax; Dr2 mov dword ptr [ecx + 10h],eax; Dr3 mov dword ptr [ecx + 14h],eax; Dr6 mov dword ptr [ecx + 18h],eax; Dr7添加雙字ptr [ecx + 0b8h],2;我們在EIP上加2以跳過div eax retClrHwBpHandler endp