首页
社区
课程
招聘
SetUnhandledExceptionFilter函数在C、C++、VC中的使用
发表于: 2010-5-21 16:34 8676

SetUnhandledExceptionFilter函数在C、C++、VC中的使用

2010-5-21 16:34
8676
这个问题终于解决,把最终代码贡献出来,

最近在看异常处理的内容,想用VC实现SetUnhandledExceptionFilter函数的调用,遇到一些问题,向各路大侠求助
(1)VC自动提示的CONTEXT结构与Win32汇编中的CONTEXT结构不同,没有EIP、EAX等系列寄存器,而是一些Gpr0、Fpr0、Msr、Iar、Lr、Ctr寄存器,为什么呢?我自己声明了这个结构来用,可以吗?
(2)如何使异常处理结束后回到一个安全的位置呢? 就是这个新的指向安全位置的EIP的值如何获取
(3)我编写的下列代码有一些问题,它会连续三次弹出“回调函数”、“安全函数”对话框,然后就产生了一个异常,确定后程序退出,忽略后会继续连续弹出上边的两个对话框直至程序自动终止,什么原因哈..
(4)敬请提供在非汇编环境下实现这个SetUnhandledExceptionFilter函数的源码,C、C++、VC、内联汇编皆可,不胜感激。

下面的代码是可以运行的,分别是C++和MFC中的实现
//********************************************************
1. 顶级异常处理 C++
#include <windows.h>
#include <stdio.h> 

DWORD NewEip;
DWORD lpOldHandler;

typedef LPTOP_LEVEL_EXCEPTION_FILTER (_stdcall  *pSetUnhandledExceptionFilter)(
                      LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter 
                      );
pSetUnhandledExceptionFilter lpSetUnhandledExceptionFilter;

LONG WINAPI TopUnhandledExceptionFilter(
	struct _EXCEPTION_POINTERS *ExceptionInfo
)
{
	_asm pushad
	MessageBox(NULL,"回调函数被调用","回调函数",MB_OK);
	ExceptionInfo->ContextRecord->Eip=NewEip;
	lpSetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER )lpOldHandler);
	_asm popad
	return EXCEPTION_CONTINUE_EXECUTION;
}

/*void Bug() 
{ 
	_asm{
		mov  SafeAddr,offset NewEip	
		int  3
NewEip:
	}
}*/

int main()
{
lpSetUnhandledExceptionFilter=(pSetUnhandledExceptionFilter)GetProcAddress(LoadLibrary(("kernel32.dll")),"SetUnhandledExceptionFilter"); 
	lpOldHandler=(DWORD)lpSetUnhandledExceptionFilter(TopUnhandledExceptionFilter);

//	Bug();
	_asm{
		mov  NewEip,offset SafeAddr	
		int  3
SafeAddr:
	}

	MessageBox(NULL,"安全位置","成功回到安全位置",MB_OK);
	return 1;
}
2. 顶级异常处理 MFC
//********************************************************
static DWORD lpOldHandler;
typedef LPTOP_LEVEL_EXCEPTION_FILTER (_stdcall  *pSetUnhandledExceptionFilter)(
                      LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter 
                      );
pSetUnhandledExceptionFilter lpSetUnhandledExceptionFilter;

LONG WINAPI TopUnhandledExceptionFilter(
	struct _EXCEPTION_POINTERS *ExceptionInfo
)
{
	_asm pushad
	AfxMessageBox("回调函数");
	lpSetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER )lpOldHandler);
	ExceptionInfo->ContextRecord->Eip=NewEip;//转移到安全位置
	_asm popad
	return EXCEPTION_CONTINUE_EXECUTION;
}

void CDetectODDlg::OnSetUnhandledExceptionFilter() 
{
	bool isDebugged=0;
	// TODO: Add your control notification handler code here
	lpSetUnhandledExceptionFilter = (pSetUnhandledExceptionFilter)GetProcAddress(LoadLibrary(("kernel32.dll")),
  "SetUnhandledExceptionFilter"); 
	lpOldHandler=(DWORD)lpSetUnhandledExceptionFilter(TopUnhandledExceptionFilter);
	_asm{  //获取这个安全地址
		call me     //方式一,需要NewEip加上一个偏移值
me:
		pop NewEip  //方式一结束
		mov NewEip,offset safe //方式二,更简单
		int 3  //触发异常
	}	
	AfxMessageBox("检测到OD");
	isDebugged=1;
	_asm{
safe:	
	}
	if(1==isDebugged){

	}else{
		AfxMessageBox("没有OD");
	}	
}
//********************************************************

[课程]Linux pwn 探索篇!

收藏
免费 0
支持
分享
最新回复 (10)
雪    币: 20
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感动呀,还有54Ex就拿50Ex出来悬赏,竟依然还没人理……

那俺就班门弄斧一把了……

先献上WinNT下函数实现源码:
LPTOP_LEVEL_EXCEPTION_FILTER
WINAPI
SetUnhandledExceptionFilter(
    LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
    )
{
    LPTOP_LEVEL_EXCEPTION_FILTER PreviousTopLevelFilter;

    PreviousTopLevelFilter = BasepCurrentTopLevelFilter;
    BasepCurrentTopLevelFilter = lpTopLevelExceptionFilter;

    return PreviousTopLevelFilter;
}

把我理解的说一下,不一定对,仅供参考:
首先说说我对SetUnhandledExceptionFilter()函数的理解,这个函数的作用应该是设置未处理异常的过滤器,但是经过我对Win2003的研究,发现系统在执行Dll的加载与连接时会掉用到这个函数,就在进行初始化进程之前。

因此你的程序多次弹出对话框我个人认为是与此有关。
2010-5-23 21:45
0
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
学习来了谢谢
2010-5-23 22:04
0
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
都是高人我还刚刚进来
2010-5-23 22:06
0
雪    币: 72
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
LONG WINAPI GEHExceptionFilter( _EXCEPTION_POINTERS* ExceptionInfo )
{
printf( "Exception ...\n" );
ExitProcess( 0 );
return EXCEPTION_CONTINUE_SEARCH;
}

void Bug()
{
*( int* )0 = 0;
}

typedef LPTOP_LEVEL_EXCEPTION_FILTER (_stdcall  *pSetUnhandledExceptionFilter)(
                      LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
                      );
pSetUnhandledExceptionFilter lpSetUnhandledExceptionFilter;

int main()
{
lpSetUnhandledExceptionFilter = (pSetUnhandledExceptionFilter)GetProcAddress(LoadLibrary(("kernel32.dll")),
  "SetUnhandledExceptionFilter");

lpSetUnhandledExceptionFilter(GEHExceptionFilter);
Bug();
return 1;
}
2010-5-23 23:10
0
雪    币: 126
活跃值: (37)
能力值: ( LV2,RANK:140 )
在线值:
发帖
回帖
粉丝
6
谢谢,现在可以由这个过滤函数获取异常进行处理,但处理异常后,怎么样转移到异常指令后面的指令继续执行呢?我知道通过CONTEXT结构修改EIP就可以,我的代码中也已实现,问题在于:怎么样获取异常指令后面的这条指令的地址呢?有没有汇编里面的标号什么的?

怎么样获取某条指令的地址? 标号可以吗?

#include <windows.h>
#include <stdio.h> 
LONG WINAPI GEHExceptionFilter( _EXCEPTION_POINTERS* ExceptionInfo ) 
{ 
 printf( "Exception ...\n" ); 
 ExitProcess( 0 ); 
 return EXCEPTION_CONTINUE_SEARCH; 
}

void Bug() 
{ 
 *( int* )0 = 0; 
}

typedef LPTOP_LEVEL_EXCEPTION_FILTER (_stdcall  *pSetUnhandledExceptionFilter)(
                      LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter 
                      );
pSetUnhandledExceptionFilter lpSetUnhandledExceptionFilter;

int main()
{
 lpSetUnhandledExceptionFilter = (pSetUnhandledExceptionFilter)GetProcAddress(LoadLibrary(("kernel32.dll")),
  "SetUnhandledExceptionFilter");
 
 lpSetUnhandledExceptionFilter(GEHExceptionFilter);
 Bug();
 int a=5; //如何转到此处继续运行,也就是怎么获取这条指令的地址呢?有没有标号什么的?
 return 1;
} 
2010-5-24 09:47
0
雪    币: 65
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
下一个反汇编引擎,把指令解释一下是比较可靠的

如果要偷懒,就直接硬加一下这条指令长度吧
2010-5-24 16:30
0
雪    币: 359
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

DWORD g_dwLabel0 = 0;

LONG WINAPI GEHExceptionFilter(EXCEPTION_POINTERS* ExceptionInfo) 
{ 
	printf("Exception ...\n"); 
	ExceptionInfo->ContextRecord->Eip = g_dwLabel0;
	return EXCEPTION_CONTINUE_EXECUTION; 
}

void Bug() 
{ 
	__asm
	{
		mov eax, label0
		mov dword ptr[g_dwLabel0], eax
	}
	*(int*)0 = 0; 
	__asm
	{
	label0:
	}
}

int main()
{
	SetUnhandledExceptionFilter(GEHExceptionFilter);
	Bug();
	int a = 5; //如何转到此处继续运行,也就是怎么获取这条指令的地址呢?有没有标号什么的?
	printf("Exit Normally!\n"); 
	return 1;
}

如果要在Bug里面抛异常,并跳到Bug外面执行,那么esp会不平衡,不建议这么做。这里出异常后是跳到错误语句的下一句执行,这样对esp没影响。
如果非要跳到外面去,可以用setjmp和longjmp来做,不过还不如用__try...__except或者try...catch关键字呢。
PCONTEXT不需要自己定义,提示或许是有点问题,是几个宏的毛病,不要管它,直接用就行了。
2010-5-24 16:55
0
雪    币: 126
活跃值: (37)
能力值: ( LV2,RANK:140 )
在线值:
发帖
回帖
粉丝
9
谢谢各位,这个问题已经解决了,不好意思啊,再问一个问题:
我的这个VirtualProtect函数问什么老是执行失败呢,返回值一直是1,大家看看什么问题
VC XP平台

	PDWORD dwOldType;
	LPVOID lpvBase;               // 获取内存的基地址
	lpvBase = VirtualAlloc(NULL,0x1000,MEM_COMMIT,PAGE_READWRITE);
	if (lpvBase == NULL )		AfxMessageBox("内存分配失败");
	if(0==::VirtualProtect(lpvBase,0x1000,PAGE_EXECUTE_READ | PAGE_GUARD,dwOldType))
	AfxMessageBox("执行失败");
2010-5-24 20:54
0
雪    币: 359
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10
DWORD dwOldType;
if(0==::VirtualProtect(lpvBase,0x1000,PAGE_EXECUTE_READ | PAGE_GUARD,&dwOldType))

你原来的dwOldType是指针,没分配空间。
2010-5-24 21:05
0
雪    币: 126
活跃值: (37)
能力值: ( LV2,RANK:140 )
在线值:
发帖
回帖
粉丝
11
呀,你太强大了,崇拜
2010-5-25 18:20
0
游客
登录 | 注册 方可回帖
返回
//