windows的验证机制
发现软件瑕疵的最普遍方法就是测试,常用的测试手段有如下几种:
- 黑盒测试
- 白盒测试
- 内建自检
- 压力测试
虽然以上每种测试都有它的优势和侧重点,但即使用上了以上所有测试手段,也不能保证会发现所有问题。
比如某个程序有轻微的内存泄漏,就很难发现。
比如有些异常需要再比较苛刻的环境下才会出现,但测试时会很难满足。
……
windows操作系统的验证机制(Verifier)就是为了满足这个需求而设计的。
windows 验证机制分为驱动验证器和应用程序验证器,这里主要讲解应用程序验证器。
应用程序验证器工作原理
验证器的基本设计思想是在应用程序调用内核函数时,对应用程序执行各种检查,看其是否符合windows sdk的调用条件和规范。
windows 采用的是通过修改被验证程序的输入地址表(IAT)来挂载(hook)应用程序的api调用。 系统会将被验证驱动程序的IAT表中的api函数地址替换为验证函数的地址。这样,当这个应用程序调用api函数时,便会调用对应的验证函数。
应用检测器组成
位于NTDLL中的支持例程
位于ntdll.dll 中,大多已 AVrf 开头
验证提供器模块
安装验证工具时复制到system32目录下的多个dll文件
应用验证管理器
关于管理验证程序参数的图形界面工具。
执行过程
执行过程是详细讲解是比较复杂的,这里我已简单的doublefree来简单介绍下执行过程。
当函数中执行free时,最终会调用到virtualfree,这时应用验证器实际调用的是AVrfVirtualFree,改函数会调用AVrfVirtualFreeSanityChecks 执行健全性检查……
当第二次对同一个地址进行free时,健全性检查会验证不过,从而主动触发一个异常。
使用应用验证器
下载:链接:https://pan.baidu.com/s/1JKst9CbDKTFROKL0yWsmjg 提取码:7291 ,里面的ApplicationVerifier.x86.msi 和 ApplicationVerifier.amd64.msi
验证项目
目前的验证器设计了6个类别,19个验证项目。
basics
COM | 正确使用组件对象模型(COM) |
Exceptions | 检查非法访问异常 |
handles | 正确使用句柄 |
Heaps | 正确使用堆 |
Locks | 正确使用同步对象 |
Memory | 合理使用虚拟内存 |
RPC | 正确使用rpc |
Threadpool | 正确使用内存池 |
Tls | 正确使用线程局部存储 |
Compatibility(兼容性)
FilesPaths | 正确读取公共目录和使用有个api |
HighVersionLie | 读取版本信息的方式 |
Interactive-service | 验证交互式系统服务 |
KernelMode-DriverInstall | 正确安装内核态驱动程序 |
hangs
hangs | 检测可能导致程序僵死的情况 |
lowRes(低资源模拟)
lowRes | 模拟低资源情况,对分配资源请求返回失败 |
LuaPriv
LuaPriv | 判断在管理员权限可以运行的程序是否也可以在受限账号下正常运行 |
杂项
DangerousAPIs | 检查使用危险api的情况 |
DirtyStacks | 检测使用未初始化局部变量的情况 |
TimeRoolOver | 强制GetTickCount api快速重新计数,已考验是否处理该异常 |
打印
PrintAPI | 正确使用打印API |
PrintDriver | 验证打印驱动程序 |
服务
Service | 验证系统服务 |
doublefree操作举例
安装应用验证
安装后,找到appverif.exe
doublefree代码
1 | int *p = new int[100]; |
不开启应用验证时,程序不会出现异常。
开启应用验证
“file” –>”add application” —>”xxx.exe” (不要在.exe 运行时操作),选择“heaps”
启动 .exe ,然后执行doublefree 程序崩溃。
使用windbg可以查看异常堆栈1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
180:000> kv
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
004feafc 6ade80c8 6aded258 00000007 07041000 vrfcore!VerifierStopMessageEx+0x5b8
004feb20 0fdcdfbe 00000007 0fdc1cac 07041000 vrfcore!VerifierDisableVerifier+0x598
004feb78 0fdcbb9f 00000007 0fdc1cac 07041000 verifier!VerifierStopMessage+0x8e
004febe4 0fdc89bd 07041000 00000000 0a8607ec verifier!VerifierDisableFaultInjectionExclusionRange+0x44af
004fec48 0fdc8b15 07041000 0a6d6e70 00000000 verifier!VerifierDisableFaultInjectionExclusionRange+0x12cd
004fec6c 0fdc8d90 07041000 0a6d6e70 004fed04 verifier!VerifierDisableFaultInjectionExclusionRange+0x1425
004fec88 0fdcadd0 07041000 0a6d6e70 0a8607ec verifier!VerifierDisableFaultInjectionExclusionRange+0x16a0
004feca4 77b72fa1 07040000 01001002 0a6d6e70 verifier!VerifierDisableFaultInjectionExclusionRange+0x36e0
004fed14 77ad2735 0a6d6e70 08ba3c35 00000000 ntdll!RtlpNtSetValueKey+0x3cf1
004fee60 77ad2302 00000000 0a6d6e70 00000111 ntdll!RtlGetCurrentServiceSessionId+0xf5
004feeb4 6adead3b 07040000 00000000 0a6d6e70 ntdll!RtlFreeHeap+0x222
004feed4 71de3c1b 07040000 00000000 0a6d6e70 vrfcore!VerifierSetAPIClassName+0x16b
004fef20 00181660 0a6d6e70 004ff758 0a6d6e70 MSVCR90!free+0xcd
004fef40 78409479 004ff758 004fef68 7840965b TraceMe!CTraceMeDlg::OnBnClickedButton1+0x40 (CONV: thiscall) [c:\users\b41-cx\documents\visual studio 2008\projects\traceme\traceme\tracemedlg.cpp @ 195]
004fef4c 7840965b 000003e9 00000039 00000000 mfc90!_AfxDispatchCmdMsg+0x3b
个人常用方法
- 一般用这个工具来分析踩内存
- 可以在测试环境中验证服务
注意点
- 只能检查native代码
- 程序序正常退出才行,强行杀进程不能得到正确的报告
- 只能做Run-time检测。尽量使用程序的所有功能已保证检测到更多代码
- 开启检测时,性能会下降,内存会升高,不要在生产环境中使用。