首页 > 学技术 > 技术网文 > C/C++ > 正文

[保留] 通过切换STACK实现远跳longjmp的最简单的演示


来源 chinaunix.net kuqin整理

前几天有人问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

我那程序仅仅是一个最简单的原理演示. 目的就是使程序简单容易看懂. 不是有用的实用程序.

大家可以发贴子改进.




原文链接:http://bbs.chinaunix.net/viewthread.php?tid=902285
转载请注明作者名及原文出处



收藏本页到: