标 题: 谁动了我的EIP 作 者: riverfor <mailto: [email protected]> 日 期: 2005-1-22 关键词: stack, shellcode 内 容;

写在前面的前面
  我是一个Linux fan, 本文所讲述的系统为X86架构上的Linux, 我用的linux为Redhat ES 和 knoppix, 使用的gcc都是Version3.2, 本文的例子都是基于此. 同时,我又是一个初学者,所以本文的思想都体现的是我对我所找到的相关文档的理解, 写下这片文章的目的除了以文档的形式总结一下自己所学的东西,同时在看国内前辈的文章时,感觉到前辈们虽然很理解Stack overflow,但是没有全面地讲述出来,我才艺不精,但自认文笔清晰,谨以此文献给广大Linux初级爱好者,也感谢高手们斧正。
  本文的例子中,注释带[paltform]表示不同的Linux发行版或编译器,可能需要改变

** 简介 **
  1, 关于EIP: 存放进程下一步指令的地址. 

/*
* 谁动了我的EIP: DEMO 1
* 输出结果:  x = 0
*/
void ch_eip() {
    int *ret;
    ret = (int *)&ret + 2;      // [paltform]
    (*ret) += 7;              // [paltform]
}
int main() {
    int x = 0;
    ch_eip();
    x = 1;
    print("x = %d\n", x);
}
  ch_eip()被调用时,系统把ch_eip()调用返回后将要执行的指令的地址压入栈,而我们的ch_eip()改变了这个值,让其变成了print...这个指令的地址, 所以ch_eip()返回后,系统把经过我们更改的值弹入eip, 因此跳过了x = 1,我们得到了x = 0.

** 关于栈 **
  1, 定义
    /------------------\  Higer
    |                  |  memory
    |       Stack      |  addresses
    |                  |
    |------------------|
    |   (Initialized)  |
    |        Data      |
    |  (Uninitialized) |
    |------------------|
    |                  |
    |       Text       |  Lower
    |                  |  memory
    \------------------/  addresses

  2, 特点
    ABCD     => [44434241] Highter
                 .......
    ABCDDCBA => [44434241]
                [41424343] Lower
    由高往低增长, 没有边界检查,因此存在溢出,表现形式为放入预定高内存区的内容的大小由于超过预设空间,因此把低内存的一些数据给覆盖了。而由于程序调用子函数时会把函数返回后的下一步指令的地址值压入堆栈,函数完成调用后将该值弹回eip,相对函数的内部变量的存放地值来说,这个值位于内存的低区域,因此就存在溢出的可嗯给,尽管不同的版本的编译器,使得栈中存放的函数返回调用地址相对函数内部变量的位置不一样,但溢出依然是没问题的。
/*
* 谁动了我的eip: DEMO 2
* 输出结果 segment falt 41414141
*/
int main() {
    char buffer[8];
    if (argc > 1) {
        strcpy(buffer, argv[1]);
    }
}

$./demo2 `perl -e 'print "A"x16'`
Segment falt 41414141
  进程收到SIGEVL, 我们的main函数中的strcpy操作将main调用返回后的下一步指令地址更改成为0x41414141, 而此地址指向的位置的指令不可运行,所以程序中止,那么如果指向的地址可以运行呢?答案是那么将不会中止。