77范文网 - 专业文章范例文档资料分享平台

深入探索Win32结构化异常处理 - 图文(6)

来源:网络收集 时间:2019-08-17 下载这篇文档 手机版
说明:文章内容仅供预览,部分内容可能不全,需要完整文档或者需要复制内容,请下载word后使用。下载word有问题请添加微信号:或QQ: 处理(尽可能给您提供完整文档),感谢您的支持与谅解。点击这里给我发消息

{

// 生成一个异常

excptRec2.ExceptionRecord = pExcptRec; excptRec2.NumberParameters = 0;

excptRec2.ExceptionCode = STATUS_INVALID_UNWIND_TARGET; excptRec2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; RtlRaiseException( &exceptRec2 ); } }

PVOID pStack = pExcptRegHead + 8; // 8 = sizeof(EXCEPTION_REGISTRATION)

// 确保pExcptRegHead在堆栈范围内,并且是4的倍数 if ( (stackUserBase <= pExcptRegHead ) && (stackUserTop >= pStack ) && (0 == (pExcptRegHead & 3)) ) {

DWORD pNewRegistHead; DWORD retValue;

&pNewRegistHead, pExceptRegHead->handler ); if ( retValue != DISPOSITION_CONTINUE_SEARCH ) {

if ( retValue != DISPOSITION_COLLIDED_UNWIND ) {

excptRec2.ExceptionRecord = pExcptRec; excptRec2.NumberParameters = 0;

excptRec2.ExceptionCode = STATUS_INVALID_DISPOSITION; excptRec2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; RtlRaiseException( &excptRec2 ); } else

pExcptRegHead = pNewRegistHead; }

PEXCEPTION_REGISTRATION pCurrExcptReg = pExcptRegHead; pExcptRegHead = pExcptRegHead->prev; RtlpUnlinkHandler( pCurrExcptReg ); }

else // 堆栈已经被破坏!生成一个异常 {

excptRec2.ExceptionRecord = pExcptRec; excptRec2.NumberParameters = 0;

excptRec2.ExceptionCode = STATUS_BAD_STACK;

excptRec2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; RtlRaiseException( &excptRec2 ); }

tehandlerForUnwind(pExcptRec, pExcptRegHead, &context,

}

// 如果执行到这里,说明已经到了EXCEPTION_REGISTRATION // 结构链表的末尾,正常情况下不应该发生这种情况。

// (因为正常情况下异常应该被处理,这样就不会到链表末尾) if ( -1 == pRegistrationFrame ) NtContinue( &context, 0 ); else

NtRaiseException( pExcptRec, &context, 0 ); }

RtlUnwind 函数的伪代码到这里就结束了,以下是它调用的几个函数的伪代码: PEXCEPTION_REGISTRATION RtlpGetRegistrationHead( void ) {

return FS:[0]; }

RtlpUnlinkHandler( PEXCEPTION_REGISTRATION pRegistrationFrame ) {

FS:[0] = pRegistrationFrame->prev; }

void RtlpCaptureContext( CONTEXT * pContext ) {

pContext->Eax = 0; pContext->Ecx = 0; pContext->Edx = 0; pContext->Ebx = 0; pContext->Esi = 0; pContext->Edi = 0; pContext->SegCs = CS; pContext->SegDs = DS; pContext->SegEs = ES; pContext->SegFs = FS; pContext->SegGs = GS; pContext->SegSs = SS;

pContext->EFlags = flags; // 它对应的汇编代码为__asm{ PUSHFD / pop [xxxxxxxx] } pContext->Eip = 此函数的调用者的调用者的返回地址 // 读者看一下这个函数的 pContext->Ebp = 此函数的调用者的调用者的EBP // 汇编代码就会清楚这一点 pContext->Esp = pContext->Ebp + 8; }

虽然RtlUnwind函数的规模看起来很大,但是如果你按一定方法把它分开,其实并不难理解。它首先从FS:[4]和FS:[8]处获取当前线程堆栈的界限。它们对于后面要进行的合法性检查非常重要,以确保所有将要被展开的异常帧都在堆栈范围内。

RtlUnwind 接 着在堆栈上创建了一个空的EXCEPTION_RECORD结构并把STATUS_UNWIND赋给它的ExceptionCode域,同时把 EXCEPTION_UNWINDING标志赋给它的ExceptionFlags域。指向这个结构的指针作为其中一个参数被传递给每个异常回调函数。然 后,这个函数调用

RtlCaptureContext函数来创建一个空的CONTEXT结构,这个结构也变成了在展开阶段调用每个异常回调函数时传递给它 们的一个参数。

RtlUnwind 函 数的其余部分遍历EXCEPTION_REGISTRATION结构链表。对于其中的每个帧,它都调用 RtlpExecuteHandlerForUnwind函数,后面我会讲到这个函数。正是这个函数带EXCEPTION_UNWINDING标志调用了 异常处理回调函数。每次回调之后,它调用RtlpUnlinkHandler移除相应的异常帧。

RtlUnwind 函 数的第一个参数是一个帧的地址,当它遍历到这个帧时就停止展开异常帧。上面所说的这些代码之间还有一些安全性检查代码,它们用来确保不出问题。如果出现任 何问题,RtlUnwind就引发一个异常,指示出了什么问题,并且这个异常带有

EXCEPTION_NONCONTINUABLE标志。当一个进程被设 置了这个标志时,它就不允许再运行,必须终止。

未处理异常

在 文章的前面,我并没有全面描述UnhandledExceptionFilter这个API。通常情况下你并不直接调用它(尽管你可以这么做)。大多数情 况下它都是由KERNEL32中进行默认异常处理的过滤器表达式代码调用。前面BaseProcessStart函数的伪代码已经表明了这一点。

图 13是我为UnhandledExceptionFilter函数写的伪代码。这个API有点奇怪(至少在我看来是这样)。如果异常的类型是 EXCEPTION_ACCESS_VIOLATION,它就调用

_BasepCheckForReadOnlyResource。虽然我没有提供这个函 数的伪代码,但可以简要描述一下。如果是因为要对EXE或DLL的资源节(.rsrc)进行写操作而导致的异 常,

_BasepCurrentTopLevelFilter就改变出错页面正常的只读属性,以便允许进行写操作。如果是这种特殊的情 况,UnhandledExceptionFilter返回EXCEPTION_CONTINUE_EXECUTION,使系统重新执行出错指令。

图13 UnHandledExceptionFilter函数的伪代码

UnhandledExceptionFilter( STRUCT _EXCEPTION_POINTERS *pExceptionPtrs ) {

PEXCEPTION_RECORD pExcptRec; DWORD currentESP; DWORD retValue; DWORD DEBUGPORT; DWORD dwTemp2;

DWORD dwUseJustInTimeDebugger;

CHAR szDbgCmdFmt[256]; // 从AeDebug这个注册表键值返回的字符串

CHAR szDbgCmdLine[256]; // 实际的调试器命令行参数(已填入进程ID和事件ID) STARTUPINFO startupinfo; PROCESS_INFORMATION pi; HARDERR_STRUCT harderr; // ??? BOOL fAeDebugAuto; TIB * pTib; // 线程信息块

pExcptRec = pExceptionPtrs->ExceptionRecord;

if ( (pExcptRec->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) && (pExcptRec->ExceptionInformation[0]) ) {

retValue=BasepCheckForReadOnlyResource(pExcptRec->ExceptionInformation[1]);

if ( EXCEPTION_CONTINUE_EXECUTION == retValue )

return EXCEPTION_CONTINUE_EXECUTION; }

// 查看这个进程是否运行于调试器下

retValue = NtQueryInformationProcess(GetCurrentProcess(), ProcessDebugPort, &debugPort, sizeof(debugPort), 0 ); if ( (retValue >= 0) && debugPort ) // 通知调试器

return EXCEPTION_CONTINUE_SEARCH;

// 用户调用SetUnhandledExceptionFilter了吗? // 如果调用了,那现在就调用他安装的异常处理程序 if ( _BasepCurrentTopLevelFilter ) {

retValue = _BasepCurrentTopLevelFilter( pExceptionPtrs ); if ( EXCEPTION_EXECUTE_HANDLER == retValue ) return EXCEPTION_EXECUTE_HANDLER;

if ( EXCEPTION_CONTINUE_EXECUTION == retValue ) return EXCEPTION_CONTINUE_EXECUTION;

// 只有返回值为EXCEPTION_CONTINUE_SEARCH时才会继续执行下去 }

// 调用过SetErrorMode(SEM_NOGPFAULTERRORBOX)吗? {

harderr.elem0 = pExcptRec->ExceptionCode; harderr.elem1 = pExcptRec->ExceptionAddress; if ( EXCEPTION_IN_PAGE_ERROR == pExcptRec->ExceptionCode )

harderr.elem2 = pExcptRec->ExceptionInformation[2]; else

harderr.elem2 = pExcptRec->ExceptionInformation[0]; dwTemp2 = 1;

fAeDebugAuto = FALSE;

harderr.elem3 = pExcptRec->ExceptionInformation[1]; pTib = FS:[18h];

DWORD someVal = pTib->pProcess->0xC; if ( pTib->threadID != someVal ) { __try {

char szDbgCmdFmt[256];

retValue = GetProfileStringA( \ szDbgCmdFmt, sizeof(szDbgCmdFmt)-1 ); if ( retValue )

dwTemp2 = 2; char szAuto[8];

retValue = GetProfileStringA( \ szAuto, sizeof(szAuto)-1 );

if ( retValue )

if ( 0 == strcmp( szAuto, \ if ( 2 == dwTemp2 ) fAeDebugAuto = TRUE; }

__except( EXCEPTION_EXECUTE_HANDLER ) {

ESP = currentESP; dwTemp2 = 1;

fAeDebugAuto = FALSE; }

}

if ( FALSE == fAeDebugAuto ) {

retValue=NtRaiseHardError(STATUS_UNHANDLED_EXCEPTION | 0x10000000, 4, 0, &harderr,_BasepAlreadyHadHardError ? 1 : dwTemp2, &dwUseJustInTimeDebugger ); } else {

dwUseJustInTimeDebugger = 3; retValue = 0; }

if (retValue >= 0 && (dwUseJustInTimeDebugger == 3)

&& (!_BasepAlreadyHadHardError)&&(!_BaseRunningInServerProcess)) {

_BasepAlreadyHadHardError = 1;

SECURITY_ATTRIBUTES secAttr = { sizeof(secAttr), 0, TRUE }; HANDLE hEvent = CreateEventA( &secAttr, TRUE, 0, 0 ); memset( &startupinfo, 0, sizeof(startupinfo) );

sprintf(szDbgCmdLine, szDbgCmdFmt, GetCurrentProcessId(), hEvent); startupinfo.cb = sizeof(startupinfo); startupinfo.lpDesktop = \

CsrIdentifyAlertableThread(); // ???

= CreateProcessA( 0, // 应用程序名称

szDbgCmdLine, // 命令行

0, 0, // 进程和线程安全属性 1, // bInheritHandles 0, 0, // 创建标志、环境 0, // 当前目录 &statupinfo, // STARTUPINFO &pi); // PROCESS_INFORMATION if ( retValue && hEvent ) {

百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说教育文库深入探索Win32结构化异常处理 - 图文(6)在线全文阅读。

深入探索Win32结构化异常处理 - 图文(6).doc 将本文的Word文档下载到电脑,方便复制、编辑、收藏和打印 下载失败或者文档不完整,请联系客服人员解决!
本文链接:https://www.77cn.com.cn/wenku/jiaoyu/680616.html(转载请注明文章来源)
Copyright © 2008-2022 免费范文网 版权所有
声明 :本网站尊重并保护知识产权,根据《信息网络传播权保护条例》,如果我们转载的作品侵犯了您的权利,请在一个月内通知我们,我们会及时删除。
客服QQ: 邮箱:tiandhx2@hotmail.com
苏ICP备16052595号-18
× 注册会员免费下载(下载后可以自由复制和排版)
注册会员下载
全站内容免费自由复制
注册会员下载
全站内容免费自由复制
注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: