C溢出函数。。分段故障
当我试图访问下面代码中的secret函数时,编译器给出了segm错误。我获得了访问权限,但到达后,秘密函数retr_addr是doNotTouch[12]的地址。我无法返回0 我怎样才能解决这个问题,谢谢 输出: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() {
现在进入入口()
现在是秘密 进程已完成,退出代码为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
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
入口
,并通过扫描上面的一点堆栈来检测是否从外部调用存储了魔法值,从而使堆栈增长一点。在检测到递归之后,您将使用返回地址到secret加载堆栈,其上方是一些良性库函数的重复地址,如abs
,该函数使用寄存器调用约定,可用于向上移动SP。最终,该功能将正常返回到main
,SP处于正确位置。但这假设您可以再次呼叫入口
void*
size,这样当secret
返回到main时,main和outer函数将在预期的位置找到返回地址。这是stk[n+1]=stk[n]
思想的扩展-您需要有策略地选择要移动的地址,以便main
具有有效的返回地址,以及调用main
的任何没有堆栈帧的运行时函数(因为具有堆栈帧的函数将“修复”)他们自己,只要你将他们需要的第一个BP向上移动)
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;
}