黑客软件漏洞分析0基础教学 初级栈溢出 入门到地狱( 二 )


用户输入的字符串将拷贝进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”之后才能通过验证 。程序运行情况如下:

黑客软件漏洞分析0基础教学 初级栈溢出 入门到地狱

文章插图
 
要是输入几十个字符的长串 , 应该会崩溃 。多少个字符会崩溃?为什么?卖个关子 , 下节课慢慢讲 。现在来个8个字符的密码试下:
黑客软件漏洞分析0基础教学 初级栈溢出 入门到地狱

文章插图
 
注意为什么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受到很多限制 , 从某种程度上讲也更加困难 。这个区别将在后面几讲中得到深化 , 并被我不断强调 。
好了 , 今天的扫盲课程暂时结束 , 作为栈溢出的开场白 , 希望这个自制的漏洞程序能够给您带来一点点帮助 。




推荐阅读