原理就是对所设地址的属性设置为不可读不可写属性,这样当这个地址被访问或写入就会产生异常。
//改变内存地址内存页的属性
BOOL VirtualProtectEx(
IN HANDLE hProcess,// 要修改内存的进程句柄
IN LPVOID lpAddress,// 要修改内存的起始地址
IN SIZE_T dwSize,// 页区域大小
IN DWORD flNewProtect,// 新内存页属性
OUT PDWORD lpflOldProtect //原内存页属性 用于保存改变前的属性
)
将被调试进程的某内存属性修改为:
PAGE_NOACCESS //不可访问 (PTE.P位 = 0)
PAGE_EXECUTE_READ //可读可执行 不可写 (PTE.P位 = 1 PTE.R/W = 0)
被调试进程
- CPU访问错误内存地址,触发页异常
- 查IDT表找到对应的中断处理函数 nt !_KiTrap0E (E号中断)
- ConmonDispatchErceptio
- KiDispatchException
- DbgkFPorwardException收集并发送调试事件
DbgkpSendApillessage(x, x)
1)第一个参数:消息结构 每种消息都有自己的消息结构共有7种类型.
2)第二个参数,要不要把本进程内除了自己之外的其他线程挂起.有些消息需要把其他线程挂起,比如异常
typedef HANDLE(__stdcall *pMyOpenThread)(
DWORD dwDesiredAccess, // access right
BOOL bInheritHandle, // handle inheritance option
DWORD dwThreadId // thread identifier
);
//被调试进程句柄
HANDLE hDebuggeeProcess = NULL;
//被调试线程句柄
HANDLE hDebuggeeThread;
DWORD dwOriginalProtect;//原页属性
//线程上下文
CONTEXT Context = {
0 };
BOOL WaitForUserCommand()
{
BOOL bRet = FALSE;
char cContext;
printf("COMMAND> ");
cContext = getchar();