接触黑客的同志们经常遇到,使用一些扫描工具扫描的时候,会得到一些缓冲区溢出的漏洞,但是怎么利用自己是一团雾水
网上很少有相关的工具,也很少有相关的文章,下面我们就说说这个“窿西”吧
[蛋痛]文章丢失了一次,CSDN需要改进暂存机制
用VB的便宜不太明白“缓冲区”,当然这一点对熟悉API的朋友有一定改善,缓冲区就是一段内存,通俗这么讲吧。
我们给局部变量或者全局变量赋值时,变量的内存大小不可能是无限的,也很难做到自动适应(否则执行效率会很慢),当
赋值的数据大小超过变量的内存大小时,就会造成溢出,这歌溢出经常看到的描述是:不可意料的结果。
我们通过VC6编写一个简单的程序,来说明这个不可意料的结果吧。
// buffer overflow code by cto@renshenguo.com #include <windows.h> #include <stdio.h> void fnHack() //the host never expect to run this { printf("Your computer has been hacked!\n"); //example for hack action exit(0); //exit process } int main() { int var[4] = {NULL}; var[5] = (int)fnHack; printf("the host is running in normal way.\n"); return 0; }
简单吧!有人吐了,这个不就比我在学校时候的那个“helloworld”差不多嘛。不错,你可以这么理解。
在这里我们没有给main函数声明参数如 main(int argc, char **args),但是在WIN32运行时,仍然是传递这些参数的,在VC
下的DASM看不到这些,我们用OllyIce查看其编译后运行的反汇编代码:
函数的调用一般按照这样的方式:返回地址入栈,被调函数入栈,被调函数返回地址入栈,相关参数入栈……
可以看到程序有两个函数,当然这是Debug,OllyIce能够识别相关的源代码文件,如果是发布的Release版本,可能只看到地址
跳转执行,到后面“后进先出”依次出栈,返回原来地址继续执行……
那么,我们看一下,按照C/C++编译后的代码:(因为博客主要不再面向新手,怎么做我就不说了)
注意选中的那一行,本来main函数的返回地址入栈,再到我们声明的4个32位整型变量,其内存范围是【ebp】到【ebp-0x10】
注意堆栈的栈底是高地址,这个可以参考相关的说明,我对汇编代码注释一下,如图:
10: int main() 11: { int var[4] = {NULL}; 00401070 push ebp ;基址指针ebp入栈,寄存器入栈主要是暂存其内容 00401071 mov ebp,esp ;堆栈指针esp传至基址指针ebp 00401073 sub esp,50h ;堆栈指针减少0x50,也就是初始化堆栈大小800字节 00401076 push ebx ;基地址寄存器ebx入栈 00401077 push esi ;源变址寄存器esi入栈 00401078 push edi ;目的变址寄存器edi入栈 00401079 lea edi,[ebp-50h] ;传送[ebp-0x50]偏移的32位内存值到目的变址edi 0040107C mov ecx,14h ;将0x14传送到计数寄存器ecx 00401081 mov eax,0CCCCCCCCh ;将0xCCCCCCCC传送到累加器eax,VC初始化变量 00401086 rep stos dword ptr [edi] ;填充[edi]指向的内存,串操作 00401088 mov dword ptr [ebp-10h],0 ;初始化[ebp-0x10]的值为0,“高高低低”,var[3] = NULL 0040108F xor eax,eax ;eax与自身异或运算,其实就是累加器eax清零 00401091 mov dword ptr [ebp-0Ch],eax ;初始化[ebp-0x0C]的值为0,var[2] = NULL 00401094 mov dword ptr [ebp-8],eax ;初始化[ebp-0x08]的值为0,var[1] = NULL 00401097 mov dword ptr [ebp-4],eax ;初始化[ebp-0x04]的值为0,var[0] = NULL,内容涵盖到ebp,共4字节 12: var[5] = (int)fnHack; ;注意下面这条,它将fnHack函数地址覆盖main函数返回地址 0040109A mov dword ptr [ebp+4],offset @ILT+5(fnHack) (0040100a) 13: printf("the host is running in normal way.\n"); 004010A1 push offset string "the host is running in normal wa"... (00420044) 004010A6 call printf (004012b0) 004010AB add esp,4 14: return 0; 004010AE xor eax,eax 15: }执行到完毕的汇编代码如图
当函数执行到返回后总会调用__chkesp检查堆栈指针,其代码贴出来可以研究,不过跟我们关系不大
__chkesp: 00401330 jne __chkesp+3 (00401333) 00401332 ret 00401333 push ebp 00401334 mov ebp,esp 00401336 sub esp,0 00401339 push eax 0040133A push edx 0040133B push ebx 0040133C push esi 0040133D push edi 0040133E push offset string "The value of ESP was not properl"... (004200a0) 00401343 push offset string "" (0042009c) 00401348 push 2Ah 0040134A push offset string "i386\\chkesp.c" (0042008c) 0040134F push 1 00401351 call _CrtDbgReport (004046b0) 00401356 add esp,14h 00401359 cmp eax,1 0040135C jne __chkesp+2Fh (0040135f) 0040135E int 3 0040135F pop edi 00401360 pop esi 00401361 pop ebx 00401362 pop edx 00401363 pop eax 00401364 mov esp,ebp 00401366 pop ebp 00401367 ret 00401368 int 3后面它将跳到fnHack函数的地址,而不是main函数的调用处执行fnHack函数,执行结果如图:
这就是缓冲区溢出造成所谓的不可预料的结果,所带来的执行任意代码……
一般来说,黑客才回造成这样的结果,而本地溢出没有什么特别大的入侵意义,而远程溢出则还要学习shellcode方面的东西,这个以后再说吧
缓冲区溢出离我们其实并不远,往往我们看到的更多的情况是这样:
很多软件即使全面测试无数次,在特定的条件下,也会造成溢出,不测试的就更多了……
但是这种溢出不是人为的,也就是说溢出后执行的代码是不确定的,最后往往造成内存访问冲突而被操作系统终止。
好了,就说这么多吧!