char*溢出问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了char*溢出问题相关的知识,希望对你有一定的参考价值。

char* a = "abc";
请问是否溢出了
这样呢
char* a = "abc";
a = "abcd";

没有溢出,
首先"abc";这是个常量字符串。
然后,a是一个指向字符的指针,这个指针就指向常量字符串的地址,也就是字符a的地址。
你写的那也是一个字符串初始化方式,只是不能通过指针a,修改字符串"abc";因为它是常量,不能改变的。
补充回答:
char* a = "abc";
a = "abcd";
不可以,因为这种方式只可以初始化赋值指针,
不能 a = "abcd";
参考技术A 没溢出。

"abc"跟new一个空间再赋值abc的情况不一样,"abc"在程序运行前就存储在了静态区域,不是运行时分配的,所以不会溢出。
参考技术B 不会溢出。 参考技术C 要申请空间的。

堆栈中的缓冲区溢出

【中文标题】堆栈中的缓冲区溢出【英文标题】:Bufferoverflow on stack 【发布时间】:2013-09-10 16:33:07 【问题描述】:

我正在处理 C 中的安全问题。我无法理解以下代码如何破坏堆栈,

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

int chk_perm()
        printf("\n Check Perm \n");
        return 2;

int main(int argc,char* argv[])
        int fg;
        char filename[16];

        if(argc != 2)
                fprintf(stderr,"Usage : %s filename\n",argv[0]);
                exit(1);
        

        fg = chk_perm();
        strcpy(filename,argv[1]);
        if(fg == 0xdeadbeef)
                //execute as root or deposit million dollars in bank account
        
        else
                //execute as a normal user , deduct $10 from an account
        

        return 0;

传递的 argv[1] 可能会改变 fg 的值。 据说,如果传递的 argv[1] 是一个完整的二进制文件,可能会导致不希望的结果可以作为参数与返回地址一起传递,那么就会发生损坏。

我不明白,str​​cpy 如何破坏堆栈 check_perm 从而改变 fg 的值。

我对程序的假设,

当程序开始执行时,它为 main 函数创建一个堆栈,并将其参数、返回地址、局部变量放入堆栈。因此 int fg 将占用堆栈的 4 个字节(08567500 loc),文件名 [16] 将占用接下来的 16 个字节(08567504)。即使文件名溢出超过 16 个字节,如果它之后存在任何局部变量,它也可能会损坏。

那么 fg 是如何因为 strcpy(filename,argv[1]); 而损坏的?

【问题讨论】:

【参考方案1】:

如果在您的架构上堆栈向下增长(通常是这种情况),fg 将立即占用内存filename。这意味着当你写过去 filename 时,你会粉碎 fg

【讨论】:

这是唯一正确考虑堆栈增长方向的答案 @NPE:谢谢。我检查了 fg 的地址和文件名。 fg 位于文件名下方。但我有一个疑问。当堆栈加载时,参数、返回地址、局部变量按顺序存储到堆栈中。所以局部变量 fg 必须获得比文件名更高的地址。并且数组文件名从低到高 sddress 增长。为什么文件名的地址比 fg 最高。 @Angus:也许写这个例子的人说的是一个向下栈的系统,但你测试的系统使用的是向上栈。 我试图在文件名声明下面声明fg。那么 fg 也占据最低地址。如果我声明上面的文件名,我也会得到 fg 作为最低地址。当局部变量被压入堆栈时,第一个声明的变量必须获得比下面的最高地址是我的理解【参考方案2】:

fg 在堆栈上。 filename 也是如此。当你 strcpy()filename 的东西大于 16 时,它会覆盖 fg

【讨论】:

【参考方案3】:

正如其他人指出的那样,您正在写超过 filename 缓冲区。当您这样做时,堆栈中的下一项是 fg 变量,因此如果输入文件名的长度超过 15 个字符(然后再包含一个字节:零终止符),它将获得写入它的字节)。

您需要使filename 足够大以容纳用户可能为argv[1] 提供的任何内容,或者防止复制太多字节。但最好在这种情况下分配您需要的空间:

char filename[PATH_MAX+1];

如果你想动态地做:

char *filename;

if ( !(filename = malloc(strlen(argv[1]) + 1))) ) 
    ... (failure leg)

将文件名长度限制为16 字节(实际上是15 加上零终止符)对用户来说是极其不切实际的,尤其是因为他们可能会为文件参数提供完整的路径名。使用 strncpy 之类的函数可能会截断用户的文件名,并且可能会生成文件打开错误,或者更糟糕的是,会打开错误的文件。

【讨论】:

strncpy() 是个坏建议。一个非常糟糕的建议。 @joop 是的,我同意。我什至不会自己使用这种方法。我只是在实践中展示了它,因为其他人提供了它并想让它更“可见”。我已将其删除。 为什么 strncpy() 是不好的建议? @TritonMan strncpy 在某些情况下有它的位置,但在这种情况下,使用strncpy 只会截断用户的文件名,如果它太长。所以你会在其他地方失败(例如,无法打开文件)。

以上是关于char*溢出问题的主要内容,如果未能解决你的问题,请参考以下文章

缓冲区溢出,sprintf而不是char调整大小? [重复]

C-缓冲区溢出示例

试图缓冲溢出简单的c程序

vector 内存泄漏问题?

Offbyone 缓冲区溢出有效负载中的 NULL 字节

c语言溢出问题