栈溢出场景的分析(2)

之前一篇文章<<一种栈溢出的场景分析和建议>>中,本人分享了如何查找程序Crash的函数调用栈,然后通过代码审查找到栈溢出的原因。但是却有一些场景通过代码审查不易找到问题,比如如下两点:

  1. 函数的调用逻辑复杂,且触发逻辑依赖于输入样例。这样通过代码审查是很难看出问题所在的。
  2. 当触发的栈溢出问题在非自己公司开发的第三方库中,无法获取源代码,也不易看出问题。

那么针对上面这两点,都需要一个东西去做辅助分析,那就是触发栈溢出的输入内容(这的所谓输入内容不是指用户在交互界面输入,而是指触发这个栈溢出的数据),无论是自己用这个输入内容来调试栈溢出的触发逻辑,或者是交给第三方库的支持方,都是不可或缺的。

由于这种场景分析距今时间较长,本该在上一篇介绍的内容,便忘记介绍,好记性不如烂笔头。而今日正好又碰到了这种场景,遂记录于此,也与大家一起分享。

程序样例

为了将故事完整性,我重新编写了一段样例代码。记住我们的目标,是根据Crash后收集的dump内容,找到触发这个栈溢出的输入数据。 这个程序是如何触发栈溢出的:

  • 调用的函数是TriggerStackOverFlow
  • 导致栈溢出的递归调用的函数是Func
  • 这里特意设置的触发条件是当输入的数据为Data Trigger StackOverFlow ,只有这个输入的时候才会触发递归调用。实际真实的工程代码也是类似,并不是栈溢出问题必现,而是在特定的情况下才会触发,这也是为什么本文强调的是如何获取触发栈溢出的输入数据如此重要,因为调试问题离不开它。
#include <iostream>
int a = 1;
void Func(const char* pcsPara)
{
  std::cout << pcsPara << " " << ++a << std::endl;
  if (0 == strcmp(pcsPara, "Data Trigger StackOverFlow"))
    Func(pcsPara);
}

void TriggerStackOverFlow()
{
  char csTmpStr[1000] = "Data Trigger StackOverFlow";
  Func(csTmpStr);
}

int main()
{
  TriggerStackOverFlow();
  return 0;
}

找出函数调用栈

一般碰到Crash的Dump,习惯性的都是先用Windbgk命令看下函数调用栈。但是对于这个命令默认只能显示0xff个栈帧,那么我们其实还可以调用k [FrameCount], 这里的FrameCount就是设置为你想显示的栈帧数量,但是查看了最新的Windbg Preview版本最多也只能显示0xffff个栈帧,那么对于超过0xffff的栈帧无法显示。那么本人的就刚好碰到了这种场景(那也是因为我们把默认的栈空间调整到了更大),这个时候就要用到上一篇文章讲解的方法<<一种栈溢出的场景分析和建议>>, 把整个函数调用栈的空间用dps打印出来。不麻烦大家再去看原先的文章,我把这个步骤再做一次,此文不再重新说明。直接说结果,对于上述案例打印出来如下所示。0000004ea14010000000004ea1500000根据!teb得来的栈空间地址范围。

0:000> dps 0000004ea1401000 0000004ea1500000
......
0000004e`a14059a0  00007fff`d1059570 ucrtbase!_argc
0000004e`a14059a8  00007ff7`190d1cd6 StackOverflowFindData!Func+0x46 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 5]
0000004e`a14059b0  00007fff`c98c5080 MSVCP140!std::cout
0000004e`a14059b8  00007ff7`190d7bb0 StackOverflowFindData!__xt_z+0x110
0000004e`a14059c0  0000004e`00000000
0000004e`a14059c8  00007ff7`190d7bf3 StackOverflowFindData!__xt_z+0x153
0000004e`a14059d0  00007fff`d1059570 ucrtbase!_argc
0000004e`a14059d8  00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
0000004e`a14059e0  0000004e`a14ff8d0
......
0000004e`a14ff3b8  00007ff7`190d7bf3 StackOverflowFindData!__xt_z+0x153
0000004e`a14ff3c0  00007fff`d1059570 ucrtbase!_argc
0000004e`a14ff3c8  00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
0000004e`a14ff3d0  0000004e`a14ff8d0
0000004e`a14ff3d8  00007ff7`190d7bb0 StackOverflowFindData!__xt_z+0x110
0000004e`a14ff3e0  0000004e`00000000
0000004e`a14ff3e8  00007ff7`190d7bf3 StackOverflowFindData!__xt_z+0x153
0000004e`a14ff3f0  00007fff`d1059570 ucrtbase!_argc
0000004e`a14ff3f8  00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
0000004e`a14ff400  0000004e`a14ff8d0
0000004e`a14ff408  00007ff7`190d7bb0 StackOverflowFindData!__xt_z+0x110
0000004e`a14ff410  0000004e`00000000
0000004e`a14ff418  00007ff7`190d7bf3 StackOverflowFindData!__xt_z+0x153
0000004e`a14ff420  00007fff`d1059570 ucrtbase!_argc
0000004e`a14ff428  00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
0000004e`a14ff430  0000004e`a14ff8d0
0000004e`a14ff438  00007ff7`190d7bb0 StackOverflowFindData!__xt_z+0x110
......
0000004e`a14ff860  0000004e`00000000
0000004e`a14ff868  00007ff7`190d7bf3 StackOverflowFindData!__xt_z+0x153
0000004e`a14ff870  00007fff`d1059570 ucrtbase!_argc
0000004e`a14ff878  00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
0000004e`a14ff880  0000004e`a14ff8d0
0000004e`a14ff888  00007ff7`190d7bb0 StackOverflowFindData!__xt_z+0x110
0000004e`a14ff890  00000000`00000000
0000004e`a14ff898  00000000`4000006a
0000004e`a14ff8a0  00000000`00000001
0000004e`a14ff8a8  00007ff7`190d1d80 StackOverflowFindData!TriggerStackOverFlow+0x50 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 14]
......
0000004e`a14ffcc0  00002372`af0f3fac
0000004e`a14ffcc8  00000000`00000000
0000004e`a14ffcd0  00000000`00000044
0000004e`a14ffcd8  0000015e`fd10d100
0000004e`a14ffce0  00000000`00000000
0000004e`a14ffce8  00007ff7`190d1e49 StackOverflowFindData!main+0x9 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 18]
0000004e`a14ffcf0  00000000`0000001f
......

因为是样例程序,可能看不出问题的重点。这里不妨假设一下Func是一个第三方库的函数,如果通过k [FrameCount] 最多打印的函数调用栈也只能看到Func调用,却看不到是自己编写的程序哪里触发调用了Func,尤其是多处调用了第三方库的Func,甚至是调用了第三方库接口后,间接再调用了第三方库里的Func。那么通过上述方法就能够确定到,原来是我们自己编写的代码TriggerStackOverFlow调用了这个函数。

找到了触发的函数,那么这个时候没有栈帧编号,也无法用.frame [FrameNumber]去切换到TriggerStackOverFlow去直接查看函数调用中的一些参数或者局部变量的值了。那么我们接着下一章,讲一讲如何获取。

查找触发栈溢出的输入数据

在上一章的提到的情况下,可以设置BasePtr来设置栈帧: .frame /c /r = BasePtr

这个笔者测试过,并不是所有的地址都可以获取到正确的函数调用栈,在不确定的时候,可以在栈底附近的多个函数调用栈帧的地址都做尝试。比如笔者测试的地址位置如下:

0:000> .frame /c /r = 0000004e`a14ff400
00 0000004e`a14ff400 00007ff7`190d7bb0 KERNELBASE!WriteFile+0x73
rax=0000004ea1404040 rbx=0000004ea1404090 rcx=0000000000000058
rdx=0000000000000000 rsi=0000000000000058 rdi=0000000000000000
rip=00007fffd10a2573 rsp=0000004ea14ff400 rbp=0000004ea14055c1
 r8=0000000000000000  r9=0000000000000000 r10=0000000000000000
r11=0000004ea14040a0 r12=0000000000000040 r13=0000000000000000
r14=0000000000000058 r15=0000000000000001
iopl=0         nv up ei pl zr na po nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
KERNELBASE!WriteFile+0x73:
00007fff`d10a2573 ff152f0a1500    call    qword ptr [KERNELBASE!_imp_NtWriteFile (00007fff`d11f2fa8)] ds:00007fff`d11f2fa8={ntdll!NtWriteFile (00007fff`d4a5abc0)}

紧接着查看函数调用栈,查看新的栈帧。栈帧0x1b对应了函数调用TriggerStackOverFlow

0:000> k
  *** Stack trace for last set context - .thread/.cxr resets it
 # Child-SP          RetAddr           Call Site
00 0000004e`a14ff400 00007ff7`190d7bb0 KERNELBASE!WriteFile+0x73
01 0000004e`a14ff470 0000004e`00000000 StackOverflowFindData!__xt_z+0x110
02 0000004e`a14ff478 00007ff7`190d7bf3 0x0000004e`00000000
03 0000004e`a14ff480 00007fff`d1059570 StackOverflowFindData!__xt_z+0x153
04 0000004e`a14ff488 00007ff7`190d1d05 ucrtbase!_argc
05 0000004e`a14ff490 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
06 0000004e`a14ff4c0 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
07 0000004e`a14ff4f0 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
08 0000004e`a14ff520 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
09 0000004e`a14ff550 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
0a 0000004e`a14ff580 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
0b 0000004e`a14ff5b0 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
0c 0000004e`a14ff5e0 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
0d 0000004e`a14ff610 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
0e 0000004e`a14ff640 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
0f 0000004e`a14ff670 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
10 0000004e`a14ff6a0 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
11 0000004e`a14ff6d0 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
12 0000004e`a14ff700 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
13 0000004e`a14ff730 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
14 0000004e`a14ff760 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
15 0000004e`a14ff790 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
16 0000004e`a14ff7c0 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
17 0000004e`a14ff7f0 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
18 0000004e`a14ff820 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
19 0000004e`a14ff850 00007ff7`190d1d05 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
1a 0000004e`a14ff880 00007ff7`190d1d80 StackOverflowFindData!Func+0x75 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 8]
1b 0000004e`a14ff8b0 00007ff7`190d1e49 StackOverflowFindData!TriggerStackOverFlow+0x50 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 14]
1c 0000004e`a14ffcf0 00007ff7`190d227c StackOverflowFindData!main+0x9 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 18]
1d (Inline Function) --------`-------- StackOverflowFindData!invoke_main+0x22 [d:\agent\_work\2\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 78]
1e 0000004e`a14ffd20 00007fff`d41c4034 StackOverflowFindData!__scrt_common_main_seh+0x10c [d:\agent\_work\2\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 288]
1f 0000004e`a14ffd60 00007fff`d4a33691 KERNEL32!BaseThreadInitThunk+0x14
20 0000004e`a14ffd90 00000000`00000000 ntdll!RtlUserThreadStart+0x21

然后我们切换到栈帧TriggerStackOverFlow,并且查看局部变量的信息:

0:000> .frame 1b; dv /v /t
1b 0000004e`a14ff8b0 00007ff7`190d1e49 StackOverflowFindData!TriggerStackOverFlow+0x50 [c:\personal\sync\beyourbest\cpp\windbgsample\stackoverflowfinddata\source.cpp @ 14]
0000004e`a14ff8d0 char [1000] csTmpStr = char [1000] "Data Trigger StackOverFlow"

此时我们终于查找到了触发栈溢出的输入数据。这个例子是一个字符串,但是也有可能你的输入数据是一段二进制,比如一个读入到内存的文件。那么这个时候并不会像字符串一样直观,需要导出来。这个时候可以利用.writemem这个命令,以这个字符串为例,我们可以操作如下,便把这1000个字节的内容全部导出到文件sample.txt中了。

0:000> .writemem c:\\test\\sample.txt 0000004e`a14ff8d0 L?0n1000
Writing 3e8 bytes.

既然触发栈溢出的数据已经导出,那么根据这个数据重现、调试,便比较容易找出逻辑bug所在了。

本文分享自微信公众号 - 一个程序员的修炼之路(CoderStudyShare),作者:河边一枝柳

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-05-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 一种栈溢出的场景分析和建议

    有时候当你收到一个dump后,大多数情况可以通过k命令查找到导致栈溢出的函数。但是本文要讲的是,曾经碰到过的栈溢出(stackoverflow), 却无法直接通...

    河边一枝柳
  • 0Day技术分析-2-栈溢出原理

    栈溢出原理 1 什么是栈 1.1. 缓冲区 我们向一个杯子里倒水,如果我们倒的水超出了杯子的容量,水就会溢出来。 在我们写程序的时候也可能会用到一些临时的变量 ...

    zhisheng
  • 理论:第十三章:堆溢出,栈溢出的出现场景以及解决方案

    设计一个堆溢出的程序:https://blog.csdn.net/java_wxid/article/details/103021907

    java_wxid
  • Netgear R6400 upnp栈溢出漏洞分析

    Netgear R6400 多个固件版本中的upnpd存在栈溢出漏洞(CVE-2020-9373),通过向其udp 1900端口发送构造的ssdp数据包,可能导...

    FB客服
  • 经典栈溢出之MS060-040漏洞分析

    七夜安全博客
  • Linux漏洞分析入门笔记-栈溢出

    1. 在进行远程调试之前需要对Linux平台进行一些准备工作。在IDA的安装目录中的dbgsrv文件夹中,选择linux_server或者linux_serve...

    我是小三
  • 分析某旺的ActiveX控件ImageMan.dll栈溢出漏洞

    阿里旺旺的ActiveX控件ImageMan.dll动态链接库中有一个函数AutoPic,由于未对传入的参数长度进行校验导致栈溢出,在拷贝缓冲区数据时会读取到不...

    迅达集团
  • 程序员进阶系列:OOM 都搞不定,还敢妄称自己Java高级攻城狮?

    正式开讲之前,先罗列一下所知的 OutOfMemoryError (简称 OOM)异常,看看这些异常工作中你是否也遇到过?

    一猿小讲
  • CVE-2020-3119 Cisco CDP 协议栈溢出漏洞分析

    Cisco Discovery Protocol(CDP)协议是用来发现局域网中的Cisco设备的链路层协议。

    Seebug漏洞平台
  • 『JVM』我不想知道我是怎么来滴,我就想知道我是怎么没滴

    所谓的 JVM 崩溃,一般情况下就是指内存溢出,也就是 OutOfMemoryError 和 StackOverflowError。另外还有一种情况就是堆外内存...

    古时的风筝
  • 【性能优化】纳尼?内存又溢出了?!是时候总结一波了!!

    这里,我将在平时工作过程中总结的内存溢出的情况,以代码案例的形式直观的分享给大家,希望能够为小伙伴们带来实质性的帮助。

    冰河
  • CVE-2017-7529 Nginx整数溢出漏洞分析2

    正常情况下,如果我们 传入一串完整的range,那么他会检查 start,保证不会溢出为负值

    Elapse
  • Java 虚拟机 4:内存溢出

    Java堆唯一的作用就是存储对象实例,只要保证不断创建对象并且对象不被回收,那么对象数量达到最大堆容量限制后就会产生内存溢出异常了。所以测试的时候把堆的大小固定...

    用户1257393
  • 手写实现深度拷贝

    那么,对一个对象进行拷贝,无非就是对对象的属性进行拷贝,按照拷贝处理的方式不同,可分为浅拷贝和深拷贝:

    请叫我大苏
  • Flexera FlexNet Publisher中基于栈的缓冲区溢出漏洞分析

    近日,安全人员在Flexera FlexNet Publisher(License Manager)中发现了一个基于栈的缓冲区溢出漏洞(CVE编号:CVE-20...

    FB客服
  • Java多线程编程-(11)-面试常客ThreadLocal出现OOM内存溢出的场景和原理分析

    1、首先看一下代码,模拟了一个线程数为500的线程池,所有线程共享一个ThreadLocal变量,每一个线程执行的时候插入一个大的List集合:

    Java后端技术
  • 基于栈和队列实现括号匹配算法

    视频 http://study.163.com/course/courseLearn.htm?courseId=555010#/learn/video?l...

    陈黎栋
  • Vivotek 摄像头远程栈溢出漏洞分析及利用

    近日,Vivotek 旗下多款摄像头被曝出远程未授权栈溢出漏洞,攻击者发送特定数据可导致摄像头进程崩溃。

    Seebug漏洞平台
  • Vivotek 摄像头远程栈溢出漏洞分析及利用

    作者:fenix@知道创宇404实验室 前 言 近日,Vivotek 旗下多款摄像头被曝出远程未授权栈溢出漏洞,攻击者发送特定数据可导致摄像头进程崩溃。 ...

    Seebug漏洞平台

扫码关注云+社区

领取腾讯云代金券