Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C溢出函数。。分段故障_C_Segmentation Fault_Stack Overflow - Fatal编程技术网

C溢出函数。。分段故障

C溢出函数。。分段故障,c,segmentation-fault,stack-overflow,C,Segmentation Fault,Stack Overflow,当我试图访问下面代码中的secret函数时,编译器给出了segm错误。我获得了访问权限,但到达后,秘密函数retr_addr是doNotTouch[12]的地址。我无法返回0 我怎样才能解决这个问题,谢谢 输出: 现在进入入口() 现在是秘密 进程已完成,退出代码为11 #include <stdio.h> void secret() { printf("now inside secret()!\n"); } void entrance() {

当我试图访问下面代码中的secret函数时,编译器给出了segm错误。我获得了访问权限,但到达后,秘密函数retr_addr是doNotTouch[12]的地址。我无法返回0

我怎样才能解决这个问题,谢谢

输出:
现在进入入口()
现在是秘密

进程已完成,退出代码为11

#include <stdio.h>

void secret()
{
    printf("now inside secret()!\n");
}

void entrance()
{
    int doNotTouch[4];
    // can only modify this section BEGIN
    // cant call secret(), maybe use secret (pointer to function)


    // printf("addr_doNot = %d\n", &(doNotTouch));
    // *(doNotTouch + 10) = (int) &secret;

    void * a = secret;
    doNotTouch[10] = a;

    // can only modify this section END
    printf("now inside entrance()!\n");
}

int main (int argc, char *argv[])
{
    entrance();
    return 0;
}
#包括
无效机密()
{
printf(“现在是内部机密()!\n”);
}
无效入口()
{
int doNotTouch[4];
//只能从开始修改此部分
//无法调用secret(),可能使用secret(指向函数的指针)
//printf(“addr_doNot=%d\n”&(doNotTouch));
//*(doNotTouch+10)=(int)和secret;
void*a=秘密;
doNotTouch[10]=a;
//只能修改此节结束
printf(“现在在入口内()!\n”);
}
int main(int argc,char*argv[])
{
入口();
返回0;
}

如果要使用指针调用函数,则需要指向函数的指针,而不是数组

代码的问题是,您试图将地址存储在一个普通数组中并进行调用,但这不起作用,数组访问也不正确,您访问的数组超出了分配的大小<代码>*(doNotTouch+10)=(int)和secret

#include <stdio.h>

void secret()
{
    printf("now inside secret()!\n");
}


void entrance()
{
    int doNotTouch[4];
    void (*f)(void);
    // can only modify this section BEGIN
    // cant call secret(), maybe use secret (pointer to function)


    // printf("addr_doNot = %d\n", &(doNotTouch));
    // *(doNotTouch + 10) = (int) &secret;

    //void * a = secret;
    //doNotTouch[10] = a;
    
    f = secret;
    f();
    // can only modify this section END
    printf("now inside entrance()!\n");
}

int main (int argc, char *argv[])
{
    entrance();
    return 0;
}
#包括
无效机密()
{
printf(“现在是内部机密()!\n”);
}
无效入口()
{
int doNotTouch[4];
无效(*f)(无效);
//只能从开始修改此部分
//无法调用secret(),可能使用secret(指向函数的指针)
//printf(“addr_doNot=%d\n”&(doNotTouch));
//*(doNotTouch+10)=(int)和secret;
//void*a=秘密;
//doNotTouch[10]=a;
f=秘密;
f();
//只能修改此节结束
printf(“现在在入口内()!\n”);
}
int main(int argc,char*argv[])
{
入口();
返回0;
}

这是可能的,但取决于编译选项。我假设您使用的是x86-64

  • 在未优化的构建中,您可以通过BP控制SP。当
    entry()
    离开时,使用
    leave
    指令,它将SP设置为BP,并弹出BP,最后返回并转到方便地放在堆栈上的
    secret()
    地址。然后
    secret()。此时,SP太高了8个字节,因为我们通过一个函数返回了“太多”。但是当
    main
    完成时,它会将SP设置为BP,从而恢复正确的堆栈指针和BP,然后返回,从正确的堆栈位置弹出返回地址。代码的草图如下所示:

    void **stk = (void**)&stk;
    stk += ...; // adjust
    stk[1] = stk[0]; // forward return point into main to secret
    stk[0] = &secret; // return into secret
    
  • 在优化的构建中,堆栈帧被抑制,您无法控制SP或自动恢复SP。但由于SP在函数返回时未被修改,因此从函数返回会将SP上移,而调用函数会将其下移。您需要通过递归到
    入口
    ,并通过扫描上面的一点堆栈来检测是否从外部调用存储了魔法值,从而使堆栈增长一点。在检测到递归之后,您将使用返回地址到secret加载堆栈,其上方是一些良性库函数的重复地址,如
    abs
    ,该函数使用寄存器调用约定,可用于向上移动SP。最终,该功能将正常返回到
    main
    ,SP处于正确位置。但这假设您可以再次呼叫
    入口

  • 或者,如果不能显式调用入口,则必须将堆栈中的足够部分移动一个
    void*
    size,这样当
    secret
    返回到main时,main和outer函数将在预期的位置找到返回地址。这是
    stk[n+1]=stk[n]
    思想的扩展-您需要有策略地选择要移动的地址,以便
    main
    具有有效的返回地址,以及调用
    main
    的任何没有堆栈帧的运行时函数(因为具有堆栈帧的函数将“修复”)他们自己,只要你将他们需要的第一个BP向上移动)

  • 然而,您也可以查找各种面向返回的编程词汇,编写一个小的面向返回的程序,根据需要调整堆栈指针

  • 对于x86-64,使用GCC10(和许多其他版本),我已经使用了1+3方法。这在一定程度上也适用于clang,即当从
    main
    返回时,它在优化的构建中崩溃;在叮当声中,
    main
    中的堆栈布局略有不同,因此需要进行一些调整,可能会移动两个不连续的堆栈块

    dump\u stack
    函数仅用于调试此黑客,不调用它,如果您愿意,可以将其删除。放心吧

    #包括
    #包括
    无效转储\u堆栈(无效**p,内部长度)
    {
    p+=len-1;
    而(len--){
    printf(“%16llx:%16llx\n”,(长)p,(长)*p);
    --p;
    }
    }
    无效机密()
    {
    printf(“现在是内部机密()!\n”);
    }
    无效入口()
    {
    int doNotTouch[4];
    //只能从开始修改此部分
    #定义stk(*(void*volatile*volatile*)和doNotTouch)
    stk=(void*)和doNotTouch;
    #ifndef\uuu优化__
    //gcc w/o优化
    枚举{first=6,last=5};
    #否则
    //gcc-O&up
    #如果1
    //未调用dump_堆栈时
    枚举{first=8,last=3};
    #否则
    //仅在调用dump_stack时需要-O1,2,3
    枚举{first=8,last=5};
    #恩迪夫
    #恩迪夫
    for(int i=第一;i>最后;--i)
    stk[i]=stk[i-1];
    stk[last]=&secret;
    //卸载堆(stk,20);
    //只能修改此节结束
    printf(“现在在入口内()!\n”);
    }
    int main(int argc,char*argv[])
    {
    入口();
    返回0;
    }
    
    不能在数组中存储地址
    do
    
    #include <stdio.h>
    #include <stdlib.h>
    
    void dump_stack(void **p, int len)
    {
        p += len-1;
        while (len--) {
            printf("%16llx: %16llx\n", (long long)p, (long long)*p);
            --p;
        }
    }
    
    void secret()
    {
        printf("now inside secret()!\n");
    }
    
    void entrance()
    {
        int doNotTouch[4];
        // can only modify this section BEGIN
    
        #define stk (*(void*volatile*volatile*)&doNotTouch)
        stk = (void*)&doNotTouch;
    
        #ifndef __OPTIMIZE__
            // gcc w/o optimizations
            enum { first = 6, last = 5 };
        #else
            // gcc -O & up
        #if 1
            // when dump_stack is not called
            enum { first = 8, last = 3 };
        #else
            // only needed for -O1,2,3 when dump_stack is called
            enum { first = 8, last = 5};
        #endif
        #endif
        for (int i = first; i > last; --i)
            stk[i] = stk[i-1];
        stk[last] = &secret;
    
        // dump_stack(stk, 20);
    
        // can only modify this section END
        printf("now inside entrance()!\n");
    }
    
    int main(int argc, char *argv[])
    {
        entrance();
        return 0;
    }