处理在NTDll中意外的用户断点

2023-10-31 05:38

本文主要是介绍处理在NTDll中意外的用户断点,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

郁闷了,直到遇到这篇文章。。感谢帮我们搬运绊脚石的人  ---以下转帖

 

 

 

很久没有写东西了,这次是为了完善很久很久以前写的一个培训ppt(VC的使用与调试技巧),才想起来写点东西的。
下面的文章参考了http://www.debuginfo.com/tips/userbpntdll.html,但不是翻译,偶英语太烂了。


我们在调试程序的过程中,有时会突然的显示一个对话框,上面显示这样一条信息:
User breakpoint called from code at 0x77fa018c
或者是
Unhandled exception at 0x77f767cd (ntdll.dll) in myapp.exe: User breakpoint.
不过我遇到过的都是第一条信息,没有遇到过第二条信息。

怎么回事?我们没有设置断点呀!为什么会有一个用户断点?
并且这个问题看起来并没有那么严重,不在调试状态下,程序正常运行,即使在调试状态下我们把这个对话框按了确定后,再继续F5,好像什么事情也没有发生,程序仍然在正常运行!

隐患!千万不要忽视她!这个信息告诉我们,程序中某个地方已经开始溃烂,如果你频繁的碰到这个对话框,就说明溃烂已经扩大了。

如果你够仔细,你会发现在你点了这个对话框的确定按钮之后,会在Output窗口中发现多了一行信息:
HEAP[DebugInfo2.exe]: Heap block at 00030FD8 modified at 00031010 past requested size of 30

查看堆栈窗口,里面显示这样的信息:
NTDLL! 7c921230()
NTDLL! 7c97db9c()
NTDLL! 7c98cd11()
NTDLL! 7c980af8()
KERNEL32! 7c85e7af()
_CrtIsValidHeapPointer(const void * 0x00031000) line 1697
_free_dbg(void * 0x00031000, int 0x00000001) line 1044 + 9 bytes
operator delete(void * 0x00031000) line 49 + 16 bytes
WinMain(HINSTANCE__ * 0x00400000, HINSTANCE__ * 0x00000000, char * 0x00151f15, int 0x00000001) line 13 + 15 bytes
WinMainCRTStartup() line 198 + 54 bytes
KERNEL32! 7c816d4f()

重现这样的现场很容易的,只需几行代码就可以了
char *p = new char[4];
lstrcpy(p, "this is a test");
delete p;

为什么会有这样的信息消息框出现呢?这是因为如果我们在调试状态下,操作系统用DebugWin32Heap来替代正常的heap分配内存空间。在这个堆上的任何操作,debug的堆管理器会检查堆的数据完整性,如果它发现了一个错误,就会报告一个消息上来。

那么,我们怎么样才能知道造成错误的原因呢?如果只是类似上面的演示代码,不用任何技巧都能发现并且定位的。但是,绝大多数情况下,Output窗口和CallStack窗口告诉我们的信息都不能让我们精确定位。

用BoundsChecker做运行期的检查可以查到这个错误的原因,并且我个人认为在程序发布之前,在BoundsChecker下完整的跑一遍,检查内存和资源是非常有必要的。但是每次都用BoundsChecker是比较麻烦的。

还有一个办法,可以让这种定位更准确一点。

那就是windows 2000 SP2之后提供的PageHeap机制。

下面的这段文字是别人写的,我抄的,:)
当一个应用程序的PageHeap机制被激活时,该应用程序的所有的堆分配被放到内存中,这样堆的边界就与虚拟内存的边界排在一起了。与堆相邻的虚拟内存页面被设置为NO_ACCESS。在该应用程序中对堆后面的空间的访问就会立刻引起错误,这就可以在一个调试工具中被捕获。在释放堆时,过程与之类似。PageHeap修改释放的应用程序虚拟页面为NO_ACCESS,这样,如果应用程序试图读写该内存时就会发生访问错误。如果为一个应用程序运行PageHeap特性,应用程序要比正常时运行得慢,并且需要更多的虚拟内存,因为每一个堆的分配都需要两个完整的虚拟内存页面。随着应用程序对堆的使用的增加,可能需要增加系统的虚拟内存的大小,否则会出现虚拟内存不够的错误信息。除非系统有相当大的虚拟内存,否则建议不要同时运行两个以上的激活了PageHeap特性的应用程序。

让我们的程序启用Full Page Heap机制,只需在注册表中
HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Image File Execution Options/YourAppName.exe下增加如下设置:
GlobalFlag,字符串类型,值是x02200000
PageHeapFlags,字符串类型,值是0x3
VerifierFlags,DWORD类型,值是00000001
其中YourAppName.exe换成你的程序的名字,不要带路径。

如果嫌麻烦,你可以到http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx下载Debugging Tools for Windows,安装后,有一个gflags工具,使用下面的命令:
gflags –p /enable YourAppName.exe /full
这个工具帮你写好了上面的注册表项目。
这个工具是一个GUI的程序,你可以双击并且设置相关调试入口。

如果设置了Full PageHeap模式,我们在调试运行的时候,那么就会在弹出那个令人费解的断点对话框之前出现一个断言对话框,哈哈,这个对话框可是有一个Retry按钮的,点击之后进入CallStack,你可以看到此时发生了什么了。

如果你编写的是一个dll,也可以使用这个机制的,不过注册表项下的值就要设置成如下:
GlobalFlag,字符串类型,值是0x02000000"
PageHeapTargetDlls,字符串类型,值是调试的dll名称,不带路径
VerifierFlags,DWORD类型,值是00000001
PageHeapFlags,字符串类型,0x403

或者使用命令行
gflags –p /enable YourAppName.exe /full /dlls YourDll.dll

这篇关于处理在NTDll中意外的用户断点的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/313183

相关文章

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

PHP轻松处理千万行数据的方法详解

《PHP轻松处理千万行数据的方法详解》说到处理大数据集,PHP通常不是第一个想到的语言,但如果你曾经需要处理数百万行数据而不让服务器崩溃或内存耗尽,你就会知道PHP用对了工具有多强大,下面小编就... 目录问题的本质php 中的数据流处理:为什么必不可少生成器:内存高效的迭代方式流量控制:避免系统过载一次性

Python实现批量CSV转Excel的高性能处理方案

《Python实现批量CSV转Excel的高性能处理方案》在日常办公中,我们经常需要将CSV格式的数据转换为Excel文件,本文将介绍一个基于Python的高性能解决方案,感兴趣的小伙伴可以跟随小编一... 目录一、场景需求二、技术方案三、核心代码四、批量处理方案五、性能优化六、使用示例完整代码七、小结一、

Python中 try / except / else / finally 异常处理方法详解

《Python中try/except/else/finally异常处理方法详解》:本文主要介绍Python中try/except/else/finally异常处理方法的相关资料,涵... 目录1. 基本结构2. 各部分的作用tryexceptelsefinally3. 执行流程总结4. 常见用法(1)多个e

PHP应用中处理限流和API节流的最佳实践

《PHP应用中处理限流和API节流的最佳实践》限流和API节流对于确保Web应用程序的可靠性、安全性和可扩展性至关重要,本文将详细介绍PHP应用中处理限流和API节流的最佳实践,下面就来和小编一起学习... 目录限流的重要性在 php 中实施限流的最佳实践使用集中式存储进行状态管理(如 Redis)采用滑动

MyBatis-plus处理存储json数据过程

《MyBatis-plus处理存储json数据过程》文章介绍MyBatis-Plus3.4.21处理对象与集合的差异:对象可用内置Handler配合autoResultMap,集合需自定义处理器继承F... 目录1、如果是对象2、如果需要转换的是List集合总结对象和集合分两种情况处理,目前我用的MP的版本

Python自动化处理PDF文档的操作完整指南

《Python自动化处理PDF文档的操作完整指南》在办公自动化中,PDF文档处理是一项常见需求,本文将介绍如何使用Python实现PDF文档的自动化处理,感兴趣的小伙伴可以跟随小编一起学习一下... 目录使用pymupdf读写PDF文件基本概念安装pymupdf提取文本内容提取图像添加水印使用pdfplum

C# LiteDB处理时间序列数据的高性能解决方案

《C#LiteDB处理时间序列数据的高性能解决方案》LiteDB作为.NET生态下的轻量级嵌入式NoSQL数据库,一直是时间序列处理的优选方案,本文将为大家大家简单介绍一下LiteDB处理时间序列数... 目录为什么选择LiteDB处理时间序列数据第一章:LiteDB时间序列数据模型设计1.1 核心设计原则

基于Redis自动过期的流处理暂停机制

《基于Redis自动过期的流处理暂停机制》基于Redis自动过期的流处理暂停机制是一种高效、可靠且易于实现的解决方案,防止延时过大的数据影响实时处理自动恢复处理,以避免积压的数据影响实时性,下面就来详... 目录核心思路代码实现1. 初始化Redis连接和键前缀2. 接收数据时检查暂停状态3. 检测到延时过

Java利用@SneakyThrows注解提升异常处理效率详解

《Java利用@SneakyThrows注解提升异常处理效率详解》这篇文章将深度剖析@SneakyThrows的原理,用法,适用场景以及隐藏的陷阱,看看它如何让Java异常处理效率飙升50%,感兴趣的... 目录前言一、检查型异常的“诅咒”:为什么Java开发者讨厌它1.1 检查型异常的痛点1.2 为什么说