第二十九篇:USER MODE DLL开发过程中的调试技巧心得分享

2024-08-29 17:08

本文主要是介绍第二十九篇:USER MODE DLL开发过程中的调试技巧心得分享,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

最近由于项目需要,被老板安排开发一个WINDOWS USER MODE DLL, 即WINDOWS用户模式下的动态链接库。


写代码,实现具体的功能这类初等工作,对于大多数软件开发工程师来讲,只是时间与工作量上的问题,具体的WINDOWS DLL的知识点,本人参考了Jeffrey Richter的《WINDOWS核心编程》中的DLL几章,不再熬述。


这里谈一下关于USER MODE DLL在调试过程中所涉及到的一些知识点,以及它们彼此之间的关系:

1. DebugBreak / int 3;

2. OutputDebugString

3. bcdedit /debug (on/off)

4. Windbg user/kernel mode debug

5. IsDebuggerPresent() 函数返回值

6. DebugView.exe

7. EPROCESS.debugport

8. PEB.beingdebugged


1. DebugBreak / __asm int 3; 起到中断到调试器的功能。

在DLL初步编码完成,第一次上系统跑的时候,可以在DllMain中尝试加入它们,以确定DLL是否被服务或者EXE正确调用。

当然,也可以在其它阶段的函数中调用,不过,笔者在该断点HIT之时,通过.reload /f命令,正确加载了调试符号,就可以通过动态设置、取消断点的方式来继续进一步的调试。


2. OutputDebugString & DebugView.exe & Windbg user/kernel mode & IsDebuggerPresent

以及EPROCESS.debugport & PED.beingdebugged

这些个因素有他们之间的彼此关联。

首先,必须的一步,在Win7,8,8.1上使用DebugView.exe必须在注册表中加入:

HKLM/SYSTEM/CurrentControlSet/Control/Session Manager

Debug Print Filter (Key)

DWORD(type),DEFAULT (name)0xF(value)

其次,OutputDebugSting函数本质上是通过异常机制工作的(raise exception), 具体的理论方面的内容请参考张银奎《software debugging》, chapter 10.

这里只谈本人的一点实践经验。

第一,在目标进程没有被Windbg Attach的时候,即目标进程不处于被调试状态,在这种状态下,目标程序的EPROCESS.debugport == NULL, PEB.beingdebugged == FALSE.

IsDebuggerPresent()函数的判断依据实则为PEB.beingdebugged, 在没有被windbg attach时,返回为FALSE。


如果在你的代码中,有下面的代码段,OutputDebugString输出"Debugger not Present"到DebugView.exe中.

if(IsDebuggerPresent()){
OutputDebugString(TEXT("Debugger Present\n"));
}else{
OutputDebugString(TEXT("Debugger not Present\n"));
}

但是,当有windbg attach到目标进程,该目标进程进入到被调试状态,以上代码则输出“Debugger Present”到Windbg的Command窗口。

值得注意的是,IsDebuggerPresent()只与windbg attach有关,与系统是否处于kernel debug无关。

进一步讲,当目标进程被windbg attach后,上述进程处于user mode debug状态,进入user mode debug状态,则影响了EPROCESS.debugport与PEC.beingdebugged.

而通过设置NET双机调试,利用DebugBreak/int 3; 将DLL中断到windbg, 该行为并不影响以上两个变量,因为,此时目标进程处于kernel mode debug,从而IsDebuggerPresent返回为FALSE。


3. bcdedit /debug on/off & DebugBreak/int 3;

bcdedit /debug on的状态下, DebugBreak/int 3;会中断到调试器,如果此时系统没有双机联调,或者进程没有被attach, 具体表现则是系统一直pending.

bcdedit /debug off的状态下,DebugBreak/int 3;产生异常, 但由于该异常并未中断到调试器,该异常得不到正确处理,系统最终将该进程结束。


4. bcdedit /debug on/off & Windbg user/kernel mode & DebugBreak/int 3;

最后,来讲一讲他们之间的关系。

DebugBreak/int 3;作为一种异常,总归要有东西去处理。

假设, 被调试机器(target),既通过NET连接到了调试主机(host,此时bcdedit /debug on), 又在本地通过WINDBG ATTACH到了目标进程。

在这种情况下,DebugBreak/int 3;首先被本地WINDBG处理, 既中断到本地的WINDBG。

如果目标进程未被WINDBG ATTACH,则该异常中断到主机的WINDBG。

但是,如果此时也没有远程(NET)HOST WINDBG连接,则造成一个无东西处理的内核异常,则出现上面所说的,系统PENDING。


而在bcdedit /debug off并且既没有远程也没有本地WINDBG,则这是无东西处理的用户异常,最终,系统将该进程终止掉了。



后记:

EPROCESS的成员DebugPort是一个数据结构,作为调试子系统与调试器交互的一种通道(手段)。

其主要的数据成员包括一个EVENT用来信号通知,一个MUTEX用来同步链表操作,以及LIST_ENTRY用来排列调试事件。


DebugBreak的内核函数为DbgBreakPoint.


写代码是正面交战,敌人在明处,花时间与功夫,一点点地编码调试总归能够完成任务。

调试则正好相反,调试环境的搭建,调试关键知识的掌握,以及躲在暗处的BUG,从经验与系统知识上来讲,需要更加扎实的功底。


前阵子翻过一下张银奎的《software debugging》, 1000多页的内容,让人看了后面,忘了前面。

纠其原因,就是看书的方法不当,以软件开发的的思维习惯与软件开发的经验去看这本书,只能是花了时间功夫多,收获甚少。

但在开发这个DLL项目过程当中,实实在在地将一些调试方面的知识应用在实际当中,有了问题查找资料,然后再实践,之后,通过《software debugging》这本书,confirm遇到的这些调试知识点,调试技巧,达到举一反三,融会贯通的效果,将调试的基本观念用在软件开发的过程当中,才是实实在在的积小流,积跬步的过程。

这篇关于第二十九篇:USER MODE DLL开发过程中的调试技巧心得分享的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Golang操作DuckDB实战案例分享

《Golang操作DuckDB实战案例分享》DuckDB是一个嵌入式SQL数据库引擎,它与众所周知的SQLite非常相似,但它是为olap风格的工作负载设计的,DuckDB支持各种数据类型和SQL特性... 目录DuckDB的主要优点环境准备初始化表和数据查询单行或多行错误处理和事务完整代码最后总结Duck

基于Python开发电脑定时关机工具

《基于Python开发电脑定时关机工具》这篇文章主要为大家详细介绍了如何基于Python开发一个电脑定时关机工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 简介2. 运行效果3. 相关源码1. 简介这个程序就像一个“忠实的管家”,帮你按时关掉电脑,而且全程不需要你多做

SpringBoot 整合 Grizzly的过程

《SpringBoot整合Grizzly的过程》Grizzly是一个高性能的、异步的、非阻塞的HTTP服务器框架,它可以与SpringBoot一起提供比传统的Tomcat或Jet... 目录为什么选择 Grizzly?Spring Boot + Grizzly 整合的优势添加依赖自定义 Grizzly 作为

怎么关闭Ubuntu无人值守升级? Ubuntu禁止自动更新的技巧

《怎么关闭Ubuntu无人值守升级?Ubuntu禁止自动更新的技巧》UbuntuLinux系统禁止自动更新的时候,提示“无人值守升级在关机期间,请不要关闭计算机进程”,该怎么解决这个问题?详细请看... 本教程教你如何处理无人值守的升级,即 Ubuntu linux 的自动系统更新。来源:https://

Java中的Opencv简介与开发环境部署方法

《Java中的Opencv简介与开发环境部署方法》OpenCV是一个开源的计算机视觉和图像处理库,提供了丰富的图像处理算法和工具,它支持多种图像处理和计算机视觉算法,可以用于物体识别与跟踪、图像分割与... 目录1.Opencv简介Opencv的应用2.Java使用OpenCV进行图像操作opencv安装j

C++中实现调试日志输出

《C++中实现调试日志输出》在C++编程中,调试日志对于定位问题和优化代码至关重要,本文将介绍几种常用的调试日志输出方法,并教你如何在日志中添加时间戳,希望对大家有所帮助... 目录1. 使用 #ifdef _DEBUG 宏2. 加入时间戳:精确到毫秒3.Windows 和 MFC 中的调试日志方法MFC

mysql-8.0.30压缩包版安装和配置MySQL环境过程

《mysql-8.0.30压缩包版安装和配置MySQL环境过程》该文章介绍了如何在Windows系统中下载、安装和配置MySQL数据库,包括下载地址、解压文件、创建和配置my.ini文件、设置环境变量... 目录压缩包安装配置下载配置环境变量下载和初始化总结压缩包安装配置下载下载地址:https://d

将Python应用部署到生产环境的小技巧分享

《将Python应用部署到生产环境的小技巧分享》文章主要讲述了在将Python应用程序部署到生产环境之前,需要进行的准备工作和最佳实践,包括心态调整、代码审查、测试覆盖率提升、配置文件优化、日志记录完... 目录部署前夜:从开发到生产的心理准备与检查清单环境搭建:打造稳固的应用运行平台自动化流水线:让部署像

springboot整合gateway的详细过程

《springboot整合gateway的详细过程》本文介绍了如何配置和使用SpringCloudGateway构建一个API网关,通过实例代码介绍了springboot整合gateway的过程,需要... 目录1. 添加依赖2. 配置网关路由3. 启用Eureka客户端(可选)4. 创建主应用类5. 自定

C#读取本地网络配置信息全攻略分享

《C#读取本地网络配置信息全攻略分享》在当今数字化时代,网络已深度融入我们生活与工作的方方面面,对于软件开发而言,掌握本地计算机的网络配置信息显得尤为关键,而在C#编程的世界里,我们又该如何巧妙地读取... 目录一、引言二、C# 读取本地网络配置信息的基础准备2.1 引入关键命名空间2.2 理解核心类与方法