永发信息网

用C的高手请进!我写的缓冲区溢出试验程序!!!

答案:3  悬赏:0  手机版
解决时间 2021-02-08 11:19
  • 提问者网友:捧腹剧
  • 2021-02-07 15:50


void fun(const int *var1,int *var2);
void printx(void);
int x=0;

int main()
{
fun(&x,printx);
return 0;
}

void printx(void)
{
printf("x=%d",x);
exit(1);
}

void fun(const int *var1,int *var2)
{
char a[4]={'A'};
int *ppv1; //指向第一个参数
int *ppv2; //指向第二个参数
int *ebp; //堆栈的值
int *ret; //反回IP的值

int *pv;
ebp = a+4;
ret = a+8;
ppv1=a+12;
ppv2=a+16;

pv=*ppv1;
*pv=99;

*ret=*ppv2;
return 0;
}

问题:调用void printx(void)时,如果不用exit退出。就出现错误。我故计是堆栈没有还原的原因。谁能帮我改一下!

本程序在VC6下通过!

s903s 真是高手!对汇编的那一套真的是很熟啊!
最佳答案
  • 五星知识达人网友:鱼芗
  • 2021-02-07 16:05
〉调用void printx(void)时,如果不用exit退出。就出现错误。我故计是堆栈没有还原的原因。
应该不完全是堆栈没有还原的原因。首先应该是返回地址的问题。
实际上程序进入printx不是通过正常渠道进入的。而是通过把fun()的返回地址修改为printx的入口实现的。这样,fun()返回时就跳到printx去了。而printx返回时,正常的返回地址并没有设置(因为它不是通过call语句调用的),而程序仍然按正常情况取栈顶的数据作为返回地址去眺转,当然要出错误了。

分析这个程序,printx返回时取返回地址的地方,应该是参数var1的地址。所以我们可以设想,把fun()的返回地址保存到var1的位置, printx就可以返回到main()中调用fun()的下一条语句了.

具体实现: 在*pv=99; 下面加var1=*ret; 这样程序回到main()里可以运行下去。可以在main()中return 0之前加一句printf("---OK.")测试。

这里esp的问题并没有解决。因为少了一个call指令,所以在printx执行ret时回到main时的第一条指令add esp,8应该add esp,4才对。否则在main()执行ret时就回不到调用main()的地方了,还会程序异常。
为了证实这一点,可以用HEX编辑工具,找到main中这条指令add esp,8修改成add esp,4(把83 C4 08 改成 83 C4 04),就不会发生程序异常了。
更简单的做法是main()最后不返回,把return 0改成exit(0)退出,也不会发生程序异常了。

C中不使用汇编是修改不了esp或ebp的。如果保持main仍然return 0, 那么就必须放弃前面的修改,改作另外的修改。而且必须使用汇编。思路是:

既然回到main()要用add esp,4代替add esp,8才正确,那么我就在不影响程序运行的前提下,提前修正esp. 可以设想把修改集中到fun()的最后通过修改ebp寄存器进行。这样,就要先调整堆栈:
*pv=99; //修改x=99; 保留这一句。下面要重写了!
*(int *)a = *ebp; // 复制main()传过来的ebp寄存器值
*ebp = *ppv2; // 改为printx入口,供fun的ret指令转入printx
__asm {
sub ebp,4
}
return; //展开后即是mov esp, ebp; pop bp; ret;
从而在不影响程序运行的前提下修正了esp寄存器.

这样就圆满了。顺便说一句:fun()中定义a[]字符型并定义了那么多指针变量纯粹是为了降低可读性,增加反编译难度。如果为了避免VC对
ebp=a+4; ret=a+8;...
一类的语句报类型错误而使用强制类型转换的时候, 千万注意要把(a+4)...括起来:
ebp=(int *)(a+4); ret=(int *)(a+8); ...

如果把a[]定义成int,编程可能容易而且清晰。缺点是别人反编译容易了:
int x=0;
void printx() { printf("x=%d\n",x); }

void fun(int *var1,void *var2)
{
int a[1]={99};
*(int *)a[3]=a[0]; //修改x, x=99
a[0]=a[1]; //ebp寄存器
a[1]=a[4]; //printx入口
__asm {sub ebp,4 } //间接校正esp指向a[0]
return;
}

int main()
{
fun(&x,printx); printf("--- OK?");
return 0;
}
全部回答
  • 1楼网友:由着我着迷
  • 2021-02-07 17:14
你好! [a][a][a][a][ebp][ret][var1][var2(pr)]应该是[ret]在[ebp]前面吧! 如有疑问,请追问。
  • 2楼网友:孤独入客枕
  • 2021-02-07 16:40
郁闷!
我要举报
如以上回答内容为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
点此我要举报以上问答信息
大家都在看
推荐资讯