有意的缓冲区溢出并不总是导致程序崩溃

2024-02-12

考虑以下最小 C 程序:

案例编号1:

#include <stdio.h>
#include <string.h>

void foo(char* s)
{
    char buffer[10];
    strcpy(buffer,s);
}

int main(void)
{
    foo("01234567890134567");
}

这不会导致崩溃转储

如果只添加一个字符,则新的 main 为:

案例编号 2:

void main()
{
    foo("012345678901345678");
                          ^   
}

程序因分段错误而崩溃。

看起来除了堆栈中保留的 10 个字符之外,还有额外的空间可容纳 8 个额外的字符。因此第一个程序不会崩溃。但是,如果您再添加一个字符,您就会开始访问无效内存。我的问题是:

  1. 为什么我们要在堆栈中保留这额外的 8 个字符?
  2. 这是否与内存中的 char 数据类型对齐有关?

在这种情况下,我的另一个疑问是操作系统(在本例中为 Windows)如何检测错误的内存访问?通常根据 Windows 文档,默认堆栈大小为 1MB堆栈大小 https://msdn.microsoft.com/en-us/library/windows/desktop/ms686774(v=vs.85).aspx。所以我不明白操作系统如何检测到正在访问的地址位于进程内存之外,特别是当最小页面大小通常为 4k 时。在这种情况下,操作系统是否使用 SP 来检查地址?

PD:我使用以下环境进行测试
Cygwin
海湾合作委员会 4.8.3
Windows 7操作系统

EDIT:

这是生成的程序集http://gcc.godbolt.org/# http://gcc.godbolt.org/#但使用 GCC 4.8.2,我在可用编译器中看不到 GCC 4.8.3。但我想生成的代码应该是类似的。我构建的代码没有任何标志。我希望具有汇编专业知识的人能够阐明 foo 函数中发生的情况以及为什么额外的字符会导致 seg 错误

    foo(char*):
    pushq   %rbp
    movq    %rsp, %rbp
    subq    $48, %rsp
    movq    %rdi, -40(%rbp)
    movq    %fs:40, %rax
    movq    %rax, -8(%rbp)
    xorl    %eax, %eax
    movq    -40(%rbp), %rdx
    leaq    -32(%rbp), %rax
    movq    %rdx, %rsi
    movq    %rax, %rdi
    call    strcpy
    movq    -8(%rbp), %rax
    xorq    %fs:40, %rax
    je  .L2
    call    __stack_chk_fail
.L2:
    leave
    ret
.LC0:
    .string "01234567890134567"
main:
    pushq   %rbp
    movq    %rsp, %rbp
    movl    $.LC0, %edi
    call    foo(char*)
    movl    $0, %eax
    popq    %rbp
    ret

我相信您明白您已经实施了一些导致未定义行为的事情。因此很难回答为什么它会因额外的字符串而失败而不会因原始字符串而失败。它可能与内部编译器实现有关+受编译标志(如对齐、优化等)的影响。

您可以尝试反汇编二进制文件或创建汇编代码,然后查看缓冲区到底放置在堆栈上的位置。您可以对不同的优化级别执行相同的操作,以检查汇编代码和行为的更改。

操作系统(在本例中为 Windows)如何检测错误的内存访问? 通常,根据 Windows 文档,默认堆栈大小为 1MB 堆栈大小。所以我不明白操作系统如何检测该地址 被访问的是进程内存之外,特别是当 最小页面大小通常为 4k。在这种情况下操作系统是否使用 SP 检查地址?

操作系统不会监视您执行的代码。硬件(CPU)执行此操作(因为它执行此代码)。一旦您的代码尝试访问未分配给您的进程的地址(未分配给您的进程)由操作系统映射 https://en.wikipedia.org/wiki/Virtual_address_space对于您的程序)操作系统将收到指示,因为硬件将触发#PF(页面错误)异常。另一种情况是,您尝试访问为您分配的地址,但权限不正确(例如,您尝试从没有“执行”权限的数据页执行二进制数据)或转到代码页,但权限错误偏移量和您读取的指令不存在,或者(更糟糕)它存在并解码为您不期望的东西(我们之前说过未定义的行为吗?)。

一般来说,您的代码很可能不会失败strcpy(如果您写入足够的数据来访问某些禁止的地址,则可以,但很可能情况并非如此) - 当它从foo功能。strcpy只是覆盖了指向下一条指令的下一条指令指针foo功能。因此指令指针填充了“012345678901345678”字符串中的数据,并尝试从“垃圾”地址获取下一条指令,但由于上述原因而失败。

这个“方法”/错误被称为“缓冲区溢出攻击 https://en.wikipedia.org/wiki/Buffer_overflow”并在黑客中广泛使用,使您的代码(更常见的是以更高权限执行的 OS/BIOS/VMM/SMM 代码)执行黑客提供的恶意代码。只需确保使用指令的地址覆盖指令指针即可您提前准备的代码。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

有意的缓冲区溢出并不总是导致程序崩溃 的相关文章

  • C# 中直接从 URL 获取图像尺寸

    我正在尝试使用以下代码直接从网络上获取图片的尺寸 string image http www hephaestusproject com csharp3 png byte imageData new WebClient DownloadDa
  • C++ 中的“int”默认是“signed long int”吗?

    Is int默认情况下signed long int in C 它是否依赖于平台和 或编译器 如果是这样 怎么办 EDIT 以下任何一项是否保证是重复的 signed short int signed int signed long int
  • JetBrains Rider 针对 4.5 框架,无法切换到 4.7

    基本上 当尝试添加不支持旧框架的 NuGet 包时 会出现错误 但是在项目配置中只有 4 5 可用 在项目创建过程中 不存在选择目标的选项 有什么方法可以正确配置它吗 I haven t found out how to set up NE
  • 使用 GCHandle 将大型结构数组从 C# unity 脚本传递到 C++ dll 在 C++ 函数执行后崩溃

    我想从 C unity 脚本将结构数组传递给 c 本机插件 我做了如下操作 我可以访问数据 但我的应用程序在执行 c 函数后崩溃 我不知道为什么 C side StructLayout LayoutKind Sequential publi
  • 如何部署包含第三方 DLL 文件的 C# 应用程序?

    首先 我对部署了解不多 我希望我的问题有意义 我需要将 C 应用程序安装 部署到多个桌面 它需要一个第三方 DLL 文件 一个 C 库 lpsolve55 dll 对于那些感兴趣的人 它是一个免费的 MIP LP 求解器 请参阅 lpsol
  • 尽管浮点数相同,但它们并不相等? [复制]

    这个问题在这里已经有答案了 下面的程序输出This No is not same 当两个数字相同时为什么会这样做 void main float f 2 7 if f 2 7 printf This No is same else prin
  • 如何在 ASP.NET Core 6.0 Web API 项目中启用 cors?

    在我的 ASP NET Core 6 0 Web API 项目中配置了 CORS 但预检请求收到 http 405 错误 换句话说 不允许使用 HTTP OPTION 看起来 cors 没有启用 我见过的例子config EnableCor
  • C语言中没有循环可以打印数组吗?

    例如 在Python中 如果我们将一个列表作为数组 它会直接用一行代码打印整个数组 有什么办法可以用C语言实现同样的事情吗 简短回答 No 对表格上几乎所有问题的简短回答 用 C 语言做 X 工作能像用 Python 一样简单吗 No 长答
  • 使用默认行为将模型绑定到接口

    我正在尝试将控制器操作绑定到接口 但仍保持默认的绑定行为 public class CoolClass ISomeInterface public DoSomething get set ISomeInterface public clas
  • 从 Golang 调用 C 函数

    我想在 Golang 中编写控制器逻辑并处理 json 和数据库 同时在 C 中使用我的数学处理模型 在我看来 调用 C 函数的开销必须尽可能低 就像设置寄存器 rcx rdx rsi rdi 一样 执行一些操作fastcall 并获取 r
  • 何时分离或加入 boost 线程?

    我有一个方法 大约每 30 秒触发一次 我需要在一个线程中包含它 我有一个可以从类外调用的方法 像 call Threaded Method 这样的东西会创建一个线程 该线程本身会调用最终的线程方法 这些是 MyClass 的方法 void
  • 文件加密与解密问题

    我一直在尝试在 VC Express 2010 中加密和解密文件 我见过的所有教程和文档都需要两个FileStreams 来加密文件 一个用于读取未加密的版本 另一个用于加密 当我实际编写代码时 它不断抛出错误 告诉我它无法打开该文件 因为
  • 如何使用 C# 将表格粘贴到 Ms-Word 文档的末尾

    我有一个预制的 Word 模板 其中有一个表格 我想打开它 然后在文档末尾添加 粘贴 另一个表格 问题是它不会转到文档的末尾 而是将新表格粘贴到原始表格的第一个单元格中 任何帮助将不胜感激 previous code copied a ta
  • 动态菜单创建IoC

    我想知道是否有人知道我如何创建如何使用 AutoFac 之类的东西来让我动态地允许 dll 创建自己的表单和菜单项以在运行时调用它们 所以如果我有一个 员工 dll 新入门表格 证书表格 供应商 dll 供应商详细信息来自 产品形态 在我的
  • 如何使 WinForms UserControl 填充其容器的大小

    我正在尝试创建一个多布局主屏幕应用程序 我在顶部有一些按钮链接到应用程序的主要部分 例如模型中每个实体的管理窗口 单击这些按钮中的任何一个都会在面板中显示关联的用户控件 面板包含用户控件 而用户控件又包含用户界面 WinForms User
  • C# 和断点 - 这里有魔术师吗?

    我有这个 public static void ByLinkText string text for var i 0 i lt 50 i try Setup Driver FindElement By LinkText text Click
  • 如何获取运行或段落的高度

    我找到了Run or Paragraph in FlowDocument现在我需要知道HEIGHT of it i e while navigator CompareTo flowDocViewer Document ContentEnd
  • 是否可以检测流是否已被客户端关闭?

    简要介绍一下情况 我有一项服务可以通过套接字接收信息并发送回复 连接不安全 我想设置另一个可以为这些连接提供 TLS 的服务 这个新服务将提供单个端口并根据提供的客户端证书分发连接 我不想使用 stunnel 有几个原因 其中之一是每个接收
  • 有没有办法在 C# 中仅通过文件名查找文件?

    我们现在使用绝对路径或相对路径在 C 应用程序中查找文件 如果文件位于当前工作目录下或 路径 之一下 有没有办法仅通过名称查找文件 使用绝对路径不好 使用相对路径也不够好 因为我们可能通过重命名或移动项目文件夹来更改项目结构 如果我们的代码
  • 线程安全的有限大小队列,不使用锁

    我正在尝试编写一个主题队列 但遇到死锁和其他多线程问题 我想用Interlocked CompareExchange避免lock用法 但这段代码并没有按预期工作 它只是擦除整个队列 我在这里做错了什么 public class FixedS

随机推荐