35、应用验证器测试设置与调试技术全解析

应用验证器测试设置与调试技术全解析

1. LuaPriv 测试设置

LuaPriv 测试设置全称为有限用户账户预测器(Limited User Account Predictor),主要有两个用途:
- 预测应用程序是否能够以降低的权限集(如普通用户)运行。
- 确定应用程序在以降低的权限集(普通用户)运行时可能出现的问题。

默认情况下,所有与有限用户账户相关的停止代码在触发时不会导致调试器中断,而是将停止代码和违规堆栈跟踪记录在日志文件中。以下是该测试设置定义的停止代码及其说明:
| 停止代码 | 测试 | 描述 |
| — | — | — |
| 00003300 | 名称规范化失败 | 当应用验证器尝试对对象名称进行规范化但失败时触发此停止。 |
| 00003301 | 无法找到规范名称 | 应用验证器无法找到对象的规范名称时触发。 |
| 00003302 | 无法打开对象 | 由于尝试打开对象时出错,应用验证器无法获取对象信息时触发。 |
| 00003303 | HKEY_CURRENT_USER | 应用验证器无法解释 HKEY_CURRENT_USER 注册表项时触发,因此该注册表项下的注册表项必须标记为受限。 |
| 00003304 | USERPROFILE | 如果未找到 USERPROFILE 环境变量,则触发此停止,这可能导致应用验证器认为当前用户的配置文件不可用,并将某些文件和目录列为受限。 |
| 00003305 | 安全对象 | 应用验证器认为对象是安全的时触发。 |
| 00003306 | 列出的对象命名空间 | 应用验证器遇到列出的命名空间中的对象时触发,标准用户无法写入此命名空间。 |
| 00003307 | 无命名空间 | 对象在未指定命名空间的情况下创建,导致其在全局命名空间中创建,标准用户无法写入该命名空间。 |
| 00003308 | 文件/目录位置 | 应用验证器尝试定位文件或目录但失败时生成此停止。 |
| 00003309 | 无法打开父对象 | 应用验证器在尝试确定标准用户是否能够创建子对象时,无法打开父对象。 |
| 0000330A | 以管理员身份运行 | 应用验证器检测到应用程序以管理员身份运行,这只是为了确保以标准用户身份测试的场景不会意外以管理员身份运行的信息。 |
| 0000330B | 安全标识符转换失败 | 应用验证器无法将安全标识符(SID)的可读形式转换为 Windows 内部形式。 |
| 0000330C | GetTokenInformation 请求 | 应用程序调用 GetTokenInformation API 请求列出的信息类,尽管这在标准用户下可能有效,但通常意味着应用程序应作为管理员运行。 |
| 0000330D | 权限不存在 | 正在检查的权限在应用程序运行的 Windows 版本上不存在。 |
| 0000330E | 权限查找失败 | 应用验证器通过 LUID 查找指定权限失败。 |
| 0000330F | 成功的权限请求 | 应用程序请求并获得标准用户未被授予的权限。 |
| 00003310 | 失败的权限请求 | 应用程序请求标准用户未被授予的权限失败。 |
| 00003311 | 成功访问列出的权限 | 应用程序以标准用户身份启动并有权访问列出的权限。 |
| 00003312 | 访问列出的权限失败 | 应用程序以无权限访问列出权限的用户身份启动,尽管权限查找成功。 |
| 00003313 | 无权限访问列出的权限 | 应用程序以无权限访问列出权限的用户身份启动。 |
| 00003314 | 注册表查询失败 | 应用验证器尝试查询注册表值但未成功。 |
| 00003315 | INI 文件注册表映射 | 应用程序使用映射到注册表项的 INI 文件,且 INI 文件的语法未知。 |
| 00003316 | 配置文件访问失败 | 应用程序尝试访问给定配置文件但失败。 |
| 00003317 | 授予对象访问权限 | 应用程序被授予对指定对象的访问权限,标准用户应该能够访问该对象。 |
| 00003318 | 授予对象访问权限 | 应用程序被授予对指定对象的访问权限,标准用户可能无法访问该对象。 |
| 00003319 | 安全描述符转换失败 | 应用验证器尝试将安全描述符转换为可读形式但失败。 |
| 0000331A | 对象访问失败 | 应用程序请求访问对象但被拒绝。 |
| 0000331B | 对象访问 | 应用程序请求访问仅授予受信任用户的对象。 |
| 0000331C | 对象访问 | 应用程序请求访问仅授予受信任用户的对象,此消息后总是跟随其他消息。 |
| 0000331D | 对象访问 | 应用程序请求访问仅授予特权用户和对象所有者的对象。 |
| 0000331E | 对象访问 | 应用程序请求访问至少授予一个非特权用户的对象。 |
| 0000331F | 对象访问 | 应用程序请求访问不授予任何人的对象。 |
| 00003320 | 安全描述符分析 | 应用验证器尝试对对象的安全描述符进行分析,将其拆分为各个部分但失败。 |
| 00003321 | 安全描述符分析 | 应用验证器尝试分析对象安全描述符自由访问列表中的 ACL 但失败。 |
| 00003322 | 对象访问 | 应用程序请求对对象的最大允许访问权限,应用验证器决定将应用程序视为实际上需要所有对象权限进行分析。 |
| 00003323 | 对象访问 | 应用程序请求对对象的最大允许访问权限,应用验证器尝试确定应用程序实际需要的权限但失败。 |
| 00003324 | 未知权限 | 应用程序请求的权限是应用验证器未知的。 |
| 00003325 | 配置文件 | 应用程序被授予对配置文件的访问权限。 |
| 00003326 | 安全标识符 | 应用程序查询 Windows 列出的安全标识符是否是用户令牌的一部分,此操作通常仅限于列出组中的用户。 |
| 00003327 | 安全标识符 | 应用程序查询 Windows 列出的安全标识符(SID)是否是用户令牌的一部分,尽管该 SID 无法识别。 |
| 00003328 | 配置文件 | 应用程序调用 WriteProfile API 时输入的内容在作为标准用户运行时可能失败。 |

2. DangerousAPIs 测试设置

Win32 中的许多 API 非常强大,使用时必须格外小心,以避免可能出现的问题。此测试设置用于检查对这些危险 API 的调用。默认情况下,所有与危险 API 相关的停止代码在触发时会导致调试器中断。具体停止代码如下:
| 停止代码 | 测试 | 描述 |
| — | — | — |
| 00000100 | TerminateThread | 如果应用程序使用 TerminateThread API 终止线程,则触发此停止,TerminateThread 很可能导致死锁和数据损坏等问题。 |
| 00000101 | 堆栈提交大小 | 如果应用程序的堆栈大小设置为在可能引发堆栈溢出异常的情况下(低内存条件)不允许堆栈增长,则触发此停止。 |
| 00000102 | ExitProcess | 如果应用程序使用 ExitProcess API 终止正在运行多个线程的进程,则触发此停止,ExitProcess 内部使用 TerminateThread API,可能导致稳定性问题。 |
| 00000103 | LoadLibrary | 如果应用程序在 DllMain 函数中调用 LoadLibrary,则触发此停止,从 DllMain 函数调用此 API 可能导致崩溃或死锁。 |
| 00000104 | FreeLibrary | 如果应用程序在 DllMain 函数中调用 FreeLibrary,则触发此停止,从 DllMain 函数调用此 API 可能导致崩溃或死锁。 |

此测试设置有一个可更改的属性(DllMainCheck),如果将此属性设置为 TRUE,则测试设置会捕获从 DllMain 到 LoadLibrary 或 FreeLibrary API 的任何调用。

3. DirtyStacks 测试设置

未初始化的堆栈变量,尤其是未初始化的堆栈指针,是常见的 bug 来源。为了捕获此类 bug,此测试设置会定期用特定模式填充堆栈的未使用部分。当应用程序尝试使用未初始化的变量时,由于访问被视为无效内存访问的填充模式初始化的内存,可能会导致访问冲突。此测试设置会引发异常而不是硬停止。

4. TimeRollOver 测试设置

在使用 GetTickCount 和 TimeGetTime API 时,开发人员必须处理溢出情况。为了测试溢出情况,需要能够快速触发溢出。此测试设置允许你控制溢出发生的时间,没有实际的停止代码,而是有一个名为 Delay 的测试设置属性,可以设置为指示溢出发生前延迟的秒数。

5. PrintAPI 和 PrintDriver 测试设置

在使用打印 API 时可能会出现许多问题,PrintAPI 测试设置和 PrintDriver 测试设置可以进行一系列测试,以确保正确使用这些 API。

6. 调试器相关内容

6.1 调试器类型与配置

  • 用户模式调试器 :配置包括将其附加到正在运行的进程(可非侵入式附加)、设置事件控制(如创建进程、线程等事件)、异常控制等。其事件处理遵循一定的顺序和机制,并且可以通过内核调试器重定向输出。
  • 内核模式调试器 :需要进行选择、配置和连接等操作,例如启用 Virtual PC 以支持内核模式调试。在 Windows Vista 中,其地址空间布局有特定特点。

6.2 调试器功能

  • 代码断点 :可以设置代码断点,包括条件断点,用于检测引用释放等情况。
  • 代码执行跟踪 :能够跟踪代码的执行过程,包括单步执行和跨函数执行等。
  • 内存检查 :可以检查内存内容、变量值等。
  • 符号管理 :涉及符号缓存、符号文件、符号服务器等的管理和使用。

6.3 调试命令

调试器有丰富的命令,如 !address ba d dt 等,这些命令用于不同的调试目的,如查看地址信息、设置访问断点、查看内存内容、查看数据结构等。

6.4 调试场景

  • 64 位调试 :涉及 64 位操作系统、处理器和应用程序的调试,包括使用特定的调试工具和命令,处理内存腐败和安全问题等。
  • 远程调试 :需要使用调试服务器、内核服务器和进程服务器等,进行源文件和符号的解析。
  • 内存腐败调试 :包括内存腐败的检测过程(如使用检测工具、分析源代码等)和避免策略。
  • 死锁调试 :分析应用程序中的死锁问题,如检测和解决死锁的方法。

6.5 调试工具

  • Debug Diagnostic Tool :可以设置崩溃规则、挂起规则和泄漏规则等,用于分析处理泄漏和内存泄漏等问题,还可以编写自定义分析脚本。
  • Application Verifier :有多种测试设置,可用于检测应用程序的各种问题。

6.6 事件和异常处理

  • 事件控制 :用户模式调试器可以控制事件的发生和处理,包括事件的调整和检查。
  • 异常控制 :处理结构化异常分发机制,包括异常的调度和控制。

6.7 调试器扩展

可以编写自定义调试器扩展,包括 C++ 二进制树实现、代码组织、命令取消等功能,还需要进行初始化和版本管理。

7. 其他相关内容

7.1 安全相关

  • 访问控制 :涉及 Windows Vista 中的访问控制及其副作用,以及访问令牌的管理。
  • 安全描述符 :包括安全描述符的解码和分析。
  • 安全标识符 :应用程序对安全标识符的查询和使用。

7.2 数据结构和算法

  • 堆分配 :包括前端和后端分配器,以及内存块的分配和释放。
  • 临界区 :用于线程同步,包括临界区的管理和使用。

7.3 网络通信

  • 进程间通信 :有多种通信机制,如 LPC 协议,并且可以进行调试。
  • 网络流量分析 :使用工具进行网络流量的分析。

7.4 对话框相关

  • Dr. Watson 对话框 :包含应用程序错误、崩溃转储、模块列表等信息。

7.5 代码示例

文档中还包含了许多代码示例,如汇编代码(ProcA 过程、Sum 函数等)、C++ 代码(如 C++ 二进制树实现)等,用于说明相关的概念和操作。

通过以上对各种测试设置和调试技术的介绍,可以帮助开发人员更好地进行应用程序的开发和调试,提高应用程序的稳定性和安全性。

8. 具体调试操作流程

8.1 启动调试流程

以下是一个使用调试器对应用程序进行调试的通用流程:

graph TD
    A[选择调试器类型] --> B{用户模式调试器}
    A --> C{内核模式调试器}
    B --> D[配置调试器]
    C --> E[选择、配置和连接内核调试器]
    D --> F[附加到运行进程或启动新进程]
    E --> F
    F --> G[设置断点和事件监控]
    G --> H[开始调试]
    H --> I{发现问题}
    I -->|是| J[分析问题并解决]
    I -->|否| K[结束调试]
    J --> H

8.2 调试过程中的操作步骤

  1. 设置断点
    - 代码断点:使用调试器命令(如 bp )在代码中指定位置设置断点。例如,要在函数 Func 入口处设置断点,可以使用 bp Func 命令。
    - 条件断点:可以设置带有条件的断点,例如 bp Func "if (arg1 == 10) {g}" ,表示当参数 arg1 等于 10 时触发断点。
  2. 查看内存和变量
    - 使用 d 命令查看内存内容,如 d 0x12345678 查看地址 0x12345678 处的内存。
    - 使用 dv 命令查看局部变量值, dt 命令查看数据结构。
  3. 控制程序执行
    - p 命令单步执行代码, t 命令进入函数内部单步执行。
    - g 命令继续执行程序直到下一个断点。

8.3 调试不同场景的注意事项

  1. 64 位调试
    - 确保使用支持 64 位调试的工具,如 Debugging Tools for Windows。
    - 注意 64 位系统的内存布局和指针大小与 32 位系统的差异。
  2. 远程调试
    - 配置好调试服务器、内核服务器和进程服务器,确保网络连接正常。
    - 正确设置源文件和符号文件的路径,以便在调试时能够正确解析。
  3. 内存腐败调试
    - 使用内存检测工具,如 Application Verifier 的相关测试设置。
    - 分析源代码,查找可能导致内存腐败的问题,如越界访问、未初始化指针等。

9. 调试工具的使用技巧

9.1 Debug Diagnostic Tool

  1. 设置规则
    - 崩溃规则 :用于在应用程序崩溃时收集信息。可以设置崩溃触发条件,如特定的异常代码。
    - 挂起规则 :当应用程序无响应时触发,可收集进程的状态信息。
    - 泄漏规则 :监测内存泄漏和句柄泄漏等问题。
  2. 编写自定义分析脚本
    - 可以使用脚本语言编写自定义分析脚本,对收集到的数据进行更深入的分析。例如,分析内存泄漏的具体对象和调用栈。

9.2 Application Verifier

  1. 选择测试设置
    根据应用程序的特点和可能出现的问题,选择合适的测试设置。例如,如果应用程序涉及权限操作,可以启用 LuaPriv 测试设置。
  2. 查看测试结果
    - 当测试设置触发停止代码时,查看日志文件中的停止代码和堆栈跟踪信息,分析问题所在。

9.3 调试器命令使用技巧

  1. 组合命令 :可以将多个调试器命令组合使用,提高调试效率。例如,使用 !address;!heap 一次性查看地址信息和堆信息。
  2. 使用别名 :为常用的命令或复杂的命令组合设置别名,方便快速输入。

10. 常见问题及解决方案

10.1 内存腐败问题

  • 问题表现 :应用程序崩溃、数据损坏等。
  • 解决方案
    • 使用内存检测工具,如 Application Verifier 检测内存越界、未初始化指针等问题。
    • 对源代码进行静态分析,查找可能的内存操作错误。
    • 增加内存边界检查代码,如使用 BUFFER_OVERFLOW_CHECKS 环境变量。

10.2 死锁问题

  • 问题表现 :应用程序无响应,线程无法继续执行。
  • 解决方案
    • 分析线程的调用栈,找出可能的死锁循环。
    • 使用临界区和锁的正确管理方法,避免嵌套锁导致的死锁。

10.3 权限问题

  • 问题表现 :应用程序无法访问某些资源或执行某些操作。
  • 解决方案
    • 使用 LuaPriv 测试设置检测应用程序的权限需求,确保以正确的权限运行。
    • 检查注册表项和文件的访问权限,确保应用程序有足够的权限。

11. 总结

通过对应用验证器的各种测试设置(如 LuaPriv、DangerousAPIs 等)以及调试器相关技术(包括调试器类型、功能、命令和调试场景等)的详细介绍,我们可以看到在应用程序开发和调试过程中,这些工具和技术能够帮助我们发现和解决各种问题,如内存腐败、死锁、权限问题等。同时,掌握调试工具的使用技巧和常见问题的解决方案,能够提高调试效率,确保应用程序的稳定性和安全性。在实际开发中,开发人员应根据应用程序的特点和需求,合理选择和使用这些工具和技术,不断优化应用程序的性能和质量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值