IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Windows下程序异常崩溃处理 -> 正文阅读

[系统运维]Windows下程序异常崩溃处理

崩溃(Crash)的原因是什么

在Windows中,调用?CreateProcess?函数启动主线程或?CreateThread?启动线程时,线程函数会在如下代码中运行(下面的代码引自《Windows核心编程》第25章未处理异常和C++异常)

// 主线程启动函数
// CreateProcess启动线程函数
VOID BaseProcessStart(PPROCESS_START_ROUTINE pfnSatrtAddr){
    __try{
        ExitThread((pfnSatrtAddr)());
    }
    __except(UnHandledExceptionFilter(GetExceptionInformation())){
        ExitProcess(GetExceptionCode());
    }
}

// CreateThread启动线程函数
VOID BaseThreadStart(PTHREAD_START_ROUTINE pfnSatrtAddr, PVOID pvParam){
    __try{
        ExitThread((pfnSatrtAddr)());
    }
    __except(UnHandledExceptionFilter(GetExceptionInformation())){
        ExitProcess(GetExceptionCode());
    }
}

会调用?UnHandledExceptionFilter(GetExceptionInformation())?来过滤异常信息,然后调用?ExitProcess(GetExceptionCode());?退出进程的运行。

也就是说,当线程中出现未捕获异常时,系统/程序就会Crash,蓝屏信息和异常信息对话框的显示都是在UnHandledExceptionFilter(GetExceptionInformation())?这句代码中出现的。

如何消除崩溃时出现的异常信息对话框

那么,如何消除程序崩溃时出现的异常信息对话框呢?我们有三种办法来处理。

1. 在每个线程中调用 SetErrorMode(SEM_NOGPFAULTERRORBOX) 来让 UnHandledExceptionFilter(GetExceptionInformation()) 调用时直接返回 EXCEPTION_EXECUTE_HANDLER,不显示异常信息框,直接退出程序。

2. 在每个线程中使用 __try{...}__except{...} 块,捕获未捕获异常,自行处理未捕获异常。

3. 使用自定义的 UnHandledExceptionFilter 函数替换Windows默认的 UnHandledExceptionFilter 函数,自行处理未捕获异常。

这三种方法中,最优的方法是第三种,下面我们就来讨论如何使用第三种方式捕获崩溃(Crash)时的异常,生成dump文件来帮助寻找异常。


如何捕获崩溃(Crash)时的异常,生成dump文件来帮助寻找异常

一般而言,Windows程序都是运行在客户的电脑上的,当程序出现Crash时,如果没有使程序生成dump文件的话,就只能远程控制客户的电脑生成,或者当程序出现Crash的时候,让客户不操作电脑,使用windbg之类的工具调试程序来寻找崩溃点。但是,这样也太麻烦了,而且影响客户对软件的使用。所以,我们让程序在Crash时自动生成dump文件,然后在客户处将dump文件获取到手,最后分析dump文件来寻找Crash原因就好了。

那么,如何让程序在Crash时自动生成dump文件呢?

这就用到了我们上一节讨论到的使用自定义的 MyUnhandledExceptionFilter 函数替换Windows默认的 UnHandledExceptionFilter 函数,自行处理未捕获异常了。

然后在调用函数运行下面代码即可:

SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);

上述代码的作用就是使用自定义的?MyUnhandledExceptionFilter?函数来替换Windows默认的?UnHandledExceptionFilter?函数,来达到在程序出现Crash时自动生成dump文件的结果。

但是,在出现未处理CRT异常时,CRT代码中会调用

SetUnhandledExceptionFilter(UNLL);

来还原我们的 UnHandledExceptionFilter 函数,所以在出现未捕获的CRT异常时还是不能生成dump文件,那么要怎么处理呢?

我们可以通过改写kernel32.dll中的 UnHandledExceptionFilter 函数的地址来使未捕获的CRT异常还是调用到我们自定义的 UnHandledExceptionFilter 函数这样来处理。

步骤如下

1.遍历程序的输入节,找到kernel32.dll的位置。
2.遍历kernel32.dll的输入节,找到UnHandledExceptionFilter函数地址。
3.改写该地址所指向的函数位置,重指向自定义的UnHandledExceptionFilter函数。

完整代码如下:

#include <windows.h>
#include <DbgHelp.h>
#include <stdlib.h>
#pragma comment(lib, "dbghelp.lib")
 
inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName)
{
	if(pModuleName == 0)
	{
		return FALSE;
	}
 
	WCHAR szFileName[_MAX_FNAME] = L"";
	_wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);
 
	if(wcsicmp(szFileName, L"ntdll") == 0)
		return TRUE;
 
	return FALSE;
}
 
inline BOOL CALLBACK MiniDumpCallback(PVOID                            pParam,
	const PMINIDUMP_CALLBACK_INPUT   pInput,
	PMINIDUMP_CALLBACK_OUTPUT        pOutput)
{
	if(pInput == 0 || pOutput == 0)
		return FALSE;
 
	switch(pInput->CallbackType)
	{
	case ModuleCallback:
		if(pOutput->ModuleWriteFlags & ModuleWriteDataSeg)
			if(!IsDataSectionNeeded(pInput->Module.FullPath))
				pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg);
	case IncludeModuleCallback:
	case IncludeThreadCallback:
	case ThreadCallback:
	case ThreadExCallback:
		return TRUE;
	default:;
	}
 
	return FALSE;
}
 
 
inline void CreateMiniDump(PEXCEPTION_POINTERS pep, LPCTSTR strFileName)
{
	HANDLE hFile = CreateFile(strFileName, GENERIC_READ | GENERIC_WRITE,
		FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
 
 
	if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
	{
		MINIDUMP_EXCEPTION_INFORMATION mdei;
		mdei.ThreadId           = GetCurrentThreadId();
		mdei.ExceptionPointers  = pep;
		mdei.ClientPointers     = NULL;
 
		MINIDUMP_CALLBACK_INFORMATION mci;
		mci.CallbackRoutine     = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;
		mci.CallbackParam       = 0;
 
		::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpNormal, (pep != 0) ? &mdei : 0, NULL, &mci);
 
		CloseHandle(hFile);
	}
}
 
LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
{
	CreateMiniDump(pExceptionInfo, L"core.dmp");
 
	return EXCEPTION_EXECUTE_HANDLER;
}
 
// 此函数一旦成功调用,之后对 SetUnhandledExceptionFilter 的调用将无效
void DisableSetUnhandledExceptionFilter()
{
	void* addr = (void*)GetProcAddress(LoadLibrary(L"kernel32.dll"),
		"SetUnhandledExceptionFilter");
 
	if (addr)
	{
		unsigned char code[16];
		int size = 0;

		code[size++] = 0x33;
		code[size++] = 0xC0;
		code[size++] = 0xC2;
		code[size++] = 0x04;
		code[size++] = 0x00;
 
		DWORD dwOldFlag, dwTempFlag;
		VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag);
		WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);
		VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);
	}
}
 
void InitMinDump()
{
	//注册异常处理函数
	SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
 
	//使SetUnhandledExceptionFilter
	DisableSetUnhandledExceptionFilter();
}
 
int _tmain(int argc, _TCHAR* argv[])
{
	InitMinDump();  
	int x=0;
	int y = 5;
 
	int z = y/x;
 
	return 0;
}

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-08-03 11:36:38  更:2021-08-03 11:38:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/10 1:53:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码