用户输入的字符串将拷贝进buffer[8] , 从示意图中可以看到 , 如果我们输入的字符超过7个(注意有串截断符也算一个) , 那么超出的部分将破坏掉与它紧邻着的authenticated变量的内容!
再复习一下程序 , authenticated变量实际上是一个标志变量 , 其值将决定着程序进入错误重输的流程(非0)还是密码正确的流程(0)
下面是比较有趣的部分:
当密码不是宏定义的1234567时 , 字符串比较将返回1或-1(这里只讨论1 , 结尾的时候会谈下-1的情况)
由于intel是所谓的大顶机 , 其实就是内存中的数据按照4字节(DWORD)逆序存储 , 所以authenticated为1时 , 内存中存的是0x01000000
如果我们输入包含8个字符的错误密码 , 如“qqqqqqqq” , 那么字符串截断符0x00将写入authenticated变量
这溢出数组的一个字节0x00将恰好把逆序存放的authenticated变量改为0x00000000 。
函数返回 , main函数中一看authenticated是0 , 就会欢天喜地地告诉你 , oh yeah 密码正确!这样 , 我们就用错误的密码得到了正确密码的运行效果
下面用5分钟实验一下这里的分析吧 。将代码用VC6.0编译链接 , 生成可执行文件 。注意 ,
VC6.0或者更早的编译器 , 不是7.0 , 不是8.0 , 不是.NET , 不是VS2003 , 不是VS2005 。为什么 , 其实不是高级的编译器不能搞 , 是比较难搞 , 它们有特殊的GS编译选项 , 为了不给咱们扫盲班增加负担 , 所以暂时飘过 , 用6.0!
按照程序的设计思路 , 只有输入了正确的密码”1234567”之后才能通过验证 。程序运行情况如下:

文章插图
要是输入几十个字符的长串 , 应该会崩溃 。多少个字符会崩溃?为什么?卖个关子 , 下节课慢慢讲 。现在来个8个字符的密码试下:

文章插图
注意为什么01234567不行?因为字符串大小的比较是按字典序来的 , 所以这个串小于“1234567” , authenticated的值是-1 , 在内存里将按照补码存负数 , 所以实际存的不是0x01000000而是0xffffffff 。那么字符串截断后符0x00淹没后 , 变成0x00ffffff , 还是非0 , 所以没有进入正确分支 。
总结一下 , 由于编程的粗心 , 有可能造成程序中出现缓冲区溢出的缺陷 。
这种缺陷大多数情况下会导致崩溃 , 但是结合内存中的具体情况 , 如果精心构造缓冲区的话 , 是有可能让程序作出设计人员根本意向不到的事情的
本节只是用一个字节淹没了邻接变量 , 导致了程序进入密码正确的处理流程 , 使设计的验证功能失效 。
其实作为cracker , 大家可能会说这有什么难的 , 我可以说出一堆方法做到这一点:
直接查看PE , 找出宏定义中的密码值 , 得到正确密码
反汇编PE , 找到爆破点,JZ JNZ的或者TEST EAX,EAX变XOR EAX,EAX的在分支处改它一个字节
但是今天介绍的这种方法与crack的方法有一个非常重要的区别 , 非常非常重要~~
就是~~~我们是在程序允许的情况下 , 用合法的输入数据(对于程序来说)得到了非法的执行效果(对于程序员来说)——这是hack与crack之间的一个重要区别 , 因为大多数情况下hack是没有办法直接修改PE的 , 他们只能通过影响输入来影响程序的流程 , 这将使hack受到很多限制 , 从某种程度上讲也更加困难 。这个区别将在后面几讲中得到深化 , 并被我不断强调 。
好了 , 今天的扫盲课程暂时结束 , 作为栈溢出的开场白 , 希望这个自制的漏洞程序能够给您带来一点点帮助 。
推荐阅读
- 理性分析洗牙的利与弊
- 老年人吃猪血好处多
- 项羽失败的原因分析 项羽失败的原因
- Linux后渗透常见后门驻留方式分析
- Linux 常见异常分析,请收好这份排查指南
- 如何用换手率指标分析基金 基金换手率
- 娃娃鱼养殖过程中对食类的需求分析 娃娃鱼养殖技术
- 重点分析摩羯座爱情观1 摩羯座的爱情!
- 大博弈|服了!《大博弈》的剧情出现大漏洞,编剧怎么圆都圆不过来了
- 驴得水中铁男人物分析,驴得水里周铁男的角色分析-
