📄 csdn_文档中心_突破c++的虚拟指针--c++程序的缓冲区溢出攻击.htm
字号:
document.write(".");
document.write(month);
document.write(".");
document.write(date);
// -->
</SCRIPT>
</B> </TD></TR>
<TR bgColor=#999999>
<TD colSpan=3 height=1></TD></TR></TBODY></TABLE>
<TABLE border=0 width=770>
<TBODY>
<TR>
<TD align=middle bgColor=#fafafa class=td1 vAlign=top width=150><BR>
<SCRIPT
src="CSDN_文档中心_突破C++的虚拟指针--C++程序的缓冲区溢出攻击.files/microsoft.js"></SCRIPT>
</TD>
<TD align=middle width=620>
<TABLE bgColor=#eeeeee border=0 cellPadding=0 cellSpacing=0 width=600>
<TBODY>
<TR bgColor=#ffffff>
<TD align=middle height=10 width=50></TD>
<TD align=right><A href="http://www.csdn.net/">CSDN</A> - <A
href="http://www.csdn.net/develop/">文档中心</A> - <FONT
color=#003399>Visual C++</FONT> </TD></TR>
<TR>
<TD align=middle height=5></TD>
<TD align=middle width=500></TD></TR>
<TR>
<TD align=middle bgColor=#003399 height=10><FONT
color=#ffffff>标题</FONT></TD>
<TD><B> 突破C++的虚拟指针--C++程序的缓冲区溢出攻击</B> ghj1976(转贴)
</TD></TR>
<TR>
<TD align=middle height=5></TD>
<TD align=middle width=500></TD></TR>
<TR>
<TD align=middle bgColor=#003399><FONT color=#ffffff>关键字</FONT></TD>
<TD
width=500> 突破C++的虚拟指针--C++程序的缓冲区溢出攻击</TD></TR>
<TR>
<TD align=middle height=5></TD>
<TD align=middle width=500></TD></TR>
<TR>
<TD align=middle bgColor=#003399 height=10><FONT
color=#ffffff>出处</FONT></TD>
<TD height=10> <A
href="http://www.isbase.com/">http://www.isbase.com/</A></TD></TR>
<TR>
<TD align=middle height=10></TD>
<TD height=10></TD></TR></TBODY></TABLE><!--文章说明信息结束//-->
<TABLE border=0 width=600>
<TBODY>
<TR>
<TD align=left><BR>
<P><BR><BR>作者:rix (<A
href="mailto:rix@securiweb.net">rix@securiweb.net</A>)<BR></P>
<P><BR>backend注:本文来自Phrack56期的《SMASHING C++
VPTRS》。正如大多数国外黑客的文章,技术原理及应用都讲得比较详细,但所提供的源代码似乎总是会存在不大不小的问题。这也许是因为他们觉得应该让读者自己去研究和调试,以更好地掌握这些技术。或许以后我也会这样做。;)<BR><BR>测试环境:<BR><BR> 操作系统:Red
Hat 6.1 (i386)<BR> 内核版本:Kernel
2.2.14<BR> 内核补丁:None Non-executable stack patch (by
Solar Design)<BR> C++编译器:gcc<BR> <BR><BR>---[[ 前言
]]--------------------------------------<BR><BR> 到目前为止,我所掌握的缓冲区溢出程序都是针对C编程语言的。虽然C语言编程在UNIX系统中几乎无处不在,但越来越多的C++程序也开始出现了。对于大多数情况,C语言的溢出技术对于C++语言也是适用的,但C++的面向对象的特性也导致了新的缓冲区溢出技术。下面以x86
Linux系统和C++ GNU编译器为平台进行分析。<BR><BR><BR>---[[ 基础--简单的C++程序
]]--------------------------------------<BR><BR> 我不愿在这里浪费时间讲解太多的C++语言基础。如果你对C++或面向对象编程技术一无所知,请先找本这方面的书籍看看。在继续往下看之前,请确认你已经掌握或了解以下C++术语:<BR> <BR> 1、Class(类)<BR> 2、Object(对象)<BR> 3、Method(方法)<BR> 4、Virtual(虚拟)<BR> 5、Inherit(继承)<BR> 6、Derivative(派生)<BR><BR> 接着,把下面的两个程序看完,确认你了解每条语句的含义和作用:<BR> <BR>//
bo1.cpp<BR>// C++基础程序<BR><BR>#include <stdio.h><BR>#include
<string.h><BR><BR>class MyClass<BR>{<BR> private:<BR> char
Buffer[32];<BR> public:<BR> void SetBuffer(char
*String)<BR> {<BR> strcpy(Buffer,
String);<BR> }<BR> void
PrintBuffer()<BR> {<BR> printf("%s\n",
Buffer);<BR> }<BR>};<BR><BR>void main()<BR>{<BR> MyClass
Object;<BR><BR> Object.SetBuffer("string");<BR> Object.PrintBuffer();<BR>}<BR><BR>===========================================================<BR><BR>//
bo2.cpp<BR>// 有缓冲区溢出漏洞的常见C++程序<BR><BR>#include
<stdio.h><BR>#include <string.h><BR><BR>class
BaseClass<BR>{<BR> private:<BR> char
Buffer[32];<BR> public:<BR> void SetBuffer(char
*String)<BR> {<BR> strcpy(Buffer,String); //
存在缓冲区溢出漏洞<BR> }<BR> virtual void
PrintBuffer()<BR> {<BR> printf("%s\n",Buffer);<BR> }<BR>};<BR><BR>class
MyClass1:public BaseClass<BR>{<BR> public:<BR> void
PrintBuffer()<BR> {<BR> printf("MyClass1:
");<BR> BaseClass::PrintBuffer();<BR> }<BR>};<BR><BR>class
MyClass2:public BaseClass<BR>{<BR> public:<BR> void
PrintBuffer()<BR> {<BR> printf("MyClass2:
");<BR> BaseClass::PrintBuffer();<BR> }<BR>};<BR><BR>void
main()<BR>{<BR> BaseClass *Object[2];<BR><BR> Object[0] = new
MyClass1;<BR> Object[1] = new
MyClass2;<BR><BR> Object[0]->SetBuffer("string1");<BR> Object[1]->SetBuffer("string2");<BR> Object[0]->PrintBuffer();<BR> Object[1]->PrintBuffer();<BR>}<BR><BR> 以下是bo2.cpp编译后的运行结果:<BR><BR>[backend@isbase
test]> ./bo2<BR>MyClass1: string1<BR>MyClass2:
string2<BR>[backend@isbase
test]><BR><BR> 再一次提醒,在继续往下看时,确信你读懂了上面的程序,特别是对象虚拟(virtual)方法PrintBuffer()。与SetBuffer()方法不同,PrintBuffer方法必须在基类BaseClass的派生类MyClass1和MyClass2中声明并实现。这使得SetBuffer与PrintBuffer方法在运行时的处理会有所不同。<BR><BR><BR>---[[
C++的虚拟指针(Virtual
PoinTeR,VPTR)]]--------------------------------------<BR><BR> 我们知道,虚拟方法与非虚拟方法的一个不同之处是,非虚拟方法的调用是在编译时确定(通常称为“静态绑定”),而虚拟方法的调用却是在程序时确定的(通常称为“动态绑定”)。下面以上例中的BaseClass基类及其派生类为例,对动态绑定的机制做一些解释。<BR><BR> 编译器在编译时首先检查BaseClass基类的声明。在本例,编译器首先为私有变量Buffer(字符串型)保留32个字节,接着为非虚拟方法SetBuffer()计算并指定相应的调用地址(静态绑定处理),最后在检查到虚拟方法PrintBuffer()时,将做动态绑定处理,即在类中分配4个字节用以存放该虚拟方法的指针。结构如下:<BR><BR> BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBVVVV<BR><BR>说明:
B 变量Buffer占用。<BR> V
虚拟方法指针占用。<BR><BR> 这个指针通常被称为“VPTR”(Virtual
Pointer),它指向一个“VTABLE”结构中的函数入口之一。每一个类都有一个VTABLE。如下图所示:<BR><BR>Object[0]:
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBVVVV<BR> =+==<BR> |<BR> +------------------------------+<BR> |<BR> +-->
VTABLE_MyClass1: IIIIIIIIIIIIPPPP<BR><BR>Object[1]:
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBWWWW<BR> =+==<BR> |<BR> +------------------------------+<BR> |<BR> +-->
VTABLE_MyClass2: IIIIIIIIIIIIQQQQ<BR><BR>说明: B
变量Buffer占用。<BR> V 指向VTABLE_MyClass1的VPTR指针占用。<BR> W
指向VTABLE_MyClass2的VPTR指针占用。<BR> I 其它用途的数据<BR> P
MyClass1对象实例的PrintBuffer()方法的地址指针。<BR> Q
MyClass2对象实例的PrintBuffer()方法的地址指针。<BR><BR> 我们可以发现,VPTR位于进程内存中Buffer变量之后。即当调用危险的strcpy()函数时有可能覆盖VPTR的内容!<BR> <BR> 根据rix的研究测试,对于Windows平台上的Visual
C++ 6.0,VPTR位于对象的起始位置,因此这里提到的技术无法产生作用。这点与GNU
C++有很大的不同。<BR><BR><BR>---[[ 剖析VPTR
]]--------------------------------------<BR><BR> 在Linux下当然是使用GDB来分析了:<BR><BR>[backend@isbase
test]> gcc -o bo2 bo2.cpp<BR>[backend@isbase test]> gdb
bo2<BR>GNU gdb 4.18<BR>Copyright 1998 Free Software Foundation,
Inc.<BR>GDB is free software, covered by the GNU General Public
License, and you are<BR>welcome to change it and/or distribute
copies of it under certain conditions.<BR>Type "show copying" to see
the conditions.<BR>There is absolutely no warranty for GDB. Type
"show warranty" for details.<BR>This GDB was configured as
"i386-redhat-linux"...<BR>(gdb) disassemble main<BR>Dump of
assembler code for function main:<BR>0x8049400
<main>: push %ebp<BR>0x8049401
<main+1>: mov %esp,%ebp<BR>0x8049403
<main+3>: sub $0x8,%esp<BR>0x8049406
<main+6>: push %edi<BR>0x8049407
<main+7>: push %esi<BR>0x8049408
<main+8>: push %ebx<BR>0x8049409
<main+9>: push $0x24<BR>0x804940b
<main+11>: call 0x804b580
<__builtin_new><BR>0x8049410
<main+16>: add $0x4,%esp<BR>0x8049413
<main+19>: mov %eax,%eax<BR>0x8049415
<main+21>: mov %eax,%ebx<BR>0x8049417
<main+23>: push %ebx<BR>0x8049418
<main+24>: call 0x804c90c
<__8MyClass1><BR>0x804941d
<main+29>: add $0x4,%esp<BR>0x8049420
<main+32>: mov %eax,%esi<BR>0x8049422
<main+34>: jmp 0x8049430 <main+48><BR>0x8049424
<main+36>: call 0x8049c3c <__throw><BR>0x8049429
<main+41>: lea 0x0(%esi,1),%esi<BR>0x8049430
<main+48>: mov %esi,0xfffffff8(%ebp)<BR>0x8049433
<main+51>: push $0x24<BR>0x8049435
<main+53>: call 0x804b580
<__builtin_new><BR>0x804943a
<main+58>: add $0x4,%esp<BR>0x804943d
<main+61>: mov %eax,%eax<BR>0x804943f
<main+63>: mov %eax,%esi<BR>0x8049441
<main+65>: push %esi<BR>0x8049442
<main+66>: call 0x804c8ec
<__8MyClass2><BR>0x8049447
<main+71>: add $0x4,%esp<BR>0x804944a
<main+74>: mov %eax,%edi<BR>0x804944c
<main+76>: jmp 0x8049455 <main+85><BR>0x804944e
<main+78>: mov %esi,%esi<BR>0x8049450
<main+80>: call 0x8049c3c <__throw><BR>0x8049455
<main+85>: mov %edi,0xfffffffc(%ebp)<BR>0x8049458
<main+88>: push $0x804cda2<BR>0x804945d
<main+93>: mov 0xfffffff8(%ebp),%eax<BR>0x8049460
<main+96>: push %eax<BR>0x8049461
<main+97>: call 0x804c930
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -