首页
社区
课程
招聘
[求助]神奇的硬件中断hook,为什么release版本运行失败
发表于: 2012-12-28 01:20 7577

[求助]神奇的硬件中断hook,为什么release版本运行失败

2012-12-28 01:20
7577
小弟新手,有空写了个调试寄存器Hook(硬件中断),问题如下:
1.直接双击exe,debug版本没有问题;release版本hook不成功,仍然调用原函数???
2.由VC调试,运行后,直接在原API处断下,按F5没有用,一直断下.为什么会会一直停留在原API处?

整个工程也附上了,VS2008平台,还请兄弟们帮忙看下 哈:)

代码如下:

/************************************************************************
SetHardWareBP:
设置线程硬件断点
hThread:  线程句柄
dwAddr:    断点地址
dwDrIndex:  硬件寄存器(0~3)
nType:    断点类型(0:执行,1:读取,2:写入 3:读写)
nLen:    读写断点数据长度(1,2,4)
/************************************************************************/

BOOL SetHardWareBP(HANDLE hThread,DWORD dwAddr,DWORD dwDrIndex,UINT nType=0,UINT nLen=1)
{
	BOOL bResult=FALSE;
	WORD wLen;

	TRACE("SetHardWareBP Enter:hThread=0x%p, dwAddr=0x%p, dwDrIndex=%d, nType=%d, nLen=%d ...\n",
		hThread, dwAddr, dwDrIndex, nType, nLen);

	//参数校验
	if (dwDrIndex < 0 || dwDrIndex >= 4)
	{
		TRACE("invalid para dwDrIndex");
		return FALSE;
	}

	if (IsBadCodePtr((FARPROC)dwAddr))
	{
		TRACE("invalid para dwAddr");
		return FALSE;
	}

	if (nType < 0 || nType > 3)
	{
		TRACE("invalid para nType");
		return FALSE;
	}

	/*
	6.  LEN0-LEN3:(由第18.19.22.23.26.27.30位控制):指定内存操作的大小。
	00:1字节(执行断点只能是1字节长)
	01:2字节
	10:未定义或者是8字节(和cpu的系列有关系)
	11:4字节
	*/
	if (nLen == 1)
	{
		wLen = 0;
	}
	else if (nType == 0)
	{
		wLen = 0;
	}
	else if (nLen == 2)
	{
		if (dwAddr % 2 != 0)
		{
			TRACE("invalid para dwAddr:not mod 2");
			return FALSE;
		}
		else
		{
			wLen = 1;
		}
	}
	else if (nLen == 4)
	{
		if (dwAddr % 4 != 0)
		{
			TRACE("invalid para dwAddr:not mod 4");
			return FALSE;
		}
		else
		{
			wLen = 3;
		}
	}
	else
	{
		TRACE("invalid para dwAddr");
		return FALSE;
	}


	CONTEXT context = {0};
	context.ContextFlags=CONTEXT_DEBUG_REGISTERS;
	if(::GetThreadContext(hThread,&context))
	{
		DWORD dwDrFlags=context.Dr7;
		TRACE("begin Dr7=0x%x\n", dwDrFlags);

		//将断点地址复制进入对应Dr寄存器(参考CONTEXT结构)
		memcpy(((BYTE *)&context)+4+dwDrIndex*4,&dwAddr,4);  

		//决定使用哪个寄存器
		dwDrFlags|=(DWORD)0x1<<(2*dwDrIndex);
		TRACE("Dr7=0x%x\n", dwDrFlags);

		//见OD读写断点时 这个置位了,执行没有(置位也正常-_-)
		dwDrFlags|=0x100;
		TRACE("Dr7=0x%x\n", dwDrFlags);


		//先将对应寄存器对应4个控制位清零(先或,再异或,还有其它好方法吗) =.= 悲催的小学生
		// 		dwDrFlags|=(DWORD)0xF<<(16+4*dwDrIndex);
		// 		dwDrFlags^=(DWORD)0xF<<(16+4*dwDrIndex);
		DWORD dwTemp = (~((DWORD)0xF<<(16+4*dwDrIndex)));
		TRACE("dwTemp=0x%x\n", dwTemp);
		dwDrFlags &= dwTemp;
		TRACE("Dr7=0x%x\n", dwDrFlags);


		//设置断点类型,执行:00 读取:10 写入:01 读写:11
		dwDrFlags|=(DWORD)nType<<(16+4*dwDrIndex);  //读取
		TRACE("Dr7=0x%x\n", dwDrFlags);

		//设置读写断点时数据长度
		dwDrFlags|=(DWORD)wLen<<(18+4*dwDrIndex);  

		context.Dr7=dwDrFlags;
		TRACE("end Dr7=0x%x\n", dwDrFlags);

		if (::SetThreadContext(hThread,&context))
		{
			bResult=TRUE;
			TRACE("SetThreadContext successfully.\n");
		}
		else
		{
			TRACE("SetThreadContext failed.err=0x%x", GetLastError());
		}
	}
	return bResult;
}


/************************************************************************
ClearHardWareBP:
取消线程硬件断点
hThread:  线程句柄
dwAddr:    断点地址
dwDrIndex:  硬件寄存器(0~3)
nType:    断点类型(0:执行,1:读取,2:写入 3:读写)
nLen:    读写断点数据长度(1,2,4)
/************************************************************************/

BOOL ClearHardWareBP(HANDLE hThread, DWORD dwDrIndex)
{
	BOOL bResult=FALSE;
//	WORD wLen;

	TRACE("ClearHardWareBP Enter:hThread=0x%p, dwDrIndex=%d \n",
		hThread, dwDrIndex);

	//参数校验
	if (dwDrIndex < 0 || dwDrIndex >= 4)
	{
		TRACE("invalid para dwDrIndex");
		return FALSE;
	}

	CONTEXT context = {0};
	context.ContextFlags=CONTEXT_DEBUG_REGISTERS;
	if(::GetThreadContext(hThread,&context))
	{
		DWORD dwDrFlags=context.Dr7;
		TRACE("begin Dr7=0x%x\n", dwDrFlags);

		//将断点地址复制进入对应Dr寄存器(参考CONTEXT结构)
		memset(((BYTE *)&context)+4+dwDrIndex*4, 0, 4);  

		//决定使用哪个寄存器 L0-3/G0-3 清0
		dwDrFlags &= (~((DWORD)0x3<<(2*dwDrIndex)));

		//见OD读写断点时 这个置位了,执行没有(置位也正常-_-) --LE清0
		/*dwDrFlags &= !((DWORD)0x100);*/

		//先将对应寄存器对应4个控制位清零(先或,再异或,还有其它好方法吗) =.= 悲催的小学生
		dwDrFlags &= (~((DWORD)0xF<<(16+4*dwDrIndex)));

		//设置断点类型,执行:00 读取:10 写入:01 读写:11
		//dwDrFlags|=(DWORD)nType<<(16+4*dwDrIndex);  //读取

		//设置读写断点时数据长度
		//dwDrFlags|=(DWORD)wLen<<(18+4*dwDrIndex);  

		context.Dr7=dwDrFlags;
		TRACE("end Dr7=0x%x\n", dwDrFlags);

		if (::SetThreadContext(hThread,&context))
		{
			TRACE("SetThreadContext successfully.\n");
			bResult=TRUE;
		}
		else
		{
			TRACE("SetThreadContext failed.err=0x%x\n", GetLastError());
		}
	}
	return bResult;
}


PVOID g_pSehHandle = NULL;
BOOL AddSystemSehHandler() //添加异常处理SEH
{
	TRACE("AddSystemSehHandler Enter... \n");

	if (g_pSehHandle)
	{
		TRACE("SEH have been added");
		return FALSE;
	}

	if (g_pSehHandle = AddVectoredExceptionHandler(1, (PVECTORED_EXCEPTION_HANDLER)ExceptionHandler))
	{
		TRACE("AddSystemSehHandler successfully \n");
		return TRUE;
	}
	else
	{
		TRACE("AddSystemSehHandler failed \n");
		return FALSE;
	}
}

BOOL DelSystemSehHandler()
{
	TRACE("DelSystemSehHandler Enter... \n");

	if (!g_pSehHandle)
	{
		TRACE("SEH not added");
		return FALSE;
	}

	if (RemoveVectoredExceptionHandler(g_pSehHandle))
	{
		TRACE("DelSystemSehHandler successfully \n");
		g_pSehHandle = NULL;
		return TRUE;
	}
	else
	{
		TRACE("DelSystemSehHandler failed \n");
	}

	g_pSehHandle = NULL;

	return FALSE;
}


//异常处理函数 ---若调试器启动状态下,异常不会进入此处,因为内核优先分发异常给调试器
DWORD NTAPI ExceptionHandler(EXCEPTION_POINTERS * ExceptionInfo)
{
	//if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP) //硬件断点执行触发的是单步调试
	{
		if ((DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress == (DWORD)TestFun)
		{
			//直接改eip为目的函数,原函数直接被过滤
			ExceptionInfo->ContextRecord->Eip = (DWORD)HookedTestFun;
			return EXCEPTION_CONTINUE_EXECUTION;
		}
		else if ((DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress == (DWORD)TestFun2)
		{
			//直接改eip为目的函数,原函数直接被过滤
			ExceptionInfo->ContextRecord->Eip = (DWORD)HookedTestFun2;
			return EXCEPTION_CONTINUE_EXECUTION;
		}
		else if ((DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress == (DWORD)TestFun3)
		{
			//直接改eip为目的函数,原函数直接被过滤
			ExceptionInfo->ContextRecord->Eip = (DWORD)HookedTestFun3;
			return EXCEPTION_CONTINUE_EXECUTION;
		}
		else if ((DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress == (DWORD)TestFun4)
		{
			//直接改eip为目的函数,原函数直接被过滤
			ExceptionInfo->ContextRecord->Eip = (DWORD)HookedTestFun4;
			return EXCEPTION_CONTINUE_EXECUTION;
		}
	}


	return EXCEPTION_CONTINUE_SEARCH;
	// 	else
	// 	{
	// 		//在异常handler里重设drx防止断点被意外清除
	// 		ExceptionInfo->ContextRecord->Dr0 = 0x6f3a20dd;
	// 		ExceptionInfo->ContextRecord->Dr1 = 0x6f361f7b;
	// 		ExceptionInfo->ContextRecord->Dr7 = 0x405;
	// 		return EXCEPTION_CONTINUE_SEARCH;
	// 	}
}


void TestFun()
{
	_asm
	{
		mov eax,eax
			mov eax,eax
	}
	OutputDebugString("TestFun is running...\n");
	AfxMessageBox("TestFun");
}

void HookedTestFun()
{
	_asm
	{
		mov ebx,ebx
			mov ebx,ebx
	}
	OutputDebugString("HookedTestFun is running...\n");
	AfxMessageBox("HookedTestFun");
}

//////////////////////////////////////////////////////////////////////////
void CDrxHookTestDlg::OnBnClickedButton4()
{
	// TODO: 在此添加控件通知处理程序代码
	TestFun();
	TestFun2();
	TestFun3();
	TestFun4();
}

void CDrxHookTestDlg::OnBnClickedButton5()
{
	// TODO: 在此添加控件通知处理程序代码
	AddSystemSehHandler();

	_asm
	{
		mov ecx,ecx
			mov ecx,ecx
	}
	SetHardWareBP(GetCurrentThread(), (DWORD)TestFun, 1, 0, 1);
	SetHardWareBP(GetCurrentThread(), (DWORD)TestFun2, 2, 0, 1);
	SetHardWareBP(GetCurrentThread(), (DWORD)TestFun3, 3, 0, 1);
	SetHardWareBP(GetCurrentThread(), (DWORD)TestFun4, 0, 0, 1);
	//SetHardWareBP(GetCurrentThread(), (DWORD)0x004131D0, 1, 0, 1);
}

void CDrxHookTestDlg::OnBnClickedButton6()
{
	// TODO: 在此添加控件通知处理程序代码
	ClearHardWareBP(GetCurrentThread(), 0);
	ClearHardWareBP(GetCurrentThread(), 1);
	ClearHardWareBP(GetCurrentThread(), 2);
	ClearHardWareBP(GetCurrentThread(), 3);

	DelSystemSehHandler();
}



复件 DrxHookTest.zip

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 0
支持
分享
最新回复 (4)
雪    币: 55
活跃值: (519)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
2
Visual Studio 的调试循环会优先于你的VEH。
2012-12-28 08:01
0
雪    币: 126
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
不用VS,直接打开,release版本为啥hook失败呢?
2012-12-28 11:12
0
雪    币: 126
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
SetHardWareBP(GetCurrentThread(), (DWORD)TestFun, 1, 0, 1);
奇怪了,函数名怎么不是入口地址? 而是数据段的
2012-12-28 11:18
0
雪    币: 126
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
神奇的原因找到,是因为release版本编译器优化造成,将原本调用函数变成了调用的函数代码直接写在调用处.
修改方法:配置属性->c/c++->优化->内联函数展开->只适用于 __inline (/Ob1)

release版本默认编译如下:
00401A48    8B5424 1C       MOV     EDX, [ESP+1C]
00401A4C    52              PUSH    EDX
00401A4D    68 B8344000     PUSH    DrxHookT.004034B8                ; ASCII "Dr7=0x%x",LF
00401A52    33C9            XOR     ECX, ECX
00401A54    E8 67010000     CALL    DrxHookT.00401BC0
00401A59    83C4 08         ADD     ESP, 8
00401A5C    8BD2            MOV     EDX, EDX
00401A5E    8BD2            MOV     EDX, EDX
00401A60    8BC0            MOV     EAX, EAX
00401A62    8BC0            MOV     EAX, EAX
00401A64    8B35 5C304000   MOV     ESI, [<&KERNEL32.OutputDebugStri>; kernel32.OutputDebugStringA
00401A6A    68 98364000     PUSH    DrxHookT.00403698                ; ASCII "TestFun is running...",LF
00401A6F    FFD6            CALL    ESI
00401A71    6A 00           PUSH    0
00401A73    6A 00           PUSH    0
00401A75    68 B0364000     PUSH    DrxHookT.004036B0                ; ASCII "TestFun"
00401A7A    E8 75030000     CALL    <JMP.&mfc90.#1183>
00401A7F    68 E8364000     PUSH    DrxHookT.004036E8                ; ASCII "TestFun2 is running...",LF
00401A84    FFD6            CALL    ESI
00401A86    6A 00           PUSH    0
00401A88    6A 00           PUSH    0
00401A8A    68 00374000     PUSH    DrxHookT.00403700                ; ASCII "TestFun2"
00401A8F    E8 60030000     CALL    <JMP.&mfc90.#1183>
00401A94    68 3C374000     PUSH    DrxHookT.0040373C                ; ASCII "TestFun3 is running...",LF
00401A99    FFD6            CALL    ESI
00401A9B    6A 00           PUSH    0
00401A9D    6A 00           PUSH    0
00401A9F    68 54374000     PUSH    DrxHookT.00403754                ; ASCII "TestFun3"
00401AA4    E8 4B030000     CALL    <JMP.&mfc90.#1183>
00401AA9    68 90374000     PUSH    DrxHookT.00403790                ; ASCII "TestFun4 is running...",LF
00401AAE    FFD6            CALL    ESI


修改后编译如下:
00401A9D   .  52            PUSH    EDX
00401A9E   .  68 B8344000   PUSH    DrxHookT.004034B8                ;  ASCII "Dr7=0x%x",LF
00401AA3   .  33C9          XOR     ECX, ECX
00401AA5   .  E8 56010000   CALL    DrxHookT.00401C00
00401AAA   .  83C4 08       ADD     ESP, 8
00401AAD   >  8BD2          MOV     EDX, EDX
00401AAF   .  8BD2          MOV     EDX, EDX
00401AB1   .  E8 EAF9FFFF   CALL    DrxHookT.004014A0
00401AB6   .  E8 25FAFFFF   CALL    DrxHookT.004014E0
00401ABB   .  E8 60FAFFFF   CALL    DrxHookT.00401520
00401AC0   .  E8 9BFAFFFF   CALL    DrxHookT.00401560
2012-12-28 11:56
0
游客
登录 | 注册 方可回帖
返回
//