反調試——4——硬件斷點反調試


反調試——4——硬件斷點反調試

 

 

首先需要明白什么是硬件斷點,硬件斷點其實是通過一個調試寄存器來實現的,這個調試寄存器是CPU上的東西,就是前面截圖的這個東西,叫做Debug Registers,在intel手冊卷3 17章第二節里面)。

DR0-DR3為設置斷點的地址,DR4和DR5為保留內容。DR6為調試異常產生后顯示的一些信息,DR7保存了斷點是否啟用、斷點類型和長度等信息。

重點在DR0-DR3和DR7這四個里面。

DR0-DR3中存放的是斷點的地址。

然后DR7根據各各字段的不同意義不同:

 

字段 意義
L0-L3 對於DR0-DR3存放的地址斷點是否有效,並且是一個局部斷點
G0-G3 對應DR0-DR3存放的地址是否有效,但是是一個全局斷點(在Windows中用不了。)
LEN0-LEN3 對應DR0-DR3斷點的長度。00表示1字節,01表示二字節,11表示四字節
RW0-RW3 對應DR0-DR3斷點的類型。00表示執行斷點,01表示寫入斷點,11表示讀寫斷點。

獲取硬點斷點信息:

這里我們要使用到一個API:

BOOL GetThreadContext(
 HANDLE    hThread,
 LPCONTEXT lpContext
);

用這個API來獲取當前線程的環境,肯定有人要問為什么是線程,不是進程,不是啥啥啥的。因為在操作系統中,線程才是真正執行代碼流程的東西,進程只是一個分配資源的概念,而每個代碼執行的時候,自己的寄存器或多或少都會受到影響,簡單來說就是線程才能實實在在執行代碼,如果用進程的話每個線程都會受到影響,而且進程也沒有這個GetProcessContext得到進行環境寄存器的API。

參數:

參數 意義
hThread 線程句柄
lpContext 指向CONTEXT結構體的指針,需要注意的是context是一個輸出參數就是通過這個API會修改CONTEXT結構體里的值,但是需要設置CONTEXT里的ContextFlags值來限制要獲得什么內容,如果不設置則不能獲得內容。

 

 

所以如果我們要獲取Debug Register的內容,這里需要設置為CONTEXT_DEBUG_REGISTERS了。

簡單實現硬件斷點反調試:

#include<Windows.h>
#include<iostream>
using namespace std;


int main()
{

CONTEXT TestContext{ 0 };
TestContext.ContextFlags = CONTEXT_DEBUG_REGISTERS;
GetThreadContext(GetCurrentThread(), &TestContext);
if (TestContext.Dr0 != 0 || TestContext.Dr1 != 0 || TestContext.Dr2 != 0 || TestContext.Dr3 != 0)
{
MessageBoxA(NULL, "硬件斷點檢測成功,程序正在被調試!", "硬件斷點檢測", MB_OK);
}
else
{
MessageBoxA(NULL, "硬件斷點檢測失敗", "硬件斷點檢測", MB_OK);
}

system("pause");
return 0;
}
#pragma once
#include<Windows.h>
#include<iostream>
using namespace std;
void MyTestExceptionFilter();
LONG WINAPI MyUnhandledExceptionFilter(_EXCEPTION_POINTERS* ExceptionInfo);

 

最后查看通過OD打下硬件斷點的情況,和直接運行的情況:

 

 

 

采用異常實現硬件斷點反調試:

如果說直接用前面那種來實現反調試就太辣雞了,很容易就被識破,但是如果我們添加一個異常呢,這樣就會好很多,因為異常要通過一些寄存器,一些不是上面那種直接調用API的辦法,會麻煩一點。

采用異常過濾器來處理:

關於異常過濾器可以查看直接的博客:反調試——異常過濾器 - Sna1lGo - 博客園 (cnblogs.com)

這里我直接上代碼了:

#include"Anti-debugging.h"
LONG WINAPI MyUnhandledExceptionFilter(_EXCEPTION_POINTERS* ExceptionInfo)
{
if (ExceptionInfo->ContextRecord->Dr0 != 0 || ExceptionInfo->ContextRecord->Dr1 != 0 || ExceptionInfo->ContextRecord->Dr2 != 0 ||
ExceptionInfo->ContextRecord->Dr3 != 0)
{
cout << "Fuck" << endl;
cout << "異常過濾器驗證成功,程序正在被調試" << endl;
cout << "即將退出進程" << endl;
ExitProcess(0);
}
else
{
cout << "異常過濾器驗證失敗,程序有沒有被調試不知道" << endl;
}

ExceptionInfo->ContextRecord->Eip += 3;

return EXCEPTION_CONTINUE_EXECUTION;
}

void MyTestExceptionFilter()
{
printf("test\n");
SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
int a = 0;
int b = 2 / a;
cout << "跳過了異常代碼" << endl;
cout << "程序正常結束" << endl;
}
int main()
{
MyTestExceptionFilter();
system("pause");
return 0;
}

這里eip+3的原因是錯誤代碼的硬編碼是三個字節,跳過就好了。

 

 

但是這個用調試器就不行了,會一直在異常這里,不知道為什么。

 修正:

 

      官方文檔上寫了這個異常過濾器的函數的描述,如果這個程序正在被調試,那么異常會直接傳遞給調試器,所以當我們進行調試的時候這個異常過濾器是沒有作用的。

 

 

采用SEH來處理:

EXCEPTION_DISPOSITION mySEH(struct _EXCEPTION_RECORD* ExceptionRecord,PVOID EstablisherFrame,PCONTEXT pcontext,PVOID DispatcherContext)
{
if (pcontext->Dr1 != 0 || pcontext->Dr2 != 0 || pcontext->Dr3 != 0 || pcontext->Dr0 != 0)
{
printf("SEH驗證異常,程序正在被調試,即將退出程序\n");
ExitProcess(0);
}
else
{
printf("SEH驗證正常\n");
}
pcontext->Eip += 3;

return ExceptionContinueExecution;
}
void TestSeh()
{
printf("test SEH\n");

__asm
{
push mySEH
mov eax,fs:[0]
push eax
mov fs:[0],esp
mov eax, 0
mov[eax], 1
}
cout << "SEH: 跳過了異常代碼" << endl;
cout << "SEH: 程序正常結束" << endl;
}

然后通過調試就OK了,當調試器沒有選擇捕獲你這個異常的時候,異常就是交給程序的VEH,SEH,異常過濾器來處理的。

 

采用VEH來處理:

 

LONG WINAPI MyPvectoredExceptionHandler(_EXCEPTION_POINTERS* ExceptionInfo)
{
if (ExceptionInfo->ContextRecord->Dr1 != 0 || ExceptionInfo->ContextRecord->Dr2 != 0 || ExceptionInfo->ContextRecord->Dr3 != 0 || ExceptionInfo->ContextRecord->Dr0 != 0)
{
printf("VEH 驗證異常,程序正在被調試,即將退出程序\n");
ExitProcess(0);
}
else
{
printf("硬件斷點的VEH驗證正常,無硬件斷點\n");
}
ExceptionInfo->ContextRecord->Eip += 3;
return EXCEPTION_CONTINUE_EXECUTION;
}
void TestVeh()
{
printf("test VEH\n");
AddVectoredExceptionHandler(1, MyPvectoredExceptionHandler);
__asm
{
mov eax, 0
mov[eax], 1
}
cout << "VEH: 跳過了異常代碼" << endl;
cout << "VEH: 程序正常結束" << endl;
}

小結

首先需要理解硬件斷點的原理,然后通過各種異常驗證的時候比對硬件斷點是否存在來進行驗證。然后就是VEH,SEH,還有異常過濾器的使用方法。今天這個異常過濾器不知道為啥不行,明天再更新來解決這個異常過濾器的問題。(2021年10月4日 異常過濾器的問題已解決)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM