INT3斷點
INT3斷點是利用0Xcc指令實現的,cpu在執行0xcc指令時會引發斷點異常調試器會捕捉這個異常。
INT3斷點引發的異常屬於陷阱型異常,在執行完0xcc指令后eip指向下一條指令。但是系統對int3有特殊處理,當異常第一次分發時如果調試器沒有處理那么第二次異常分發之前系統會令eip-1。
下面寫個調試程序來看一下。
#include <Windows.h>
#include <iostream>using namespace std;
int flag = 0; //標志是第一次斷點異常,還是第二次斷點異常
int main()
{
char a[256] = {0};
cout<<"請輸入需要調試的目標程序的路徑:";
cin>>a;
PROCESS_INFORMATION pi; //接受新進程的一些有關信息
STARTUPINFO si; //指定新進程的主窗體如何顯示
DEBUG_EVENT devent; //消息事件
CONTEXT stContext; //線程信息塊
GetStartupInfo(&si);
CreateProcessA(
a,
NULL,
NULL,
NULL,
FALSE, // 不可繼承
DEBUG_ONLY_THIS_PROCESS | DEBUG_PROCESS, // 調試模式啟動
NULL,
NULL,
&si,
&pi );
cout<<"創建進程成功"<<endl;
while(TRUE)
{
if(WaitForDebugEvent(&devent, INFINITE))
{
switch(devent.dwDebugEventCode)
{
case EXCEPTION_DEBUG_EVENT:
switch(devent.u.Exception.ExceptionRecord.ExceptionCode)
{
case EXCEPTION_BREAKPOINT: //斷點異常
if(devent.u.Exception.dwFirstChance == 1) //第一次異常分發
{
cout<<"第一次異常。 ";
cout<<"eip:";
stContext.ContextFlags = CONTEXT_FULL;
GetThreadContext(pi.hThread, &stContext);
int n1 = GetLastError();
cout<<stContext.Eip<<endl;
flag = 1;
}
if(devent.u.Exception.dwFirstChance == 0) //第二次異常分發
{
cout<<"第二次異常。 ";
cout<<"eip:";
GetThreadContext(pi.hThread, &stContext);
cout<<stContext.Eip<<endl;
flag = 0;
}
break;
}
break;
}
}
if(flag == 1) //如果是第一次碰見int3斷點異常,我們不處理他,讓他直接繼續進行第二次異常分發
ContinueDebugEvent(devent.dwProcessId, devent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
else //如果是第二次碰見int3斷點異常或者是其他調試事件我們直接返回讓程序繼續運行
{
flag = 0;
ContinueDebugEvent(devent.dwProcessId, devent.dwThreadId, DBG_CONTINUE);
}
}
return 0;
}
將一個不存在異常處理的程序第一條指令變為int3指令。
用上方程序作為例子進行調試,因為我們在第二次異常分發的時候返回DBG_CONTINUE來讓系統認為我們處理了異常所以eip又會指向int3指令處,至此以后一直循環產生異常
OD中對int3的處理
我們把剛才的例子程序在od中運行並設置int3異常不交給程序處理
運行程序發現eip指向int3的下一條指令,這說明OD在int3異常第一次分發時因為eip指向了下一條指令,這時od返回DBG_CONTINUE意思是異常不交給程序處理直接返回。
如果設置忽略int3異常,即int3異常傳遞給程序處理。
因為程序沒有異常處理所以第一次異常傳給程序后,異常又會進行二次分發。我們運行程序發現eip依然指向int3指令處,繼續運行發現程序依然指向int3處,這說明od默認第二次異常返回DBG_CONTINUE然后一直循環產生int異常(和我們文章開始寫的那個調試程序一樣)。
如果第二次異常時od沒有返回DBG_CONTINUE來向系統說明異常已處理,而返回DBG_EXCEPTION_NOT_HANDLED的話異常將不會繼續分發,程序將會被終止運行。(異常傳到頂層異常處理處,執行了默認的異常處理函數結束運行)
我們把文章開始的調試器修改一下,把讓第二次異常處理時返回DBG_EXCEPTION_NOT_HANDLED。
if(flag == 1) //如果是第一次碰見int3斷點異常,我們不處理他,讓他直接繼續進行第二次異常分發
ContinueDebugEvent(devent.dwProcessId, devent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
else //如果是第二次碰見int3斷點異常或者是其他調試事件我們直接返回讓程序繼續運行
{
flag = 0;
ContinueDebugEvent(devent.dwProcessId, devent.dwThreadId,DBG_EXCEPTION_NOT_HANDLED);
}
再次拿原來的那個程序當例子進行調試,我們發現在第二次異常調試器返回DBG_EXCEPTION_NOT_HANDLED后調試程序結束運行。
開始調試前
開始調試后,異常第二次分發后異常沒有繼續分發,並且程序結束運行