18910140161

微软Visual C运行时库解决方案

顺晟科技

2021-08-28 09:39:10

203

很多软件通过设置自己的异常捕捉功能来捕捉未处理的异常,并生成报告或日志(例如迷你转储文件),从而达到在Release版本下追踪bug的目的。但是在VS2005 (VC8)中,微软对CRT(C Runtime Library)的一些安全相关代码做了一些改动,比如增加了缓冲区溢出检查。在新的CRT版本中,当出现错误时,异常被强制抛出到默认调试器(如果没有配置,默认为Watson博士),而不是通知应用程序设置的异常捕获函数。这种行为主要发生在以下三种情况。

(1)调用中止函数并设置_CALL_REPORTFAULT选项(该选项在Release版本中默认设置)。

(2)启用运行时安全检查选项,在软件运行时检测到安全错误,如缓存溢出。(默认情况下,安全检查选项/GS也会打开)

(3)遇到_无效_参数错误,但应用程序没有主动调用_set_invalid_parameter_handler来设置错误捕获函数。

因此,结论是使用VS2005(VC8)编译的程序中的许多错误在SetUnhandledExceptionFilter中无法捕获。这是CRT相对于之前版本的一个很大的变化,但遗憾的是,微软并没有在相应的文档中明确指出。

解决办法

方法一:当windows进程崩溃时,禁止弹出错误对话框

程序初始化时添加以下代码。如果程序中的SetUnhandledExceptionFilter捕获到异常,则需要在SetUnhandledExceptionFilter之后添加以下代码。

set error mode(SEM _ failcriticallerrors | SEM _ nogpfaulterrobox);

_set_abort_behavior(0,_ WRITE _ ABORT _ MSG | _ CALL _ report fault);

或者

//关闭微软堆转储的噪音

_ crtstreportmode(_ CRT _ WARN,_ CRTDBG _ MODE _ FILE);

_ crtstreportfile(_ CRT _ WARN,CreateFileA('NUL ',GENERIC_WRITE,0,nullptr,OPEN_EXISTING,0,0));

set error mode(SEM _ failcriticallerrors | SEM _ nogpfaulterrobox);

//中止时禁用令人困惑的“有用”文本消息

_set_abort_behavior(0,_ WRITE _ ABORT _ MSG | _ CALL _ report fault);

_ CrtSetReportMode:将开发编译环境的报表类型设置为警告,报表的输出方式为文件输出。

_ CrtSetReportFile:创建一个空文件,并向该文件输出警告消息。警告信息已关闭。

_set_abort_behavior:处理VS环境中只有异常被强制抛出到默认调试器的问题,使用此函数将异常抛出到异常陷阱函数。SetErrorMode:控制指定类型的严重错误是否由windows或应用程序处理。

方法二:截取调用SetUnhandledExceptionFilter函数的CRT,使其无效。

应用程序无法捕获这些异常的原因是新版本的CRT实现强制删除了应用程序先前在异常处理中设置的所有捕获函数,如下所示:

/*确保删除任何已有的过滤器。*/

SetUnhandledExceptionFilter(空);

UnhandledExceptionFilter(异常指针);

解决方法是阻止CRT调用SetUnhandledExceptionFilter函数并使其无效。在X86平台下,可以使用以下代码。

#ifndef _M_IX86

#错误“以下代码仅适用于x86!”

#endif

void disablesetunhandledexception filter()

{

void * addr=(void *)GetProcAddress(LoadLibrary(_ T(' kernel 32 . dll '),' SetUnhandledExceptionFilter ');

if (addr)

{

无符号字符代码[16];

int size=0;

代码[size]=0x 33;

代码[size]=0xc 0;

代码[大小]=0xc 2;

代码[大小]=0x 04;

代码[大小]=0x 00;

DWORD dwOldFlag,dwTempFlag

VirtualProtect(addr,size,PAGE_READWRITE,dwOldFlag);

WriteProcessMemory(GetCurrentProcess(),addr,代码,大小,NULL);

VirtualProtect(addr,size,dwOldFlag,dwTempFlag);

}

}

WIN8.1上VirtualProtect报告的错误C0000005,解决方法如下:

bool AdjustPrivileges()

{

HANDLE hToken

TOKEN _ PRICES TP;

TOKEN _ PRIVILEGES oldtp

DWORD DWSize=sizeof(TOKEN _ PRIORIES);

标识符流体;

if(!OpenProcessToken(GetCurrentProcess(),TOKEN _ ADJUST _ priorities | TOKEN _ QUERY,hToken))

{

if(GetLastError()==ERROR _ CALL _ NOT _ IMPLEMENTED)返回真实的

否则返回错误的

}

if(!LookupPrivilegeValue(空,SE_DEBUG_NAME,luid))

{

关闭手柄(HToken);

返回错误的

}

ZeroMemory(tp,sizeof(TP));

tp .PrivilegeCount=1;

tp .特权[0]。流体=流体

tp .特权[0]。属性=SE _ PRIVILEGE _ ENABLED

/*调整令牌权限*/

if(!AdjustTokenPrivileges(hToken,FALSE,tp,sizeof(TOKEN_PRIVILEGES),oldtp,dwSize))

{

关闭手柄(HToken);

返回错误的

}

//关闭手柄

关闭手柄(HToken);

返回真;

}

void disablesetunhandledexception筛选器()

{

void * addr=(void *)GetProcAddress(LoadLibrary(_ T)()内核32。dll '),

setunhandledexception筛选器');

if (addr)

{

无符号字符代码[16];

int size=0;

//www.oicqzone.com

代码[大小]=0x 33;

代码[size]=0xc 0;

代码[大小]=0xc 2;

代码[大小]=0x 04;

代码[大小]=0x 00;

DWORD dwOldFlag,dwTempFlag

//提升调试权限

VirtualProtect(addr,size,PAGE_EXECUTE_READWRITE,dwOldFlag);

WriteProcessMemory(GetCurrentProcess(),addr,代码,大小,NULL);

VirtualProtect(addr,size,dwOldFlag,dwTempFlag);

}

}

在设置自己的异常处理函数后,调用disablesetunhandledexception筛选器禁止同阴极射线管设置即可。虽然也可以通过_set_abort_behavior(0,_ WRITE _ ABORT _ MSG | _ CALL _ report fault),信号(SIGABRT,), 和_set_invalid_parameter_handler(.)解决(1)(3),但是对于(2),设置美国石油学会(American Petroleum Institute)钩子是的方式。

方法三:禁止弹出"停止工作"对话框

在Win7及以后的系统中,如果一个程序发生了奔溃,系统会弹出一个“XX已停止工作"的对话框,如果不去这个窗口上点击"关闭程序",那么这个窗口会一直存在,最为关键的是,奔溃的进程并没有真正结束,还一直挂起在那里。这在自动化无人值守程序开发中是不允许的,有时候有的程序只能运行一个实例,如果奔溃的这个进程一直没有真正结束,新进程就无法启动。根据网上资料,在Windows操作系统操作系统服务管理器中关闭这个错误报告服务,仍然会弹出停止运行的对话框。最后在微软官方上找到了Windows操作系统操作系统的错误报告服务配置说明:https://msdn。微软。com/en-us/library/windows/desktop/bb 513638(v=vs . 85).文件

那如何禁止werfault窗口的弹出呢?

在栈溢出上找到一个方法,可以通过修改注册表,抑制这个错误窗口的弹出。

具体方法如下所示:

[HKEY _当前_用户\软件\微软\视窗\视窗错误报告]

Disabled '=dword:00000001

don tshowui '=dword :0000000001

[HKEY _ LOCAL _ MACHINE \ SOFTWARE \ Microsoft \ Windows \ Windows错误报告]

Disabled '=dword:00000001

don tshowui '=dword :0000000001

修改注册表后应该就可以了。

如果还有问题,可能需要重新加载注册表

1.进程中关闭explorer.exe

2.运行explorer.exe

相关文章
我们已经准备好了,你呢?
2024我们与您携手共赢,为您的企业形象保驾护航