吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 15232|回复: 29
收起左侧

[漏洞分析] 栈溢出的利用

  [复制链接]
Martin 发表于 2015-4-8 13:53
本帖最后由 Martin 于 2015-4-8 13:59 编辑

栈溢出的利用
        我们接着上面的栈溢出原理来进行讲解栈溢出的利用,首先我们不会接着上一篇的文章的例子来进行讲解,我会再写一个C语言的例子来进行讲解。再进行讲一遍栈溢出的原理。更加熟悉栈溢出的原理能够让我们更好地利用栈溢出。
下面的例子代码如下:(代码很简单我不做解释)
[C] 纯文本查看 复制代码
#include <stdio.h>
#include<string.h>
#define PASSWORD "qqqqqqq"
int verify_password(char *password)
{
    int authenticated;
    char buffer[8];
    authenticated=strcmp(password,PASSWORD);
    strcpy(buffer,password); //构造栈溢出
    return authenticated;
}
int 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("incorrect password!\n\n");
       }
       else
       {
           printf("Congratulation! you have passed the Verification !\n");
           break;
       }
    }
    getchar();
    char i;
    scanf("%s",&i);
}
从上面的例子可以看出是密码有效性的验证的一个例子,是通过输入密码进行验证密码是否输入正确,首先我们现在运行下程序。

1

1

通过输入正确密码和不正确密码的区别;
输入7个'q'程序正常运行时的栈状态。
如下图可以看到栈的内部情况:

2

2

如果继续增加输入的字符那么超出buffer[8]边界的字符将依次淹没authenticated、前栈帧EBP、返回地址。也就是说,控制好字符串的长度就可以让字符串中相应位置字符的ASCII码覆盖掉这些栈帧状态值。
按照上面对栈帧的分析,可以得出以下的结论:
(1)输入11个'q',第9-11个字符连同NULL结束符将authenticated冲刷为0x00717171。
(2)输入15个'q',第9-12个字符将authenticated冲刷为0x71717171;第13-15个字符连同NULL结束符将前
栈帧EBP冲刷为0x00717171。
(3)输入19个'q',第9-12字符将authenticated冲刷为0x71717171;第13-16个字符连同NULL结束符将前栈
帧EBP冲刷为0x71717171;第17-19个字符连同NULL结束符将返回地址冲刷为0x00717171。
    这里用19个字符作为输入,看看淹没返回地址会对程序产生什么影响。出于双字对齐的目的,我们输
入的字符串按照"4321"为一个单元进行组织,最后输入的字符串为"4321432143214321432"(测试)。

<OllyDbg加载程序,在字符串拷贝函数调用结束后观察栈状态。>
下面来进行分析:
当输入7q时,观察程序返回时堆栈的里面的内容。

3

3

下面执行这段代码:4321432143214321432
实际的内存状况和我们分析的结论一致,此时的栈状态见。请见下表的内容:

4

4

接下来我们用OD来调试下程序的运行过程:

5

5

返回地址用于在当前函数返回时重定向程序的代码。在函数返回的"retn"指令执行时,栈顶元素恰好是这个返回地址。"retn"指令会把这个返回地址弹入EIP寄存器,之后跳转到这个地址去
执行。
    在这个例子中,返回地址本来是0x040FACB,对应的是main函数代码区的指令,现在我们已经把这个地址用字符的ASCII码覆盖成了0x00323334
我们可以从调试器中的显示看出计算机中发生的事件。
(1)函数返回时将返回地址装入EIP寄存器。
(2)处理器按照EIP寄存器的地址0x00323334取指。
(3)内存0x00323334处并没有合法的指令,处理器不知道该如何处理,故报错。
由于0x00323334是一个无效的指令地址,所以处理器在取指的时候发生了错误使程序崩溃。但如果这里我们给出一个有效的指令地址,就可以让处理器跳转到任意指令区去执行(比如直接跳转到程序验证通过的部分),也就是说,我们可以通过淹没返回地址而控制程序的执行流程。
这时候我们会想到这段代码是进行对密码的验证,如果对了就显示正确信息,如果不对弹出错误消息,这时候我们可以修改这个函数返回地址,直接执行正确信息这样就达到了我们的目的;接下来我们要对程序进行一定的改进。
程序代码如下所示:
[C] 纯文本查看 复制代码
#include <stdio.h>
#define PASSWORD "1234567"
int verify_password (char *password)
{
      intauthenticated;
      charbuffer[8];
      authenticated=strcmp(password,PASSWORD);
      strcpy(buffer,password);//over flowed here!      
      returnauthenticated;
}
main()
{
      intvalid_flag=0;
      charpassword[1024];
      FILE * fp;
      if(!(fp=fopen("password.txt","rw+")))
      {
             exit(0);
      }
      fscanf(fp,"%s",password);
      valid_flag= verify_password(password);
      if(valid_flag)
      {
             printf("incorrectpassword!\n");
      }
      else
      {
             printf("Congratulation!You have passed the verification!\n");
      }
      fclose(fp);
}
这段代码主要改进部分是密码是从txt文件中读取出来的不是手动输入了,这样的好处就是能够用UE输入一些16进制来进行修改数据;首先我们将程序载入到OD中,看一下我们要跳转的地方地址在哪里,我们看下面这张图,我们可以清晰的看到我们要返回的地址应该是0x401122这个地址

6

6

       这时候我们在程序的同目录下面创建一个password.txt首先前面的东西可以随便输入,还是4321432143214321后面这个就要输入0x401122如下图所示:

7

7

这时候可以看一下栈帧情况,栈帧的情况如下图所示:

8

8

运行程序看一下结果

9

9

OK我们就可以看到我们想要的效果,当然这样修改会有瑕疵,因为没有通过一些手段进行处理,代码里面还存在一些非法的指令因为我们修改了程序的返回地址。由于栈内EBP等被覆盖为无效值,使得程序在退出时堆栈无法平衡,导致崩溃。虽然如此,我们已经成功地淹没了返回地址,并让处理器如我们设想的那样,在函数返回时直接跳转到了提示验证通过的分支。
本节接上篇文章内容。如果大家觉得好可以给点评分,有不对的地方请大家指正。
上一篇地址:http://www.52pojie.cn/thread-349478-1-1.html

免费评分

参与人数 11威望 +2 热心值 +11 收起 理由
KaQqi + 1 我很赞同!
chimodechong + 1 用心讨论,共获提升!
Lnairan + 1 谢谢@Thanks!
Jack丶雷 + 1 我很赞同!
pslll3119599 + 1 谢谢@Thanks!
Mr.Mlwareson_V + 1 鼓励转贴优秀软件安全工具和文档!
冰封尘埃 + 1 谢谢@Thanks!
yysniper + 1 好,还没接触过该领域呀
Hmily + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.
LoongKing + 1 我很赞同!
寒枫雨雪 + 1 谢谢@Thanks!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

xlhwxyh 发表于 2015-4-8 15:52
无法做到堆栈平衡算小瑕疵吗?可以说是bug了吧!很多程序在电脑上24小时运行的,在加上不同的操作系统,你运行不到1小时,程序就崩溃了, 那人家会说你程序垃圾。谁还花钱买啊,我认为程序的稳定性比反破解更加重要。如果仅仅是为了不让对方用OD断点回溯调用call,可以用多线程,采用lua的那种模式,
发送命令给lua-----lua执行命令----MessageBoxA 弹窗
发送命令给lua----lua执行命令----SetWindowText
等等..... 一切敏感性操作,都交给lua来执行。
你会发现,所有你能下断的地方,都是一个call 在频繁调用。
而且兼容性更好。

免费评分

参与人数 1热心值 +1 收起 理由
Jack丶雷 + 1 热心回复!

查看全部评分

LoongKing 发表于 2015-4-8 14:05
 楼主| Martin 发表于 2015-4-8 16:34
xlhwxyh 发表于 2015-4-8 15:52
无法做到堆栈平衡算小瑕疵吗?可以说是bug了吧!很多程序在电脑上24小时运行的,在加上不同的操作系统,你 ...

恩本文侧重于讲的是原理~这个后续会怎么完善。
 楼主| Martin 发表于 2015-4-8 16:37
xlhwxyh 发表于 2015-4-8 15:52
无法做到堆栈平衡算小瑕疵吗?可以说是bug了吧!很多程序在电脑上24小时运行的,在加上不同的操作系统,你 ...

理解你的意思,其实写这篇的主要是目的不再于后面这里讲述的是整个栈溢出的原理以及思路。
WorldElite丶 发表于 2015-4-8 21:15
必须顶,太给力了
www52pojiecn 发表于 2015-4-9 23:02
现在应该讲解dep aslr seh rop的溢出技术就好了
浙江螃蟹 发表于 2015-4-16 15:21
好深奥的感觉。
 楼主| Martin 发表于 2015-4-16 17:03
www52pojiecn 发表于 2015-4-9 23:02
现在应该讲解dep aslr seh rop的溢出技术就好了

谢谢提议~~
Chiaki 发表于 2015-4-30 08:11
没想到栈溢出还能这么玩
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-22 10:48

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表