软件断点的原理是:再目前进程的某一行代码开头的位置,把硬编码改为0xCC.
CPU在执行到这里的时候就会触发INT 3号断点,去执行IDT表的3号处理程序。如果有调试器,就回把异常转发给调试器处理。
// VEHXXXX.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>
DWORD ThreadProc(PVOID P)
{
DEBUG_EVENT dEvent={0};
DWORD *p=(PDWORD)&dEvent;
DWORD PID=1132;
HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,0,PID);
//DebugActiveProcess会在被调试程序下一个断点,把这个断点给忽略掉。
BOOL IsSysTemBreak=TRUE;
if(!hProcess)
{
printf("进程打开失败");
return 0;
}
int oldCode=0;
//读取原来的指令,保存起来,恢复断点的时候用
ReadProcessMemory(hProcess,(LPVOID)0x4113c0,&oldCode,1,NULL);
int BreakPoint=0xcc;
WriteProcessMemory(hProcess,(LPVOID)0x4113c0,&BreakPoint,1,NULL);
DebugActiveProcess(PID);
while (WaitForDebugEvent(&dEvent, INFINITE))
{
CONTEXT ct={0};
ct.ContextFlags= CONTEXT_FULL;
switch (dEvent.dwDebugEventCode)
{
case EXCEPTION_DEBUG_EVENT:
{
if(IsSysTemBreak)
{
IsSysTemBreak=FALSE;
break;
}
WriteProcessMemory(hProcess,(LPVOID)0x4113c0,&oldCode,1,NULL);
GetThreadContext(OpenThread(THREAD_ALL_ACCESS,0,dEvent.dwThreadId),&ct);
printf("出异常的地址是:%x 异常码是:%x\n",ct.Eip,dEvent.u.Exception.ExceptionRecord.ExceptionCode);
//此时的EIP 和断点的EIP相差1 恢复了指令就需要把EIP-1 重新执行
ct.Eip--;
SetThreadContext(OpenThread(THREAD_ALL_ACCESS,0,dEvent.dwThreadId),&ct);
break;
}
}
ContinueDebugEvent(dEvent.dwProcessId, dEvent.dwThreadId, DBG_CONTINUE);
}
return 0;
}
int main(int argc, char* argv[])
{
CreateThread(0,0,(LPTHREAD_START_ROUTINE)ThreadProc,0,0,0);
getchar();
return 0;
}