用户
搜索
  • TA的每日心情
    擦汗
    2019-6-21 00:06
  • 签到天数: 7 天

    连续签到: 1 天

    [LV.3]经常看看I

    版主

    Rank: 7Rank: 7Rank: 7

    5

    主题

    23

    帖子

    194

    魔法币
    收听
    0
    粉丝
    3
    注册时间
    2016-10-20

    i春秋签约作者

    发表于 2019-9-24 09:35:31 11071
    一、前言
           哈哈,又是我,我又来发文章了,上一篇是个小实验,感觉好玩么?这一篇俺们再来一个实验,这篇发了不知道后面要多久才会更新第三篇了,没办法,工作忙,不过有空一定更新。
           大佬们知道数据结构中的栈么?对啦,没错,今天这个小实验就在栈上做文章。首先栈是一种数据结构,是一种先进后出的数据表,这不由得又让我想起了在我考研究生的时候专业课中几乎年年会出的一道题:入栈顺序是1234,要想出栈序列为2134,该怎么进行入栈出栈操作?(假定X为入栈操作,E为出栈操作)。哎,多熟悉啊!莫名又想去考研了,就差一科就成功了,为啥就是差一点点呢?烦躁!
    不说上面的话题了,回归正题,其实从上面也能看出栈的操作只有两种:入栈(PUSH)和出栈(POP),栈的属性也只有两个:栈顶(TOP)和栈底(BASE)。以上面考研题为例,1234依次入栈,出栈的时候便不再是1234,而是4321。要想是2134出栈,就要先把12压进栈中再出栈变成了21,再3进栈出栈,最后4进栈出栈就可以得到2134的出栈顺序。所以上面题的答案是XXEEXEXE。那该怎么在这个上面做文章呢?其实这就离不开寄存器了,Win32系统提供两个特殊的寄存器:ESP(栈指针寄存器)和EBP(基址指针寄存器),ESP中存放了一个指针,这个指针永远指向系统栈最上面一个栈帧的栈顶,EBP中也放着一个指针,永远指向系统栈最上面一个栈帧的底部。一个程序在调用一个有返回值的函数时操作大概是这样的:
           1、调用函数并将返回值保存在寄存器EAX中。
           2、弹出当前栈帧,恢复上一个栈帧。
    而我们就要在这个EAX寄存器中做点小动作,OK,开始实验吧!

    二、实验环境以及要使用的软件
    系统

    软件
    Windows 10 Profession 32Bit
    UltraEdit

    LordPE

    OllyDBG

    VC++ 6.0

    IDA Pro
           若需要系统与软件可以评论拿到这个全家桶 —— VMware的Windows 10虚拟机。

    三、实验步骤
           首先打开VC++ 6.0,编写如下程序并Bulid出EXE文件。观察源码不难发现,authenticated变量的值来源于strcmp函数的返回值,之后会返回给main函数作为密码验证成功与否的标志变量:当authenticated为0时,表示验证成功;反之,验证失败。而且buffer和authenticated是两个邻居变量,那么在程序运行中它们两个也会是邻居,这让我不得不去考虑下怎么通过buffer修改authenticated变量的值,使其为0。
    [C] 纯文本查看 复制代码
    #include<stdio.h>
    #include<string.h>
    #define PASSWORD "1234567"
    
    int verify_password(char *password)
    {
        int authenticated;
        authenticated = strcmp(password, PASSWORD);
        strcpy(buffer, password);
        return authenticated;
    }
    
    void main()
    {
        int valid_flag = 0;
        char password[1024];
        while(1)
        {
            printf("please input password: ");
            scanf("%s", password);
            valid_flag = verify_password(password);
            if(valid_flag)
            {
                printf("No, your password is False!\n\n");
            }
            else
            {
                printf("Yes, your password is True!\n");
                break;
            }
        }
    }

           用OllyDBG打开这个EXE文件,如下图,当我们输入七个q时,authenticated的值为1,而当它为0的时候就代表验证成功了,那怎么修改呢?在我们输入的时候常常会按个回车键,而这个回车键实际上就是NULL值,NULL值就是空,空就是0咯。那么既然buffer和authenticated变量在内存中是相邻的,程序中给buffer8位的空间,那么如果我超出了这个空间,超出的部分会不会占用相邻authenticated变量的内存呢?
    image (11).png
           为了验证我们的想法,我们再次输入八个q加rst —— “qqqqqqqqrst”,如下图,可以看到,原authenticated变量的内存被rst所占用了。那么我们上一步的猜想已经应验,所以下面我们就要将rst变成NULL。
    image (12).png
           如何将rst变成NULL呢?很简单,在输入的时候程序会默认在后面加上一个NULL,所以我们只需要输入任意八位的密码,都能突破验证,这里我们输入八个“q”,如下图
    image (13).png
           OK,破解成功,其实可以去试试01234567,你会发现哎,不对啊!破解不了,其实这是因为在strcmp函数中,如果输入的比1234567小那么就会返回-1,而01234567 < 1234567,所以最后authenticated的十六进制值为0xFFFFFF00,故而不能突破验证,QAQ。

    四、总结
           本人才疏学浅,若文中有错误就提出来,反正我不得改,哈哈哈,谢谢阅读,下篇再会。愿你孤独的努力终有回报,愿你前行的路上有人相伴,愿你在进制的海洋里头发尚在,拜拜。

    使用道具 举报 回复
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册