解释这段不显式调用函数的代码是如何运行的?

8
下面代码的输出为“溢出”,但我并没有显式调用func函数。它是如何工作的?
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int copy(char *input)
{
    char var[20];
    strcpy(var, input);
    return 0;
}

int func(void)
{
    printf("Overflow\n");
    return 0;
}

int main(int argc, char *argv[])
{
    char str[] = "AAAABBBBCCCCDDDDEEEEFFFFGGGG";
    int *p = (int *)&str[24];
    *p = (int)func;

    copy(str);
    return 0;
}

3
你是指缓冲区溢出吗? - JosephH
3
这就是黑客如何让一个不安全的程序执行本不应执行的代码的方法。理解它需要对编译器、运行时环境和CPU架构有低层次的了解。 - Jon
1
请注意:如果func的地址中有一个零字节,它将无法按您预期的方式工作。 - aaronps
哇,这是一段极其邪恶、恶毒,但非常优雅的代码,真的很清楚地解释了这些指令是如何执行的... - ppeterka
如果你真的想知道它是如何工作的,建议阅读Jon Erickson的《黑客:攻击与防御艺术》。 - jwaliszko
1个回答

11

copy 函数在执行时会向 var 缓冲区中写入超出缓冲区大小的数据,将 main 函数返回地址覆盖为 func 函数地址。

copy 函数返回时,它不会返回到主函数 main,而是返回到函数 func


它将返回与整数值“GGGG”对应的地址吗? - pedr0
1
@pedr0 在这个赋值语句中,GGGGfunc 函数的地址所替换:*p = (int)func;strcpy 将会把这个地址复制到返回地址。 - ouah
为什么数组str需要比var多4个int的大小,而不是2或6? - wilbeibi
@Wilbeibi str需要比var多8个字符(2个int):4个用于栈帧的ebp,另外4个用于覆盖32位返回地址。 - German Garcia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接