03.栈溢出实验-shellcode初探

栈溢出实验

shellcode初探


一.  实验环境:


操作系统:Windows XP SP3

开发环境:VC++ 6.0

调试器:Ollydbg


二.  实验代码:


#include <stdio.h>

#include <windows.h>

#define PASSWORD "1234567"

int verify_password (char *password)

{

    int authenticated;

    char buffer[44];

    authenticated=strcmp(password,PASSWORD);

    strcpy(buffer,password);

    return authenticated;

}

main()

{

    int valid_flag=0;

    char password[1024];

    FILE * fp;

    LoadLibrary("user32.dll");

    if(!(fp=fopen("password.txt","rw+")))

    {

        exit(0);

    }

    fscanf(fp,"%s",password);

    valid_flag = verify_password(password);

    if(valid_flag)

    {

        printf("incorrect password!n");

    }

    else

    {

        printf("Congratulation! You have passed the verification!n");

    }

    fclose(fp);

}


三.  溢出原理


程序未对输入的密码进行长度检测,接收密码的缓冲区只有8,而输入的密码最长可以输入1024。判断密码是否正确的变量authenticated存储在栈中,当输入的密码长度大于8时,输入的字符串将冲破缓冲区,淹没authenticated所处的位置。当密码错误时authenticated的值是1,正确的时候authenticated的值是0.这就意味着我们可以构造一个合适的输入字符串来改变判断结果。


本次的程序与上一节的程序区别在引入了windows头文件,用于使用LoadLibrary函数。另外缓冲区的长度从8增加为44。


四.  实战调试


本次实战着重初步植入简单的shellcode代码。


1. 本次实验的最终目标是在成功溢出后弹出一个消息框。那么首先我们要找到消息框的API地址,如果考虑通用性,那么需要一套负责的过程,现在我们先不考虑这些。先使用Windows自带的工具获取API的地址。


2.         我们需要用到的API是MessageBox,熟悉Windows编程的朋友应该知道,实际上并没有MessgaeBox这个API,我们实际上需要调用的是MessageBoxA或者MessageBoxW,这取决于我们使用的环境是多字节还是宽字符。此次我们那使用的是MessageBoxA,这个API处于USER32.DLL中,我们获取一下USER.DLL基址是0x77D10000,然后获取MessageBoxA的偏移是0x407EA,两者相加就可以获取到MessageBoxA在内存中的入口地址0x77D507EA。


(此处获取到的地址只在我的计算机上生效。如果本地实验,需要本地重新获取。)



3.         此时我们需要确定一下我们需要覆盖的返回地址的位置和BUFFER起始位置。已知缓冲区长度为44,那么第45个字节的00将会覆盖掉密码比对结果。为了方便查看,我们使用abcd作为输入,长度为44的缓冲区则需要11组abcd刚好覆盖。


4.         运行起来,进入到密码比对函数。执行strcpy后观察堆栈的情况。可以看到缓冲区起点是0x0012FAF0,返回地址是0x0012FB24。


5.         那么我们是不是可以这样玩,把返回地址淹没成缓冲区起点,这样指令就会从缓冲区起点开始执行。这样我们就需要把返回地址覆盖成0x0012FAF0,然后再构造一个弹出消息框的机器码用于弹出消息框。


5.1 淹没返回值为0x0012FAF0


5.2这里我们先不讨论shellcode的编写。这会在接下来的大章节中详细描述。我们直接把弹出消息框的机器码填在password中。


5.3进入shellcode执行


5.4溢出成功