前几天有人问longjmp代码的问题。这里实验了一个演示。
仅仅为了说明通过切换STACK实现远跳的初步演示。是一个没有任何实际用处的程序。
/* setjmp & longjmp simple demo
*/
char jbuf[128];
char *setjmp()
{
int i;
printf("setjmp...\n");
memcpy(jbuf, &i, 32);
return jbuf;
}
int longjmp(char *p)
{
int i;
memcpy(&i, jbuf, 32);
printf("doing longjmp...\n");
return 0;
}
func()
{
printf("in function...\n");
longjmp(jbuf);
printf("useless code---\n");
}
main()
{
char *jp;
int k = 4;
printf("normal path...\n");
jp = setjmp();
if(jp) {
printf("normal path 0--------- k %d jp %p\n", k, jp);
printf("normal path 1---------\n");
//longjmp(jp);
printf("normal path 1---------\n");
func();
printf("never reach here...\n");
} else {
printf("longjmp path 3 --------- k %d jp %p\n", k, jp);
}
}
converse 回复于:2007-02-26 13:39:10
有点意思,要是加上一些解释就好了,也可以做为理解缓冲区溢出,函数栈原理的材料哦~~
思一克 回复于:2007-02-26 13:45:07
/* setjmp & longjmp simple demo
*/
char jbuf[128];
char *setjmp()
{
int i;
printf("setjmp...\n");
memcpy(jbuf, &i, 32); //保存setjmp时刻的STACK到buffer中。这里可以分配内存保存,而不用全局量jbuf. 如果这样可以有多个longjmp点。
return jbuf;
}
int longjmp(char *p)
{
int i;
memcpy(&i, jbuf, 32); //恢复此点的STACK。STACK内容在p中
printf("doing longjmp...\n");
return 0; //必须返回0,与setjmp原始返回区分路径。
}
func()
{
printf("in function...\n");
longjmp(jbuf); //远跳
printf("useless code---\n");
}
main()
{
char *jp;
int k = 4;
//其它没有什么了。基本意思可以看setjmp longjmp函数
printf("normal path...\n");
jp = setjmp();
if(jp) {
printf("normal path 0--------- k %d jp %p\n", k, jp);
printf("normal path 1---------\n");
//longjmp(jp);
printf("normal path 1---------\n");
func();
printf("never reach here...\n");
} else {
printf("longjmp path 3 --------- k %d jp %p\n", k, jp);
}
}
FreeGnu 回复于:2007-02-26 14:52:49
好久没看这些东西了,栈桢的结构都忘了。
memcpy(jbuf, &i, 32);
拷贝的是eip,ebp,edi,esi的地址把,现在还没弄懂edi,esi存什么,怎么用
试了一下,只是保存和恢复eip程序也能工作
memcpy(jbuf, &i+3, 4);
...
memcpy(&i+3, jbuf, 4);
lcstudio 回复于:2007-03-04 19:02:44
这个只是x86上的longjmp。stack longjmp与计算机体系有关
mik 回复于:2007-03-04 21:04:07
LZ 的 setjump() 有个很大的缺陷:
memcpy(jbuf, &i, 32); // 32 怎么得来?
通过变量 i 偏移来获得返回地址,在没有特别选项进行编译时,大多数编译器会浪费掉一些空间用来对齐。
所以变量 i 的上一个地址不是返回址,所以不可能是根据局部变量来得出返回地址。
获得返回地址方法有很多:
1、利用参数,参数是固定的
char * setjump(int i)
{
memcpy(buf,&i-1, 4);
......
}
2、 取 eip 值
#define __EIP__ \
{ int i; \
__asm__ __volatile__("call f\n" \
"f: pop %0\n" \
:"=r"(i) \
); \
memcpy(buf, &i, 4); \
}
思一克 回复于:2007-03-04 21:40:58
我那程序仅仅是一个最简单的原理演示. 目的就是使程序简单容易看懂. 不是有用的实用程序.
大家可以发贴子改进.
|