VC下发布的Release版程序的异常捕捉

CTF密码学奇技淫巧:当Base64遇到ROT13与Atbash 本文深入解析CTF竞赛中Base64、ROT13与Atbash的复合编码技术,提供Python实现与CyberChef可视化处理方案,帮助选手掌握密码学题目的解题技巧。通过NewStarCTF2025实战案例,对比脚本化与可视化工具的优劣,提升Web安全竞赛中的编码处理能力。 阅读详情
VC下发布的Release版程序的异常捕捉
寻找Release版程发生异常退出的地方比Debug版麻烦得多。发生异常的时候windows通常会弹出一个错误对话框,点击详细信息,我们能获得出错的地址和大概的出错信息,然后可以用以下办法分析我们的程序。
  
一.     用MAP文件定位异常代码位置。
1.         如何生成map文件
打开“Project → Project Settings”,选择 C/C++ 选项卡,在“Debug Info”栏选择“Line Numbers Only”(或者在最下面的 Project Options 里面输入:/Zd),然后要选择 Link 选项卡,选中“Generate mapfile”复选框,并再次编辑 Project Options,输入:/mapinfo:lines,以便在 MAP 文件中加入行信息。然后编译工程则可以在输出目录得到同名的.map文件。
2.         使用map文件定位发生异常的代码行
编译得到的map文件可以用文本方式打开,大致是这样的格式:(括号内是PomeloWu填加的注释)
0729                 (←工程名)    
Timestamp is 42e9bc51 (Fri Jul 29 14:19:13 2005)    (←时间戳)    
Preferred load address is 00400000         (←基址)
  ……(Data段描述,省略)    
Address         Publics by Value              Rva+Base     Lib:Object   0001:00000000       ?_GetBaseMessageMap@C0729App@@KGPBUAFX_MSGMAP@@XZ 00401000 f   0729.obj……(↑这一行开始是函数信息,下面省略)
Line numbers for ./Release/ShowDlg.obj(C:/0729/ShowDlg.cpp) segment .text      24 0001:00003f90    28 0001:00003fce    29 0001:00003fd1    30 0001:00003fd4……(行号信息,前面的数字是行号,后一个数字是偏移量,下面省略)
  在获得程序异常的地址以后,首先通过函数信息部分定位出错的OBJ和函数。做法是用获得的异常地址与Rva+Base栏地址进行比较(Rva,偏移地址;Base,基址)。找到最后一个比获得的异常地址小的那个函数,那就是出错的函数。
之后,用获得的异常地址减去该函数的Rva+Base,就得到了异常行代码相对于函数起始地址的偏移。在“Line number for”部分找到相对应的模块,并把其后的行号信息与上面减得的偏移量对比,找到最接近的一个,前面的行号大致就是目标行了。
  
二.     获得错误的详细信息。
实际上,光靠Windows的错误消息对话框提供的信息量是很有限的,用自己写的exception filter可以获得更多的错误信息。用SetUnhandledExceptionFilter设定自定义错误处理回调函数替换Win32默认的top-level exception filter:
²         SetUnhandledExceptionFilter的函数原型:
LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(
  LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
                                   // exception filter function  
);
²         SetUnhandledExceptionFilter返回当前的exception filter。应当保存这个函数指针并在不再需要使用自定义错误处理函数的时候当作参数再次调用SetUnhandledExceptionFilter。
  
²         lpTopLevelExceptionFilter 是自定义的exception filter函数指针,如果传入NULL值则指定UnhandledExceptionFilter来负责异常处理。lpTopLevelExceptionFilter其函数原型应该是与UnhandledExceptionFilter同型:
LONG WINAPI UnhandledExceptionFilter(
  STRUCT _EXCEPTION_POINTERS *ExceptionInfo   // address of
                                              // exception info
);
²         lpTopLevelExceptionFilter的返回值应该是下面3种之一:
EXCEPTION_EXECUTE_HANDLER = 1
EXCEPTION_CONTINUE_EXECUTION = -1
这两个返回值都应该由调用UnhandledExceptionFilter后返回。
EXCEPTION_EXECUTE_HANDLER 表示进程结束
EXCEPTION_CONTINUE_EXECUTION表示处理异常之后继续执行
EXCEPTION_CONTINUE_SEARCH = 0
进行系统通常的异常处理(错误消息对话框)
  
²         lpTopLevelExceptionFilter的唯一的参数是_EXCEPTION_POINTERS结构指针。
typedef struct _EXCEPTION_POINTERS { // exp
    PEXCEPTION_RECORD ExceptionRecord;
    PCONTEXT ContextRecord;
} EXCEPTION_POINTERS;
其中PCONTEXT是一个指向进程上下文结构的指针,保存了各个寄存器在异常发生的时候的值,详细信息参考《Windows核心编程》。
ExceptionRecord则指向另一个结构体EXCEPTION_RECORD:
typedef struct _EXCEPTION_RECORD { // exr
    DWORD ExceptionCode;
    DWORD ExceptionFlags;
    struct _EXCEPTION_RECORD *ExceptionRecord;
    PVOID ExceptionAddress;
    DWORD NumberParameters;
    DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} EXCEPTION_RECORD;
DWORD ExceptionCode;
异常代码,指出异常原因。常见异常代码有:
EXCEPTION_ACCESS_VIOLATION = C0000005h
读写内存冲突
EXCEPTION_INT_DIVIDE_BY_ZERO = C0000094h
除0错误
EXCEPTION_STACK_OVERFLOW = C00000FDh
堆栈溢出或者越界
EXCEPTION_GUARD_PAGE = 80000001h
由Virtual Alloc建立起来的属性页冲突
EXCEPTION_NONCONTINUABLE_EXCEPTION = C0000025h
不可持续异常,程序无法恢复执行,异常处理例程不应处理这个异常
EXCEPTION_INVALID_DISPOSITION = C0000026h
在异常处理过程中系统使用的代码
EXCEPTION_BREAKPOINT = 80000003h
调试时中断(INT 3)
EXCEPTION_SINGLE_STEP = 80000004h
单步调试状态(INT 1)
DWORD ExceptionFlags;
异常标志
0,表示可修复异常
EXCEPTION_NONCONTINUABLE = 1,表示不可修复异常。在不可修复异常后尝试继续执行会导致EXCEPTION_NONCONTINUABLE_EXCEPTION = C0000025H异常。
struct _EXCEPTION_RECORD *ExceptionRecord;
当异常处理程序中发生异常时,此字段被填充,否则为NULL
PVOID ExceptionAddress;
发生异常的地址(EIP)
DWORD NumberParameters;
规定与异常相关的参数数量(0-15),是ExceptionInformation数组中元素个数。
DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
异常描述信息,大多数异常都未定义此数组,仅有EXCEPTION_ACCESS_VIOLATION 异常的描述信息:
ExceptionInformation[0],描述导致异常的操作类型
= 0 读异常
= 1 写异常
ExceptionInformation[1],发生读写异常的内存地址  
也就是说,只要注册了自己写的这个exception filter,一旦发生异常,进入这个exception filter,从参数我们就能获得各种需要的信息了。而这个exception filter需要做的就是保存这些信息,然后将异常处理的事情交还给系统就行了:
// in the beginning
// Install the unhandled exception filter function
g_previousFilter = SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
  
// exception filter
LONG WINAPI MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
{
    WriteLogFile(pExceptionInfo);  // 写入文件
    if ( g_previousFilter )
           return g_previousFilter( pExceptionInfo );
        else
            return EXCEPTION_CONTINUE_SEARCH;
    }
  
三.     使用COD文件精确分析异常原因
说精确分析多少有点言过其实,发生异常的情况各不相同,分析真正原因很可能是一件极其复杂的事情。不过用COD文件能比MAP文件更精确地定位产生异常的位置。结合汇编代码和自定义的exception filter获得的错误情报寄存器状态等各种信息,找到异常发生的直接原因是很容易的。
1.         如何生成cod文件
仍然是打开“Project → Project Settings”,选择 C/C++ 选项卡,在“Category”栏选择“Listing Files”然后在Listing file type栏选择“Assembly with Machine Code”。重新编译工程后则可以在输出目录看到与每一个.cpp文件同名的.cod文件。
2.         Cod文件的使用
首先还是利用map文件用获得的程序异常地址通过函数信息部分定位出错的OBJ和函数,并同样记录偏移地址(用获得的异常地址减去该函数的Rva+Base的差值)。然后,在相应的cod文件中(而不是在map文件后面的行号信息部分)来查找出错的函数,找到如下的格式:
?OnPaint@CShowDlg @@IAEXXZ PROC NEAR ; CShowDlg::OnPaint, COMDAT   ; 81   : {   (←格式为: 行号 : 源代码)     00000 83 ec 64 sub esp, 100 ; 00000064H (↑偏移地址)  (↖机器码)   (↑汇编码)   00003 56 push esi   ; 82   : if (IsIconic()) (下面省略)
   找到出错的函数以后,再用偏移地址就能找到准确的异常发生的地方。然后通过源程序、汇编码即可进行更详尽的分析了。 
Android 13.0 开机启动优化之PMS扫描apk耗时相关功能优化 在android13.0的系统rom定制化开发中,在系统中开发产品时,会根据客户要求内置第三方app,这时如果内置app过多,或者安装的app过多,在系统开机的过程中 在pms扫描安装app的时候,就会比较耗时,这时候就需要优化下pms扫描安装app这块的功能代码,用多线程来实现pms扫描安装app,来加快开机时间,接下来 来实现这个功能 阅读详情

相关推荐

unity pc运行包导入glb

本文介绍了在Unity中实现GLB/GLTF模型动态导入的方法。主要使用glTFast插件进行模型导入,配合StandaloneFileBrowser实现文件选择功能。文章提供了详细的插件安装方式(包括国内镜像源),并给出了核心导入脚本代码。脚本实现了模型加载、父对象设置、材质修复等功能,解决了常见的材质显示异常问题。该方法支持编辑器和PC平台,兼容不同版本的glTFastAPI,通过简易UI操作即可完成模型导入,适合需要运行时加载3D模型的Unity项目开发。

懒懒的蓝的博客 545

关于release版本错误

引言 如果在您的开发过程中遇到了常见的错误,或许您的Release版本不能正常运行而Debug版本运行无误,那么我推荐您阅读本文:因为并非如您想象的那样,Release版本可以保证您的应用程序可以象Debug版本一样运行。 如果您在开发阶段完成之后或者在开发进行一段时间之内从来没有进行过Release版本测试,然而当您测试的时候却发现问题,那么请看我们的调试规则1: 规则1:

mail_cm的专栏 1620

从拧螺丝到精密装配:三菱伺服电机扭矩控制在工业自动化中的实战解析

本文深入解析三菱伺服电机扭矩控制在工业自动化中的实战应用,重点介绍MR-J4系列伺服系统的高精度扭矩响应技术。从螺丝紧固到精密装配,详细讲解扭矩控制模式的选择、硬件配置、参数设置及典型故障排查方案,帮助工程师提升生产效率和产品质量。

weixin_29186249的博客 471

Linux与Windows上获取当前堆栈信息

原文 在编写稳定可靠的软件服务时经常用到输出堆栈信息,以便用户/开发者获取准确的运行信息。常用在日志输出,错误报告,异常检测。 在Linux有比较简便的函数获取堆栈信息: 以上代码从参考的stackoverflow中稍作修改而来。核心就是backtrace与backtrace_symbols两个函数。 Windows下推荐用StackWalker这个开源代码,支持X86,AMD64,IA64。 如...

littlezhuhui的专栏 476

基于cnn version_transformer VIT模型的动物图像分类 完整代码+数据 动物分类教程

基于cnn version_transformer VIT模型的动物图像分类 完整代码+数据 动物分类教程

机器学习深度学习业余选手 1002

如何离线环境下安装Dify插件 (可提供远程指导协助)

离线环境下安装Dify插件

litlit023的专栏 8101

VC6下 try catch 在release下的杯具

      IDE:VC6      今天遇到一个小问题,把我郁闷了好久,××医生的VulEngine不时在wcsstr处发生crash,加了一番强大的参数检查后,再加上了强大的try catch,其实不是很喜欢用try和catch,总觉得一个完美的程序,应该代码的每一处都可以被程序员控制的,我倾向如对函数的返回值和参数进行强制的检查,当然这就要求你自己设计的函数必须也得满足这些要求,不过事情

magictong的专栏 6190

CodeQL查询时遇到报错:A fatal error occurred: Could not process query metadata for...如何解决?

🏆本文收录于 《全栈Bug调优(实战版)》 专栏,该专栏专注于分享我在真实项目开发中遇到的各类疑难Bug及其深层成因,并系统提供高效、可复现的解决思路和实操方案。无论你是刚入行的新手开发者,还是拥有多年项目经验的资深工程师,本专栏都将为你提供一条系统化、高质量的问题排查与优化路径,助力你加速成长,攻克技术壁垒,迈向技术价值最大化与职业发展的更高峰🚀!

**My Coding Family** 1085

VC下发布的Release版程序崩溃后的异常捕捉与查找

寻找Release版程发生异常退出的地方比Debug版麻烦得多。发生异常的时候windows通常会弹出一个错误对话框,点击详细信息,我们能获得出错的地址和大概的出错信息,然后可以用以下办法分析我们的程序。   一.     用MAP文件定位异常代码位置。 1.         如何生成map文件 打开“Project →Project Settings”,选择 C/C++ 选项卡,在“De

nokianasty的专栏 9364

Python 爬虫教程:企业官网基本信息抓取

本文介绍了使用Python爬虫技术抓取企业官网信息的方法,包括公司名称、简介、联系方式、地址、产品及新闻等数据。通过Requests和BeautifulSoup库实现网页请求与解析,并利用Pandas存储数据为CSV文件。同时提供了应对反爬虫机制(如设置User-Agent、代理IP池、延迟请求等)的解决方案,帮助高效获取企业公开数据。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1862

微软商店报错“此产品当前不可用”?终极修复指南

微软商店报错“此产品当前不可用”?终极修复指南

安德洛夫 3816

[转]VC下发布的Release版程序的异常捕捉

VC下发布的Release版程序的异常捕捉 新一篇:VC知识库文章 - 仅通过崩溃地址找出源代码的出错行 寻找Release版程发生异常退出的地方比Debug版麻烦得多。发生异常的时候windows通常会弹出一个错误对话框,点击详细信息,我们能获得出错的地址和大概的出错信息,然后可以用以下办法分析我们的程序。 一. 用MAP文件定位异常代码位置。 ...

weixin_30273501的博客 99

超声波雷达探测车位及信号处理方法

在APA泊车中用到了超声波雷达,第一次接触,总结研究之。

周陽讀書 1230
上一篇: 旧调重弹-SetUnhandledExceptionFilter的使用问题
下一篇: 如何让程序异常退出后重启
普通网友
博客等级 码龄22年 1万+粉丝 3156原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值