利用 _RTC_CheckStackVars(...) 和 windbg 发现访问越界
来源:互联网 发布:linux定时重启服务 编辑:程序博客网 时间:2024/06/03 17:39
背景:在项目 debug 过程中遇到 failwithmessage 函数,但是程序正常运行,判断这个函数应该是类似 exception 之类的功能。查看调用栈,发现是 _RTC_CheckStackVars(...) 引起 failwithmessage 的调用。网上查到这个函数是检查栈变量完整性,很可能程序当中已经发生了访问越界。项目稳定性的要求比较高,需要捉一下虫子。
通过本文可以了解:
1. RTC API (run time check) 的基本原理。
2. 实际分析调用栈的形式。
3. 初步探索windbg调试的一些方法。
代码:猜测是访问越界导致,所以单写了代码越界的代码调试用
int main(){ int a[3] = { 0 }; int b[3] = { 0 }; a[3] = 3; return 0;}
编译,并利用windbg调试,果然出现同样的函数调用栈。第一行是我们可以通过windbg查看的关于调用栈的所有信息。这里选了Addrs和Source args。第一列是每一个函数调用栈栈顶地址。函数名紧接着传进函数的参数的值。我们的调试函数是wmain,单步跟踪可以发现,在wmain完全退出之前(位于renturn之后)调用了_RTC_CheckStackVars。这是一个编译器行为。
图中高亮的函数是我们需要仔细分析的函数。通过搜索visual studio安装文件夹,找到了对应的定义文件。
C:\Program Files\Microsoft Visual Studio 12.0\VC\include\rtcapi.h
/* These unsupported functions are deprecated in native mode and not supported at all in /clr mode */_RTCINTERNAL_DEPRECATED void __fastcall _RTC_CheckStackVars(void *_Esp, _RTC_framedesc *_Fd);/* Compiler generated calls (unlikely to be used, even by power users) *//* Types */typedef struct _RTC_vardesc { int addr; int size; char *name;} _RTC_vardesc;typedef struct _RTC_framedesc { int varCount; _RTC_vardesc *variables;} _RTC_framedesc不太明白,网络搜索知道_RTC_CheckStackVars第一个参数是函数要检查的栈顶地址,第二个参数指向结构体_RTC_framedesc。该结构体第一个参数是压栈的局部变量个数,第二个参数保存局部变量相关信息。分别是变量的栈偏移地址,变量大小和变量的名字。因此我们可以通过地址跳转最终找到出错的变量。
首先查看_RTC_framedesc。0x0002代表检查的栈中变量的个数。0x00281434代表变量信息存储的地址。
接下来查看地址0x00281434以获得变量的信息。
第一个变量的偏移地址是0xffffffec,大小是0x0c,名称存储在0x28144e,可以看到是a(0x61)。第二个变量偏移地址是0xffffffd8,大小是0x0c,名字存储在0x28144c,b(0x62)。最后要找到出错的内存地址:栈顶地址+偏移量,得到是0x16faf8
高地址对应是a的内存,低地址是b。可以看出,对于debug版本,VS不止会为变量分配空间,而且给变量周围包围4个字节的boudary,均初始化成0xcccccccc。但读写越界的时候,这四个字节中的数据被改写,_RTC_CheckStackVars就会发现异常,并调用failwithmessage函数。而且查看该函数的栈空间,会发现Stack arround the variable 'a' corrupted字样。对应图中0x16fb04位置的内存已经从0xcccccccc改成0x03。
最后可以利用上述信息定位错误。重头开始运行程序,在进入main函数入口添加断点。查看变量a的地址是0x163f24,所以a[3]的地址是0x163f30。添加断点
ba w4 0x163f30
表示从0x163f30开始四个字节内的内存被写入时,进入断点。运行程序发现断点停在a[3] = 3。由此我们定位到了访问越界的根源。
相关的知识:
1. windbg的几种断点:bu - defferred breakpoints 每次会根据符号去计算断点地址。因此即使相应的模块还没有被加载,也可以通过它来设置断点。
bp - original breakpoints 通过地址设置断点。
ba - data breakpoints 可以针对指定内存的读写操作(另外一种是对指定代码)设置断点。
bm - set breakpoints using symbol pattern 在设置符号断点的时候可以利用通配符。比如在一个类的成员函数入口都设置断点,bm module!class::*。
2. 为了验证猜想,修该代码为a[3] = 0xcccccccc。这个时候_RTC_CheckStackVars不再报错。
3. 在VS中关闭RTC(runtime check)。
/RTC1 /RTCu /RTCc /RTCs - 编译器开关。
#pragma runtime_checks( "[runtime_checks]", {restore | off} ) - 宏编译开关。
- 利用 _RTC_CheckStackVars(...) 和 windbg 发现访问越界
- 利用 _RTC_CheckStackVars(...) 和 windbg 发现访问越界
- 利用保护页检测内存访问越界
- 越界访问
- 越界访问
- Windbg的gflags.exe调试堆栈溢出,访问越界等问题。
- 利用VMWare和WinDbg调试驱动程序
- 利用VMWare和WinDbg调试驱动程序
- 利用VMWare和WinDbg调试驱动程序
- 利用VMWare和WinDbg调试驱动程序-配置
- 利用VMWare和WinDbg调试驱动程序
- [转载]利用VMWare和WinDbg调试驱动程序
- [转载]利用VMWare和WinDbg调试驱动程序
- 【转帖】利用VMWare和WinDbg调试驱动程序
- 利用VMWare和WinDbg调试驱动程序
- 利用VMWare和WinDbg调试驱动程序
- 利用windbg探索进程和进程上下文
- 利用windbg探索进程和进程上下文
- java的运行算法
- 创建Flash CS3组件(五) 组件的实时预览
- 关于安卓系统
- DSPLINK开发初体验
- Tug of War
- 利用 _RTC_CheckStackVars(...) 和 windbg 发现访问越界
- 继下午的POJ_1644_放苹果的dfs(深度优先搜索)算法解决代码
- swf破解扫盲教程-内存抓取法破解swf加壳
- 社会化分享 SDK
- 证明辗转相除法
- ANSI C(标准C)究竟有多少个头文件?
- Oracle常用sql语句初体验select成功=努力+方法。
- HDU4726
- Android Jelly Bean滑动解锁控件实现